Merge remote-tracking branch 'upstream/master'
# Conflicts: # cmd/ks-apiserver/app/server.go
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "vendor/github.com/knative/pkg"]
|
||||
path = vendor/github.com/knative/pkg
|
||||
url = https://github.com/knative/pkg.git
|
||||
|
||||
@@ -15,16 +15,15 @@ before_install:
|
||||
- go get -u github.com/golang/dep/cmd/dep
|
||||
|
||||
before_script:
|
||||
- dep ensure -v
|
||||
- docker --version
|
||||
- bash hack/install_kubebuilder.sh
|
||||
|
||||
script:
|
||||
- make all && make test && bash hack/docker_build.sh
|
||||
- make all
|
||||
|
||||
deploy:
|
||||
skip_cleanup: true
|
||||
provider: script
|
||||
script: bash hack/docker_push.sh
|
||||
script: bash hack/docker_build.sh && bash hack/docker_push.sh
|
||||
on:
|
||||
branch: master
|
||||
|
||||
110
Gopkg.lock
generated
110
Gopkg.lock
generated
@@ -163,6 +163,12 @@
|
||||
revision = "b7062368c258c9e8f8cbe9dd2e6aebfa1b747be6"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/evanphx/json-patch"
|
||||
packages = ["."]
|
||||
revision = "72bf35d0ff611848c1dc9df0f976c81192392fa5"
|
||||
version = "v4.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/flynn/go-shlex"
|
||||
@@ -439,8 +445,22 @@
|
||||
name = "github.com/knative/pkg"
|
||||
packages = [
|
||||
"apis/istio",
|
||||
"apis/istio/authentication",
|
||||
"apis/istio/authentication/v1alpha1",
|
||||
"apis/istio/common/v1alpha1",
|
||||
"apis/istio/v1alpha3"
|
||||
"apis/istio/v1alpha3",
|
||||
"client/clientset/versioned",
|
||||
"client/clientset/versioned/scheme",
|
||||
"client/clientset/versioned/typed/authentication/v1alpha1",
|
||||
"client/clientset/versioned/typed/istio/v1alpha3",
|
||||
"client/informers/externalversions",
|
||||
"client/informers/externalversions/authentication",
|
||||
"client/informers/externalversions/authentication/v1alpha1",
|
||||
"client/informers/externalversions/internalinterfaces",
|
||||
"client/informers/externalversions/istio",
|
||||
"client/informers/externalversions/istio/v1alpha3",
|
||||
"client/listers/authentication/v1alpha1",
|
||||
"client/listers/istio/v1alpha3"
|
||||
]
|
||||
revision = "cd278f2d3394c865fda66bca12459e879e0279b8"
|
||||
|
||||
@@ -454,13 +474,32 @@
|
||||
branch = "master"
|
||||
name = "github.com/kubernetes-sigs/application"
|
||||
packages = [
|
||||
"pkg/apis/app/v1beta1",
|
||||
"pkg/component",
|
||||
"pkg/customresource",
|
||||
"pkg/finalizer",
|
||||
"pkg/genericreconciler",
|
||||
"pkg/kbcontroller",
|
||||
"pkg/resource"
|
||||
]
|
||||
revision = "4ead7f1b87048b7717b3e474a21fdc07e6bce636"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/kubesphere/s2ioperator"
|
||||
packages = [
|
||||
"pkg/apis/devops/v1alpha1",
|
||||
"pkg/client/clientset/versioned",
|
||||
"pkg/client/clientset/versioned/scheme",
|
||||
"pkg/client/clientset/versioned/typed/devops/v1alpha1",
|
||||
"pkg/client/informers/externalversions",
|
||||
"pkg/client/informers/externalversions/devops",
|
||||
"pkg/client/informers/externalversions/devops/v1alpha1",
|
||||
"pkg/client/informers/externalversions/internalinterfaces",
|
||||
"pkg/client/listers/devops/v1alpha1"
|
||||
]
|
||||
revision = "cb9f6d6145324977e5904ded95de7bfca7a01151"
|
||||
version = "v0.0.4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/lucas-clemente/aes12"
|
||||
@@ -1001,7 +1040,8 @@
|
||||
packages = [
|
||||
".",
|
||||
"cipher",
|
||||
"json"
|
||||
"json",
|
||||
"jwt"
|
||||
]
|
||||
revision = "628223f44a71f715d2881ea69afc795a1e9c01be"
|
||||
version = "v2.3.0"
|
||||
@@ -1065,7 +1105,8 @@
|
||||
"pkg/apis/apiextensions/v1beta1",
|
||||
"pkg/client/clientset/clientset",
|
||||
"pkg/client/clientset/clientset/scheme",
|
||||
"pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
|
||||
"pkg/client/clientset/clientset/typed/apiextensions/v1beta1",
|
||||
"pkg/features"
|
||||
]
|
||||
revision = "0fe22c71c47604641d9aa352c785b7912c200562"
|
||||
version = "kubernetes-1.13.1"
|
||||
@@ -1073,13 +1114,16 @@
|
||||
[[projects]]
|
||||
name = "k8s.io/apimachinery"
|
||||
packages = [
|
||||
"pkg/api/equality",
|
||||
"pkg/api/errors",
|
||||
"pkg/api/meta",
|
||||
"pkg/api/resource",
|
||||
"pkg/api/validation",
|
||||
"pkg/api/validation/path",
|
||||
"pkg/apis/meta/internalversion",
|
||||
"pkg/apis/meta/v1",
|
||||
"pkg/apis/meta/v1/unstructured",
|
||||
"pkg/apis/meta/v1/validation",
|
||||
"pkg/apis/meta/v1beta1",
|
||||
"pkg/conversion",
|
||||
"pkg/conversion/queryparams",
|
||||
@@ -1120,23 +1164,28 @@
|
||||
"third_party/forked/golang/reflect"
|
||||
]
|
||||
revision = "2b1284ed4c93a43499e781493253e2ac5959c4fd"
|
||||
version = "kubernetes-1.13.0"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "k8s.io/apiserver"
|
||||
packages = [
|
||||
"pkg/apis/audit",
|
||||
"pkg/authentication/authenticator",
|
||||
"pkg/authentication/serviceaccount",
|
||||
"pkg/authentication/user",
|
||||
"pkg/authorization/authorizer",
|
||||
"pkg/endpoints/request"
|
||||
"pkg/endpoints/request",
|
||||
"pkg/features",
|
||||
"pkg/util/feature"
|
||||
]
|
||||
revision = "39e839dff03462945cc991fb9dac4469c951772d"
|
||||
revision = "3ccfe8365421eb08e334b195786a2973460741d8"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/client-go"
|
||||
packages = [
|
||||
"discovery",
|
||||
"discovery/fake",
|
||||
"dynamic",
|
||||
"informers",
|
||||
"informers/admissionregistration",
|
||||
@@ -1255,6 +1304,7 @@
|
||||
"rest",
|
||||
"rest/watch",
|
||||
"restmapper",
|
||||
"testing",
|
||||
"third_party/forked/golang/template",
|
||||
"tools/auth",
|
||||
"tools/cache",
|
||||
@@ -1268,6 +1318,7 @@
|
||||
"tools/pager",
|
||||
"tools/record",
|
||||
"tools/reference",
|
||||
"tools/watch",
|
||||
"transport",
|
||||
"util/buffer",
|
||||
"util/cert",
|
||||
@@ -1283,7 +1334,6 @@
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.13"
|
||||
name = "k8s.io/code-generator"
|
||||
packages = [
|
||||
"cmd/client-gen",
|
||||
@@ -1297,6 +1347,7 @@
|
||||
"pkg/util"
|
||||
]
|
||||
revision = "c2090bec4d9b1fb25de3812f868accc2bc9ecbae"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -1327,14 +1378,50 @@
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/kubernetes"
|
||||
packages = ["pkg/util/slice"]
|
||||
packages = [
|
||||
"pkg/api/legacyscheme",
|
||||
"pkg/api/service",
|
||||
"pkg/api/v1/pod",
|
||||
"pkg/apis/apps",
|
||||
"pkg/apis/autoscaling",
|
||||
"pkg/apis/core",
|
||||
"pkg/apis/core/helper",
|
||||
"pkg/apis/core/install",
|
||||
"pkg/apis/core/pods",
|
||||
"pkg/apis/core/v1",
|
||||
"pkg/apis/core/v1/helper",
|
||||
"pkg/apis/core/validation",
|
||||
"pkg/apis/scheduling",
|
||||
"pkg/capabilities",
|
||||
"pkg/controller",
|
||||
"pkg/features",
|
||||
"pkg/fieldpath",
|
||||
"pkg/kubelet/types",
|
||||
"pkg/master/ports",
|
||||
"pkg/scheduler/api",
|
||||
"pkg/security/apparmor",
|
||||
"pkg/serviceaccount",
|
||||
"pkg/util/file",
|
||||
"pkg/util/hash",
|
||||
"pkg/util/metrics",
|
||||
"pkg/util/net/sets",
|
||||
"pkg/util/parsers",
|
||||
"pkg/util/slice",
|
||||
"pkg/util/taints"
|
||||
]
|
||||
revision = "c27b913fddd1a6c480c229191a087698aa92f0b1"
|
||||
version = "v1.13.4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "k8s.io/utils"
|
||||
packages = ["pointer"]
|
||||
revision = "21c4ce38f2a793ec01e925ddc31216500183b773"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "sigs.k8s.io/application"
|
||||
packages = ["pkg/apis/app/v1beta1"]
|
||||
packages = ["pkg/controller/application"]
|
||||
revision = "4ead7f1b87048b7717b3e474a21fdc07e6bce636"
|
||||
|
||||
[[projects]]
|
||||
@@ -1346,7 +1433,6 @@
|
||||
"pkg/client/apiutil",
|
||||
"pkg/client/config",
|
||||
"pkg/controller",
|
||||
"pkg/controller/controllerutil",
|
||||
"pkg/envtest",
|
||||
"pkg/envtest/printer",
|
||||
"pkg/event",
|
||||
@@ -1416,6 +1502,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "9c1d98a69374a4d7fbddc9df92f3ba83c5d4a0753b887577c161b2802f9c9494"
|
||||
inputs-digest = "662b6da91343ff0a611e4487b8eef803b103b676f5b2a5db7ed8351846218fc5"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
16
Gopkg.toml
16
Gopkg.toml
@@ -14,7 +14,9 @@ required = [
|
||||
"sigs.k8s.io/controller-runtime/pkg/runtime/signals",
|
||||
"sigs.k8s.io/controller-runtime/pkg/source",
|
||||
"sigs.k8s.io/testing_frameworks/integration", # for integration testing
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1",
|
||||
"github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned",
|
||||
"github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions",
|
||||
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
|
||||
]
|
||||
|
||||
[[constraint]]
|
||||
@@ -29,6 +31,10 @@ required = [
|
||||
name = "k8s.io/apimachinery"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[override]]
|
||||
name = "k8s.io/apiserver"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/code-generator"
|
||||
version = "kubernetes-1.13.1"
|
||||
@@ -49,6 +55,10 @@ required = [
|
||||
name="sigs.k8s.io/controller-tools"
|
||||
version="v0.1.7"
|
||||
|
||||
[[constraint]]
|
||||
name="github.com/kubesphere/s2ioperator"
|
||||
version="v0.0.7"
|
||||
|
||||
[[override]]
|
||||
name="github.com/bifurcation/mint"
|
||||
revision="824af65410658916142a7600349144e1289f2110"
|
||||
@@ -102,3 +112,7 @@ required = [
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/mux"
|
||||
version = "1.7.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/knative/pkg"
|
||||
|
||||
8
Makefile
8
Makefile
@@ -28,7 +28,7 @@ define ALL_HELP_INFO
|
||||
# debugging tools like delve.
|
||||
endef
|
||||
.PHONY: all
|
||||
all: test ks-apiserver ks-apigateway ks-iam
|
||||
all: test ks-apiserver ks-apigateway ks-iam controller-manager
|
||||
|
||||
# Build ks-apiserver binary
|
||||
ks-apiserver: test
|
||||
@@ -42,6 +42,10 @@ ks-apigateway: test
|
||||
ks-iam: test
|
||||
hack/gobuild.sh cmd/ks-iam
|
||||
|
||||
# Build controller-manager binary
|
||||
controller-manager: test
|
||||
hack/gobuild.sh cmd/controller-manager
|
||||
|
||||
# Run go fmt against code
|
||||
fmt:
|
||||
go fmt ./pkg/... ./cmd/...
|
||||
@@ -60,7 +64,7 @@ deploy: manifests
|
||||
|
||||
# Generate DeepCopy to implement runtime.Object
|
||||
deepcopy:
|
||||
./vendor/k8s.io/code-generator/generate-groups.sh deepcopy kubesphere.io/kubesphere/pkg/client kubesphere.io/kubesphere/pkg/apis "servicemesh:v1alpha2"
|
||||
./vendor/k8s.io/code-generator/generate-groups.sh deepcopy,lister,informer,client kubesphere.io/kubesphere/pkg/client kubesphere.io/kubesphere/pkg/apis "servicemesh:v1alpha2"
|
||||
|
||||
# Generate code
|
||||
generate:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Copyright 2018 The KubeSphere Authors. All rights reserved.
|
||||
# Use of this source code is governed by a Apache license
|
||||
# that can be found in the LICENSE file.
|
||||
FROM golang:1.10.3 as controller-manager-builder
|
||||
FROM golang:1.12 as controller-manager-builder
|
||||
|
||||
COPY / /go/src/kubesphere.io/kubesphere
|
||||
WORKDIR /go/src/kubesphere.io/kubesphere
|
||||
|
||||
87
cmd/controller-manager/app/controllers.go
Normal file
87
cmd/controller-manager/app/controllers.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"kubesphere.io/kubesphere/pkg/controller/destinationrule"
|
||||
"kubesphere.io/kubesphere/pkg/controller/virtualservice"
|
||||
"kubesphere.io/kubesphere/pkg/simple/controller/namespace"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"time"
|
||||
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
|
||||
istioclientset "github.com/knative/pkg/client/clientset/versioned"
|
||||
istioinformers "github.com/knative/pkg/client/informers/externalversions"
|
||||
servicemeshclientset "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||
servicemeshinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
)
|
||||
|
||||
const defaultResync = 600 * time.Second
|
||||
|
||||
var log = logf.Log.WithName("controller-manager")
|
||||
|
||||
func AddControllers(mgr manager.Manager, cfg *rest.Config, stopCh <-chan struct{}) error {
|
||||
|
||||
kubeClient, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
log.Error(err, "building kubernetes client failed")
|
||||
}
|
||||
|
||||
istioclient, err := istioclientset.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
log.Error(err, "create istio client failed")
|
||||
return err
|
||||
}
|
||||
|
||||
informerFactory := informers.NewSharedInformerFactory(kubeClient, defaultResync)
|
||||
istioInformer := istioinformers.NewSharedInformerFactory(istioclient, defaultResync)
|
||||
|
||||
servicemeshclient, err := servicemeshclientset.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
log.Error(err, "create servicemesh client failed")
|
||||
return err
|
||||
}
|
||||
|
||||
servicemeshinformer := servicemeshinformers.NewSharedInformerFactory(servicemeshclient, defaultResync)
|
||||
|
||||
vsController := virtualservice.NewVirtualServiceController(informerFactory.Core().V1().Services(),
|
||||
istioInformer.Networking().V1alpha3().VirtualServices(),
|
||||
istioInformer.Networking().V1alpha3().DestinationRules(),
|
||||
servicemeshinformer.Servicemesh().V1alpha2().Strategies(),
|
||||
kubeClient,
|
||||
istioclient)
|
||||
|
||||
drController := destinationrule.NewDestinationRuleController(informerFactory.Apps().V1().Deployments(),
|
||||
istioInformer.Networking().V1alpha3().DestinationRules(),
|
||||
informerFactory.Core().V1().Services(),
|
||||
servicemeshinformer.Servicemesh().V1alpha2().ServicePolicies(),
|
||||
kubeClient,
|
||||
istioclient)
|
||||
|
||||
nsController := namespace.NewNamespaceController(kubeClient,
|
||||
informerFactory.Core().V1().Namespaces(),
|
||||
informerFactory.Rbac().V1().Roles(),
|
||||
)
|
||||
|
||||
servicemeshinformer.Start(stopCh)
|
||||
istioInformer.Start(stopCh)
|
||||
informerFactory.Start(stopCh)
|
||||
|
||||
controllers := map[string]manager.Runnable{
|
||||
"virtualservice-controller": vsController,
|
||||
"destinationrule-controller": drController,
|
||||
"namespace-controller": nsController,
|
||||
}
|
||||
|
||||
for name, ctrl := range controllers {
|
||||
err = mgr.Add(ctrl)
|
||||
if err != nil {
|
||||
log.Error(err, "add controller to manager failed", "name", name)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
38
cmd/controller-manager/app/helper.go
Normal file
38
cmd/controller-manager/app/helper.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/klog"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// WaitForAPIServer waits for the API Server's /healthz endpoint to report "ok" with timeout.
|
||||
func WaitForAPIServer(client clientset.Interface, timeout time.Duration) error {
|
||||
var lastErr error
|
||||
|
||||
err := wait.PollImmediate(time.Second, timeout, func() (bool, error) {
|
||||
healthStatus := 0
|
||||
result := client.Discovery().RESTClient().Get().AbsPath("/healthz").Do().StatusCode(&healthStatus)
|
||||
if result.Error() != nil {
|
||||
lastErr = fmt.Errorf("failed to get apiserver /healthz status: %v", result.Error())
|
||||
return false, nil
|
||||
}
|
||||
if healthStatus != http.StatusOK {
|
||||
content, _ := result.Raw()
|
||||
lastErr = fmt.Errorf("APIServer isn't healthy: %v", string(content))
|
||||
klog.Warningf("APIServer isn't healthy yet: %v. Waiting a little while.", string(content))
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v: %v", err, lastErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -20,39 +20,42 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"kubesphere.io/kubesphere/cmd/controller-manager/app"
|
||||
"kubesphere.io/kubesphere/pkg/apis"
|
||||
"kubesphere.io/kubesphere/pkg/controller"
|
||||
"os"
|
||||
"sigs.k8s.io/application/pkg/apis/app/v1beta1"
|
||||
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/controller/namespace"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/apis"
|
||||
"kubesphere.io/kubesphere/pkg/controller"
|
||||
"kubesphere.io/kubesphere/pkg/webhook"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var metricsAddr string
|
||||
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
|
||||
flag.Parse()
|
||||
logf.SetLogger(logf.ZapLogger(false))
|
||||
log := logf.Log.WithName("entrypoint")
|
||||
var (
|
||||
masterURL string
|
||||
kubeconfig string
|
||||
metricsAddr string
|
||||
)
|
||||
|
||||
// Get a config to talk to the apiserver
|
||||
log.Info("setting up client for manager")
|
||||
cfg, err := k8s.Config()
|
||||
func init() {
|
||||
flag.StringVar(&masterURL, "master-url", "", "only need if out of cluster")
|
||||
flag.StringVar(&kubeconfig, "kubeconfig", "", "only need if out of cluster")
|
||||
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
logf.SetLogger(logf.ZapLogger(false))
|
||||
log := logf.Log.WithName("controller-manager")
|
||||
|
||||
cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)
|
||||
if err != nil {
|
||||
log.Error(err, "unable to set up client config")
|
||||
log.Error(err, "failed to build kubeconfig")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Create a new Cmd to provide shared dependencies and start components
|
||||
stopCh := signals.SetupSignalHandler()
|
||||
|
||||
log.Info("setting up manager")
|
||||
mgr, err := manager.New(cfg, manager.Options{})
|
||||
if err != nil {
|
||||
@@ -60,53 +63,27 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
log.Info("Registering Components.")
|
||||
|
||||
// Setup Scheme for all resources
|
||||
log.Info("setting up scheme")
|
||||
if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
|
||||
log.Error(err, "unable add APIs to scheme")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
log.Info("Print all known types")
|
||||
for k, v := range mgr.GetScheme().AllKnownTypes() {
|
||||
if k.Group == v1beta1.SchemeGroupVersion.Group {
|
||||
log.Info(k.String() + " / " + v.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Setup all Controllers
|
||||
log.Info("Setting up controller")
|
||||
log.Info("Setting up controllers")
|
||||
if err := controller.AddToManager(mgr); err != nil {
|
||||
log.Error(err, "unable to register controllers to the manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
log.Info("setting up webhooks")
|
||||
if err := webhook.AddToManager(mgr); err != nil {
|
||||
log.Error(err, "unable to register webhooks to the manager")
|
||||
if err := app.AddControllers(mgr, cfg, stopCh); err != nil {
|
||||
log.Error(err, "unable to register controllers to the manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = mgr.Add(manager.RunnableFunc(func(s <-chan struct{}) error {
|
||||
informerFactory := informers.SharedInformerFactory()
|
||||
informerFactory.Start(s)
|
||||
namespace.NewNamespaceController(k8s.Client(),
|
||||
informerFactory.Core().V1().Namespaces(),
|
||||
informerFactory.Rbac().V1().Roles()).Start(s)
|
||||
return nil
|
||||
}))
|
||||
|
||||
if err != nil {
|
||||
log.Error(err, "error Adding controllers to the Manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Start the Cmd
|
||||
log.Info("Starting the Cmd.")
|
||||
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
|
||||
if err := mgr.Start(stopCh); err != nil {
|
||||
log.Error(err, "unable to run the manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"kubesphere.io/kubesphere/cmd/ks-apiserver/app"
|
||||
"log"
|
||||
// Install apis
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/logging/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/metrics/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/monitoring/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/operations/install"
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
goflag "flag"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"github.com/json-iterator/go"
|
||||
kconfig "github.com/kiali/kiali/config"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
@@ -28,12 +29,14 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/filter"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/applications"
|
||||
logging "kubesphere.io/kubesphere/pkg/models/log"
|
||||
"kubesphere.io/kubesphere/pkg/signals"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
func NewAPIServerCommand() *cobra.Command {
|
||||
s := options.NewServerRunOptions()
|
||||
|
||||
@@ -60,9 +63,6 @@ func Run(s *options.ServerRunOptions) error {
|
||||
log.Printf("FLAG: --%s=%q", flag.Name, flag.Value)
|
||||
})
|
||||
|
||||
applications.OpenPitrixServer = s.OpenPitrixServer
|
||||
applications.OpenPitrixProxyToken = s.OpenPitrixProxyToken
|
||||
|
||||
var err error
|
||||
|
||||
waitForResourceSync()
|
||||
@@ -78,6 +78,7 @@ func Run(s *options.ServerRunOptions) error {
|
||||
}
|
||||
}
|
||||
|
||||
initializeESClientConfig()
|
||||
initializeKialiConfig(s)
|
||||
|
||||
if s.GenericServerRunOptions.InsecurePort != 0 {
|
||||
@@ -110,6 +111,24 @@ func initializeKialiConfig(s *options.ServerRunOptions) {
|
||||
kconfig.Set(config)
|
||||
}
|
||||
|
||||
func initializeESClientConfig() {
|
||||
|
||||
// List all outputs
|
||||
outputs,err := logging.GetFluentbitOutputFromConfigMap()
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Iterate the outputs to get elasticsearch configs
|
||||
for _, output := range outputs {
|
||||
if configs := logging.ParseEsOutputParams(output.Parameters); configs != nil {
|
||||
configs.WriteESConfigs()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func waitForResourceSync() {
|
||||
stopChan := signals.SetupSignalHandler()
|
||||
|
||||
@@ -134,12 +153,19 @@ func waitForResourceSync() {
|
||||
informerFactory.Apps().V1().StatefulSets().Lister()
|
||||
informerFactory.Apps().V1().Deployments().Lister()
|
||||
informerFactory.Apps().V1().DaemonSets().Lister()
|
||||
informerFactory.Apps().V1().ReplicaSets().Lister()
|
||||
|
||||
informerFactory.Batch().V1().Jobs().Lister()
|
||||
informerFactory.Batch().V1beta1().CronJobs().Lister()
|
||||
|
||||
informerFactory.Start(stopChan)
|
||||
informerFactory.WaitForCacheSync(stopChan)
|
||||
|
||||
s2iInformerFactory := informers.S2iSharedInformerFactory()
|
||||
s2iInformerFactory.Devops().V1alpha1().S2iBuilderTemplates().Lister()
|
||||
s2iInformerFactory.Devops().V1alpha1().S2iRuns().Lister()
|
||||
s2iInformerFactory.Devops().V1alpha1().S2iBuilders().Lister()
|
||||
|
||||
s2iInformerFactory.Start(stopChan)
|
||||
s2iInformerFactory.WaitForCacheSync(stopChan)
|
||||
log.Println("resources sync success")
|
||||
}
|
||||
|
||||
822
config/crds/servicemesh_v1alpha2_servicepolicy.yaml
Normal file
822
config/crds/servicemesh_v1alpha2_servicepolicy.yaml
Normal file
@@ -0,0 +1,822 @@
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
controller-tools.k8s.io: "1.0"
|
||||
name: servicepolicies.servicemesh.kubesphere.io
|
||||
spec:
|
||||
group: servicemesh.kubesphere.io
|
||||
names:
|
||||
kind: ServicePolicy
|
||||
plural: servicepolicies
|
||||
scope: Namespaced
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
properties:
|
||||
selector:
|
||||
description: Label selector for destination rules.
|
||||
type: object
|
||||
template:
|
||||
description: Template used to create a destination rule
|
||||
properties:
|
||||
spec:
|
||||
description: Spec indicates the behavior of a destination rule.
|
||||
properties:
|
||||
host:
|
||||
description: 'REQUIRED. The name of a service from the service
|
||||
registry. Service names are looked up from the platform''s
|
||||
service registry (e.g., Kubernetes services, Consul services,
|
||||
etc.) and from the hosts declared by [ServiceEntries](#ServiceEntry).
|
||||
Rules defined for services that do not exist in the service
|
||||
registry will be ignored. *Note for Kubernetes users*: When
|
||||
short names are used (e.g. "reviews" instead of "reviews.default.svc.cluster.local"),
|
||||
Istio will interpret the short name based on the namespace
|
||||
of the rule, not the service. A rule in the "default" namespace
|
||||
containing a host "reviews will be interpreted as "reviews.default.svc.cluster.local",
|
||||
irrespective of the actual namespace associated with the reviews
|
||||
service. _To avoid potential misconfigurations, it is recommended
|
||||
to always use fully qualified domain names over short names._ Note
|
||||
that the host field applies to both HTTP and TCP services.'
|
||||
type: string
|
||||
subsets:
|
||||
description: One or more named sets that represent individual
|
||||
versions of a service. Traffic policies can be overridden
|
||||
at subset level.
|
||||
items:
|
||||
properties:
|
||||
labels:
|
||||
description: REQUIRED. Labels apply a filter over the
|
||||
endpoints of a service in the service registry. See
|
||||
route rules for examples of usage.
|
||||
type: object
|
||||
name:
|
||||
description: REQUIRED. Name of the subset. The service
|
||||
name and the subset name can be used for traffic splitting
|
||||
in a route rule.
|
||||
type: string
|
||||
trafficPolicy:
|
||||
description: Traffic policies that apply to this subset.
|
||||
Subsets inherit the traffic policies specified at the
|
||||
DestinationRule level. Settings specified at the subset
|
||||
level will override the corresponding settings specified
|
||||
at the DestinationRule level.
|
||||
properties:
|
||||
connectionPool:
|
||||
description: Settings controlling the volume of connections
|
||||
to an upstream service
|
||||
properties:
|
||||
http:
|
||||
description: HTTP connection pool settings.
|
||||
properties:
|
||||
maxRequestsPerConnection:
|
||||
description: Maximum number of requests per
|
||||
connection to a backend. Setting this parameter
|
||||
to 1 disables keep alive.
|
||||
format: int32
|
||||
type: integer
|
||||
maxRetries:
|
||||
description: Maximum number of retries that
|
||||
can be outstanding to all hosts in a cluster
|
||||
at a given time. Defaults to 3.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
tcp:
|
||||
description: Settings common to both HTTP and
|
||||
TCP upstream connections.
|
||||
properties:
|
||||
connectTimeout:
|
||||
description: TCP connection timeout.
|
||||
type: string
|
||||
maxConnections:
|
||||
description: Maximum number of HTTP1 /TCP
|
||||
connections to a destination host.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
loadBalancer:
|
||||
description: Settings controlling the load balancer
|
||||
algorithms.
|
||||
properties:
|
||||
consistentHash:
|
||||
properties:
|
||||
httpCookie:
|
||||
description: Hash based on HTTP cookie.
|
||||
properties:
|
||||
name:
|
||||
description: REQUIRED. Name of the cookie.
|
||||
type: string
|
||||
path:
|
||||
description: Path to set for the cookie.
|
||||
type: string
|
||||
ttl:
|
||||
description: REQUIRED. Lifetime of the
|
||||
cookie.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- ttl
|
||||
type: object
|
||||
httpHeaderName:
|
||||
description: 'It is required to specify exactly
|
||||
one of the fields as hash key: HttpHeaderName,
|
||||
HttpCookie, or UseSourceIP. Hash based on
|
||||
a specific HTTP header.'
|
||||
type: string
|
||||
minimumRingSize:
|
||||
description: The minimum number of virtual
|
||||
nodes to use for the hash ring. Defaults
|
||||
to 1024. Larger ring sizes result in more
|
||||
granular load distributions. If the number
|
||||
of hosts in the load balancing pool is larger
|
||||
than the ring size, each host will be assigned
|
||||
a single virtual node.
|
||||
format: int64
|
||||
type: integer
|
||||
useSourceIp:
|
||||
description: Hash based on the source IP address.
|
||||
type: boolean
|
||||
type: object
|
||||
simple:
|
||||
description: 'It is required to specify exactly
|
||||
one of the fields: Simple or ConsistentHash'
|
||||
type: string
|
||||
type: object
|
||||
outlierDetection:
|
||||
description: Settings controlling eviction of unhealthy
|
||||
hosts from the load balancing pool
|
||||
properties:
|
||||
baseEjectionTime:
|
||||
description: 'Minimum ejection duration. A host
|
||||
will remain ejected for a period equal to the
|
||||
product of minimum ejection duration and the
|
||||
number of times the host has been ejected. This
|
||||
technique allows the system to automatically
|
||||
increase the ejection period for unhealthy upstream
|
||||
servers. format: 1h/1m/1s/1ms. MUST BE >=1ms.
|
||||
Default is 30s.'
|
||||
type: string
|
||||
consecutiveErrors:
|
||||
description: Number of errors before a host is
|
||||
ejected from the connection pool. Defaults to
|
||||
5. When the upstream host is accessed over HTTP,
|
||||
a 5xx return code qualifies as an error. When
|
||||
the upstream host is accessed over an opaque
|
||||
TCP connection, connect timeouts and connection
|
||||
error/failure events qualify as an error.
|
||||
format: int32
|
||||
type: integer
|
||||
interval:
|
||||
description: 'Time interval between ejection sweep
|
||||
analysis. format: 1h/1m/1s/1ms. MUST BE >=1ms.
|
||||
Default is 10s.'
|
||||
type: string
|
||||
maxEjectionPercent:
|
||||
description: Maximum % of hosts in the load balancing
|
||||
pool for the upstream service that can be ejected.
|
||||
Defaults to 10%.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
portLevelSettings:
|
||||
description: Traffic policies specific to individual
|
||||
ports. Note that port level settings will override
|
||||
the destination-level settings. Traffic settings
|
||||
specified at the destination-level will not be inherited
|
||||
when overridden by port-level settings, i.e. default
|
||||
values will be applied to fields omitted in port-level
|
||||
traffic policies.
|
||||
items:
|
||||
properties:
|
||||
connectionPool:
|
||||
description: Settings controlling the volume
|
||||
of connections to an upstream service
|
||||
properties:
|
||||
http:
|
||||
description: HTTP connection pool settings.
|
||||
properties:
|
||||
maxRequestsPerConnection:
|
||||
description: Maximum number of requests
|
||||
per connection to a backend. Setting
|
||||
this parameter to 1 disables keep
|
||||
alive.
|
||||
format: int32
|
||||
type: integer
|
||||
maxRetries:
|
||||
description: Maximum number of retries
|
||||
that can be outstanding to all hosts
|
||||
in a cluster at a given time. Defaults
|
||||
to 3.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
tcp:
|
||||
description: Settings common to both HTTP
|
||||
and TCP upstream connections.
|
||||
properties:
|
||||
connectTimeout:
|
||||
description: TCP connection timeout.
|
||||
type: string
|
||||
maxConnections:
|
||||
description: Maximum number of HTTP1
|
||||
/TCP connections to a destination
|
||||
host.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
loadBalancer:
|
||||
description: Settings controlling the load balancer
|
||||
algorithms.
|
||||
properties:
|
||||
consistentHash:
|
||||
properties:
|
||||
httpCookie:
|
||||
description: Hash based on HTTP cookie.
|
||||
properties:
|
||||
name:
|
||||
description: REQUIRED. Name of the
|
||||
cookie.
|
||||
type: string
|
||||
path:
|
||||
description: Path to set for the
|
||||
cookie.
|
||||
type: string
|
||||
ttl:
|
||||
description: REQUIRED. Lifetime
|
||||
of the cookie.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- ttl
|
||||
type: object
|
||||
httpHeaderName:
|
||||
description: 'It is required to specify
|
||||
exactly one of the fields as hash
|
||||
key: HttpHeaderName, HttpCookie, or
|
||||
UseSourceIP. Hash based on a specific
|
||||
HTTP header.'
|
||||
type: string
|
||||
minimumRingSize:
|
||||
description: The minimum number of virtual
|
||||
nodes to use for the hash ring. Defaults
|
||||
to 1024. Larger ring sizes result
|
||||
in more granular load distributions.
|
||||
If the number of hosts in the load
|
||||
balancing pool is larger than the
|
||||
ring size, each host will be assigned
|
||||
a single virtual node.
|
||||
format: int64
|
||||
type: integer
|
||||
useSourceIp:
|
||||
description: Hash based on the source
|
||||
IP address.
|
||||
type: boolean
|
||||
type: object
|
||||
simple:
|
||||
description: 'It is required to specify
|
||||
exactly one of the fields: Simple or ConsistentHash'
|
||||
type: string
|
||||
type: object
|
||||
outlierDetection:
|
||||
description: Settings controlling eviction of
|
||||
unhealthy hosts from the load balancing pool
|
||||
properties:
|
||||
baseEjectionTime:
|
||||
description: 'Minimum ejection duration.
|
||||
A host will remain ejected for a period
|
||||
equal to the product of minimum ejection
|
||||
duration and the number of times the host
|
||||
has been ejected. This technique allows
|
||||
the system to automatically increase the
|
||||
ejection period for unhealthy upstream
|
||||
servers. format: 1h/1m/1s/1ms. MUST BE
|
||||
>=1ms. Default is 30s.'
|
||||
type: string
|
||||
consecutiveErrors:
|
||||
description: Number of errors before a host
|
||||
is ejected from the connection pool. Defaults
|
||||
to 5. When the upstream host is accessed
|
||||
over HTTP, a 5xx return code qualifies
|
||||
as an error. When the upstream host is
|
||||
accessed over an opaque TCP connection,
|
||||
connect timeouts and connection error/failure
|
||||
events qualify as an error.
|
||||
format: int32
|
||||
type: integer
|
||||
interval:
|
||||
description: 'Time interval between ejection
|
||||
sweep analysis. format: 1h/1m/1s/1ms.
|
||||
MUST BE >=1ms. Default is 10s.'
|
||||
type: string
|
||||
maxEjectionPercent:
|
||||
description: Maximum % of hosts in the load
|
||||
balancing pool for the upstream service
|
||||
that can be ejected. Defaults to 10%.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
port:
|
||||
description: Specifies the port name or number
|
||||
of a port on the destination service on which
|
||||
this policy is being applied. Names must
|
||||
comply with DNS label syntax (rfc1035) and
|
||||
therefore cannot collide with numbers. If
|
||||
there are multiple ports on a service with
|
||||
the same protocol the names should be of the
|
||||
form <protocol-name>-<DNS label>.
|
||||
properties:
|
||||
name:
|
||||
description: Valid port name
|
||||
type: string
|
||||
number:
|
||||
description: Valid port number
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
tls:
|
||||
description: TLS related settings for connections
|
||||
to the upstream service.
|
||||
properties:
|
||||
caCertificates:
|
||||
description: 'OPTIONAL: The path to the
|
||||
file containing certificate authority
|
||||
certificates to use in verifying a presented
|
||||
server certificate. If omitted, the proxy
|
||||
will not verify the server''s certificate.
|
||||
Should be empty if mode is `ISTIO_MUTUAL`.'
|
||||
type: string
|
||||
clientCertificate:
|
||||
description: REQUIRED if mode is `MUTUAL`.
|
||||
The path to the file holding the client-side
|
||||
TLS certificate to use. Should be empty
|
||||
if mode is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
mode:
|
||||
description: 'REQUIRED: Indicates whether
|
||||
connections to this port should be secured
|
||||
using TLS. The value of this field determines
|
||||
how TLS is enforced.'
|
||||
type: string
|
||||
privateKey:
|
||||
description: REQUIRED if mode is `MUTUAL`.
|
||||
The path to the file holding the client's
|
||||
private key. Should be empty if mode is
|
||||
`ISTIO_MUTUAL`.
|
||||
type: string
|
||||
sni:
|
||||
description: SNI string to present to the
|
||||
server during TLS handshake. Should be
|
||||
empty if mode is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
subjectAltNames:
|
||||
description: A list of alternate names to
|
||||
verify the subject identity in the certificate.
|
||||
If specified, the proxy will verify that
|
||||
the server certificate's subject alt name
|
||||
matches one of the specified values. Should
|
||||
be empty if mode is `ISTIO_MUTUAL`.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- mode
|
||||
type: object
|
||||
required:
|
||||
- port
|
||||
type: object
|
||||
type: array
|
||||
tls:
|
||||
description: TLS related settings for connections
|
||||
to the upstream service.
|
||||
properties:
|
||||
caCertificates:
|
||||
description: 'OPTIONAL: The path to the file containing
|
||||
certificate authority certificates to use in
|
||||
verifying a presented server certificate. If
|
||||
omitted, the proxy will not verify the server''s
|
||||
certificate. Should be empty if mode is `ISTIO_MUTUAL`.'
|
||||
type: string
|
||||
clientCertificate:
|
||||
description: REQUIRED if mode is `MUTUAL`. The
|
||||
path to the file holding the client-side TLS
|
||||
certificate to use. Should be empty if mode
|
||||
is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
mode:
|
||||
description: 'REQUIRED: Indicates whether connections
|
||||
to this port should be secured using TLS. The
|
||||
value of this field determines how TLS is enforced.'
|
||||
type: string
|
||||
privateKey:
|
||||
description: REQUIRED if mode is `MUTUAL`. The
|
||||
path to the file holding the client's private
|
||||
key. Should be empty if mode is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
sni:
|
||||
description: SNI string to present to the server
|
||||
during TLS handshake. Should be empty if mode
|
||||
is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
subjectAltNames:
|
||||
description: A list of alternate names to verify
|
||||
the subject identity in the certificate. If
|
||||
specified, the proxy will verify that the server
|
||||
certificate's subject alt name matches one of
|
||||
the specified values. Should be empty if mode
|
||||
is `ISTIO_MUTUAL`.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- mode
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- labels
|
||||
type: object
|
||||
type: array
|
||||
trafficPolicy:
|
||||
description: Traffic policies to apply (load balancing policy,
|
||||
connection pool sizes, outlier detection).
|
||||
properties:
|
||||
connectionPool:
|
||||
description: Settings controlling the volume of connections
|
||||
to an upstream service
|
||||
properties:
|
||||
http:
|
||||
description: HTTP connection pool settings.
|
||||
properties:
|
||||
maxRequestsPerConnection:
|
||||
description: Maximum number of requests per connection
|
||||
to a backend. Setting this parameter to 1 disables
|
||||
keep alive.
|
||||
format: int32
|
||||
type: integer
|
||||
maxRetries:
|
||||
description: Maximum number of retries that can
|
||||
be outstanding to all hosts in a cluster at a
|
||||
given time. Defaults to 3.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
tcp:
|
||||
description: Settings common to both HTTP and TCP upstream
|
||||
connections.
|
||||
properties:
|
||||
connectTimeout:
|
||||
description: TCP connection timeout.
|
||||
type: string
|
||||
maxConnections:
|
||||
description: Maximum number of HTTP1 /TCP connections
|
||||
to a destination host.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
loadBalancer:
|
||||
description: Settings controlling the load balancer algorithms.
|
||||
properties:
|
||||
consistentHash:
|
||||
properties:
|
||||
httpCookie:
|
||||
description: Hash based on HTTP cookie.
|
||||
properties:
|
||||
name:
|
||||
description: REQUIRED. Name of the cookie.
|
||||
type: string
|
||||
path:
|
||||
description: Path to set for the cookie.
|
||||
type: string
|
||||
ttl:
|
||||
description: REQUIRED. Lifetime of the cookie.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- ttl
|
||||
type: object
|
||||
httpHeaderName:
|
||||
description: 'It is required to specify exactly
|
||||
one of the fields as hash key: HttpHeaderName,
|
||||
HttpCookie, or UseSourceIP. Hash based on a specific
|
||||
HTTP header.'
|
||||
type: string
|
||||
minimumRingSize:
|
||||
description: The minimum number of virtual nodes
|
||||
to use for the hash ring. Defaults to 1024. Larger
|
||||
ring sizes result in more granular load distributions.
|
||||
If the number of hosts in the load balancing pool
|
||||
is larger than the ring size, each host will be
|
||||
assigned a single virtual node.
|
||||
format: int64
|
||||
type: integer
|
||||
useSourceIp:
|
||||
description: Hash based on the source IP address.
|
||||
type: boolean
|
||||
type: object
|
||||
simple:
|
||||
description: 'It is required to specify exactly one
|
||||
of the fields: Simple or ConsistentHash'
|
||||
type: string
|
||||
type: object
|
||||
outlierDetection:
|
||||
description: Settings controlling eviction of unhealthy
|
||||
hosts from the load balancing pool
|
||||
properties:
|
||||
baseEjectionTime:
|
||||
description: 'Minimum ejection duration. A host will
|
||||
remain ejected for a period equal to the product of
|
||||
minimum ejection duration and the number of times
|
||||
the host has been ejected. This technique allows the
|
||||
system to automatically increase the ejection period
|
||||
for unhealthy upstream servers. format: 1h/1m/1s/1ms.
|
||||
MUST BE >=1ms. Default is 30s.'
|
||||
type: string
|
||||
consecutiveErrors:
|
||||
description: Number of errors before a host is ejected
|
||||
from the connection pool. Defaults to 5. When the
|
||||
upstream host is accessed over HTTP, a 5xx return
|
||||
code qualifies as an error. When the upstream host
|
||||
is accessed over an opaque TCP connection, connect
|
||||
timeouts and connection error/failure events qualify
|
||||
as an error.
|
||||
format: int32
|
||||
type: integer
|
||||
interval:
|
||||
description: 'Time interval between ejection sweep analysis.
|
||||
format: 1h/1m/1s/1ms. MUST BE >=1ms. Default is 10s.'
|
||||
type: string
|
||||
maxEjectionPercent:
|
||||
description: Maximum % of hosts in the load balancing
|
||||
pool for the upstream service that can be ejected.
|
||||
Defaults to 10%.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
portLevelSettings:
|
||||
description: Traffic policies specific to individual ports.
|
||||
Note that port level settings will override the destination-level
|
||||
settings. Traffic settings specified at the destination-level
|
||||
will not be inherited when overridden by port-level settings,
|
||||
i.e. default values will be applied to fields omitted
|
||||
in port-level traffic policies.
|
||||
items:
|
||||
properties:
|
||||
connectionPool:
|
||||
description: Settings controlling the volume of connections
|
||||
to an upstream service
|
||||
properties:
|
||||
http:
|
||||
description: HTTP connection pool settings.
|
||||
properties:
|
||||
maxRequestsPerConnection:
|
||||
description: Maximum number of requests per
|
||||
connection to a backend. Setting this parameter
|
||||
to 1 disables keep alive.
|
||||
format: int32
|
||||
type: integer
|
||||
maxRetries:
|
||||
description: Maximum number of retries that
|
||||
can be outstanding to all hosts in a cluster
|
||||
at a given time. Defaults to 3.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
tcp:
|
||||
description: Settings common to both HTTP and
|
||||
TCP upstream connections.
|
||||
properties:
|
||||
connectTimeout:
|
||||
description: TCP connection timeout.
|
||||
type: string
|
||||
maxConnections:
|
||||
description: Maximum number of HTTP1 /TCP
|
||||
connections to a destination host.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
loadBalancer:
|
||||
description: Settings controlling the load balancer
|
||||
algorithms.
|
||||
properties:
|
||||
consistentHash:
|
||||
properties:
|
||||
httpCookie:
|
||||
description: Hash based on HTTP cookie.
|
||||
properties:
|
||||
name:
|
||||
description: REQUIRED. Name of the cookie.
|
||||
type: string
|
||||
path:
|
||||
description: Path to set for the cookie.
|
||||
type: string
|
||||
ttl:
|
||||
description: REQUIRED. Lifetime of the
|
||||
cookie.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- ttl
|
||||
type: object
|
||||
httpHeaderName:
|
||||
description: 'It is required to specify exactly
|
||||
one of the fields as hash key: HttpHeaderName,
|
||||
HttpCookie, or UseSourceIP. Hash based on
|
||||
a specific HTTP header.'
|
||||
type: string
|
||||
minimumRingSize:
|
||||
description: The minimum number of virtual
|
||||
nodes to use for the hash ring. Defaults
|
||||
to 1024. Larger ring sizes result in more
|
||||
granular load distributions. If the number
|
||||
of hosts in the load balancing pool is larger
|
||||
than the ring size, each host will be assigned
|
||||
a single virtual node.
|
||||
format: int64
|
||||
type: integer
|
||||
useSourceIp:
|
||||
description: Hash based on the source IP address.
|
||||
type: boolean
|
||||
type: object
|
||||
simple:
|
||||
description: 'It is required to specify exactly
|
||||
one of the fields: Simple or ConsistentHash'
|
||||
type: string
|
||||
type: object
|
||||
outlierDetection:
|
||||
description: Settings controlling eviction of unhealthy
|
||||
hosts from the load balancing pool
|
||||
properties:
|
||||
baseEjectionTime:
|
||||
description: 'Minimum ejection duration. A host
|
||||
will remain ejected for a period equal to the
|
||||
product of minimum ejection duration and the
|
||||
number of times the host has been ejected. This
|
||||
technique allows the system to automatically
|
||||
increase the ejection period for unhealthy upstream
|
||||
servers. format: 1h/1m/1s/1ms. MUST BE >=1ms.
|
||||
Default is 30s.'
|
||||
type: string
|
||||
consecutiveErrors:
|
||||
description: Number of errors before a host is
|
||||
ejected from the connection pool. Defaults to
|
||||
5. When the upstream host is accessed over HTTP,
|
||||
a 5xx return code qualifies as an error. When
|
||||
the upstream host is accessed over an opaque
|
||||
TCP connection, connect timeouts and connection
|
||||
error/failure events qualify as an error.
|
||||
format: int32
|
||||
type: integer
|
||||
interval:
|
||||
description: 'Time interval between ejection sweep
|
||||
analysis. format: 1h/1m/1s/1ms. MUST BE >=1ms.
|
||||
Default is 10s.'
|
||||
type: string
|
||||
maxEjectionPercent:
|
||||
description: Maximum % of hosts in the load balancing
|
||||
pool for the upstream service that can be ejected.
|
||||
Defaults to 10%.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
port:
|
||||
description: Specifies the port name or number of
|
||||
a port on the destination service on which this
|
||||
policy is being applied. Names must comply with
|
||||
DNS label syntax (rfc1035) and therefore cannot
|
||||
collide with numbers. If there are multiple ports
|
||||
on a service with the same protocol the names should
|
||||
be of the form <protocol-name>-<DNS label>.
|
||||
properties:
|
||||
name:
|
||||
description: Valid port name
|
||||
type: string
|
||||
number:
|
||||
description: Valid port number
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
tls:
|
||||
description: TLS related settings for connections
|
||||
to the upstream service.
|
||||
properties:
|
||||
caCertificates:
|
||||
description: 'OPTIONAL: The path to the file containing
|
||||
certificate authority certificates to use in
|
||||
verifying a presented server certificate. If
|
||||
omitted, the proxy will not verify the server''s
|
||||
certificate. Should be empty if mode is `ISTIO_MUTUAL`.'
|
||||
type: string
|
||||
clientCertificate:
|
||||
description: REQUIRED if mode is `MUTUAL`. The
|
||||
path to the file holding the client-side TLS
|
||||
certificate to use. Should be empty if mode
|
||||
is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
mode:
|
||||
description: 'REQUIRED: Indicates whether connections
|
||||
to this port should be secured using TLS. The
|
||||
value of this field determines how TLS is enforced.'
|
||||
type: string
|
||||
privateKey:
|
||||
description: REQUIRED if mode is `MUTUAL`. The
|
||||
path to the file holding the client's private
|
||||
key. Should be empty if mode is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
sni:
|
||||
description: SNI string to present to the server
|
||||
during TLS handshake. Should be empty if mode
|
||||
is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
subjectAltNames:
|
||||
description: A list of alternate names to verify
|
||||
the subject identity in the certificate. If
|
||||
specified, the proxy will verify that the server
|
||||
certificate's subject alt name matches one of
|
||||
the specified values. Should be empty if mode
|
||||
is `ISTIO_MUTUAL`.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- mode
|
||||
type: object
|
||||
required:
|
||||
- port
|
||||
type: object
|
||||
type: array
|
||||
tls:
|
||||
description: TLS related settings for connections to the
|
||||
upstream service.
|
||||
properties:
|
||||
caCertificates:
|
||||
description: 'OPTIONAL: The path to the file containing
|
||||
certificate authority certificates to use in verifying
|
||||
a presented server certificate. If omitted, the proxy
|
||||
will not verify the server''s certificate. Should
|
||||
be empty if mode is `ISTIO_MUTUAL`.'
|
||||
type: string
|
||||
clientCertificate:
|
||||
description: REQUIRED if mode is `MUTUAL`. The path
|
||||
to the file holding the client-side TLS certificate
|
||||
to use. Should be empty if mode is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
mode:
|
||||
description: 'REQUIRED: Indicates whether connections
|
||||
to this port should be secured using TLS. The value
|
||||
of this field determines how TLS is enforced.'
|
||||
type: string
|
||||
privateKey:
|
||||
description: REQUIRED if mode is `MUTUAL`. The path
|
||||
to the file holding the client's private key. Should
|
||||
be empty if mode is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
sni:
|
||||
description: SNI string to present to the server during
|
||||
TLS handshake. Should be empty if mode is `ISTIO_MUTUAL`.
|
||||
type: string
|
||||
subjectAltNames:
|
||||
description: A list of alternate names to verify the
|
||||
subject identity in the certificate. If specified,
|
||||
the proxy will verify that the server certificate's
|
||||
subject alt name matches one of the specified values.
|
||||
Should be empty if mode is `ISTIO_MUTUAL`.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- mode
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- host
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
type: object
|
||||
version: v1alpha2
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
@@ -6,6 +6,23 @@ metadata:
|
||||
controller-tools.k8s.io: "1.0"
|
||||
name: strategies.servicemesh.kubesphere.io
|
||||
spec:
|
||||
additionalPrinterColumns:
|
||||
- JSONPath: .spec.type
|
||||
description: type of strategy
|
||||
name: Type
|
||||
type: string
|
||||
- JSONPath: .spec.template.spec.hosts
|
||||
description: destination hosts
|
||||
name: Hosts
|
||||
type: string
|
||||
- JSONPath: .metadata.creationTimestamp
|
||||
description: 'CreationTimestamp is a timestamp representing the server time when
|
||||
this object was created. It is not guaranteed to be set in happens-before order
|
||||
across separate operations. Clients may not set this value. It is represented
|
||||
in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
|
||||
lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
|
||||
name: Age
|
||||
type: date
|
||||
group: servicemesh.kubesphere.io
|
||||
names:
|
||||
kind: Strategy
|
||||
@@ -28,10 +45,18 @@ spec:
|
||||
type: object
|
||||
spec:
|
||||
properties:
|
||||
governor:
|
||||
description: Governor version, the version takes control of all incoming
|
||||
traffic label version value
|
||||
type: string
|
||||
paused:
|
||||
description: Indicates that the strategy is paused and will not be processed
|
||||
by the strategy controller
|
||||
type: boolean
|
||||
principal:
|
||||
description: Principal version, the one as reference version label version
|
||||
value
|
||||
type: string
|
||||
selector:
|
||||
description: Label selector for virtual services.
|
||||
type: object
|
||||
|
||||
9
config/samples/servicemesh_v1alpha2_servicepolicy.yaml
Normal file
9
config/samples/servicemesh_v1alpha2_servicepolicy.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
apiVersion: servicemesh.kubesphere.io/v1alpha2
|
||||
kind: ServicePolicy
|
||||
metadata:
|
||||
labels:
|
||||
controller-tools.k8s.io: "1.0"
|
||||
name: servicepolicy-sample
|
||||
spec:
|
||||
# Add fields here
|
||||
foo: bar
|
||||
@@ -12,6 +12,8 @@ spec:
|
||||
"servicemesh.kubesphere.io/type": "canary"
|
||||
template:
|
||||
spec:
|
||||
service: "details"
|
||||
principal: "v1"
|
||||
hosts:
|
||||
- details
|
||||
http:
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
|
||||
docker build -f build/ks-apigateway/Dockerfile -t kubespheredev/ks-apigateway:latest .
|
||||
docker build -f build/ks-apiserver/Dockerfile -t kubespheredev/ks-apiserver:latest .
|
||||
docker build -f build/ks-iam/Dockerfile -t kubespheredev/ks-iam:latest .
|
||||
docker build -f build/ks-iam/Dockerfile -t kubespheredev/ks-iam:latest .
|
||||
|
||||
docker build -f build/controller-manager/Dockerfile -t kubespheredev/ks-controller-manager:latest .
|
||||
|
||||
@@ -6,3 +6,4 @@ echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
docker push kubespheredev/ks-apigateway:latest
|
||||
docker push kubespheredev/ks-apiserver:latest
|
||||
docker push kubespheredev/ks-iam:latest
|
||||
docker push kubespheredev/ks-controller-manager:latest
|
||||
|
||||
@@ -45,15 +45,7 @@ esac
|
||||
command_exists curl
|
||||
command_exists tar
|
||||
|
||||
if [ "x${KUBEBUILDER_VERSION}" = "x" ] ; then
|
||||
KUBEBUILDER_VERSION=$(curl -L -s https://api.github.com/repos/kubernetes-sigs/kubebuilder/releases/latest | \
|
||||
grep tag_name | sed "s/ *\"tag_name\": *\"\\(.*\\)\",*/\\1/")
|
||||
if [ -z "$KUBEBUILDER_VERSION" ]; then
|
||||
echo "\nUnable to fetch the latest version tag. This may be due to network access problem"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
KUBEBUILDER_VERSION=v1.0.8
|
||||
KUBEBUILDER_VERSION=${KUBEBUILDER_VERSION#"v"}
|
||||
KUBEBUILDER_VERSION_NAME="kubebuilder_${KUBEBUILDER_VERSION}"
|
||||
KUBEBUILDER_DIR=/usr/local/kubebuilder
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
"kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
|
||||
"sigs.k8s.io/application/pkg/apis/app/v1beta1"
|
||||
"github.com/kubernetes-sigs/application/pkg/apis/app/v1beta1"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
33
pkg/apis/logging/install/install.go
Normal file
33
pkg/apis/logging/install/install.go
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/apis/logging/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(loggingv1alpha2.AddToContainer(container))
|
||||
}
|
||||
217
pkg/apis/logging/v1alpha2/register.go
Normal file
217
pkg/apis/logging/v1alpha2/register.go
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/logging"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/filter"
|
||||
)
|
||||
|
||||
const GroupName = "logging.kubesphere.io"
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
var (
|
||||
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
|
||||
AddToContainer = WebServiceBuilder.AddToContainer
|
||||
)
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
tags := []string{"Logging"}
|
||||
|
||||
ws.Route(ws.GET("/cluster").To(logging.LoggingQueryCluster).
|
||||
Filter(filter.Logging).
|
||||
Doc("cluster level log query").
|
||||
Param(ws.QueryParameter("operation", "operation: query statistics").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("workspaces", "workspaces specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("workspace_query", "workspace query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("namespaces", "namespaces specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("namespace_query", "namespace query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("workloads", "workloads specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("workload_query", "workload query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("pods", "pods specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("pod_query", "pod query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("containers", "containers specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("container_query", "container query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("log_query", "log query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("interval", "interval of time histogram").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("start_time", "range start time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("end_time", "range end time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort", "sort method").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("from", "begin index of result returned").DataType("int").Required(true)).
|
||||
Param(ws.QueryParameter("size", "size of result returned").DataType("int").Required(true)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}").To(logging.LoggingQueryWorkspace).
|
||||
Filter(filter.Logging).
|
||||
Doc("workspace level log query").
|
||||
Param(ws.PathParameter("workspace", "workspace specify").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("operation", "operation: query statistics").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("namespaces", "namespaces specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("namespace_query", "namespace query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("workloads", "workloads specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("workload_query", "workload query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("pods", "pods specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("pod_query", "pod query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("containers", "containers specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("container_query", "container query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("log_query", "log query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("interval", "interval of time histogram").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("start_time", "range start time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("end_time", "range end time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort", "sort method").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("from", "begin index of result returned").DataType("int").Required(true)).
|
||||
Param(ws.QueryParameter("size", "size of result returned").DataType("int").Required(true)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}").To(logging.LoggingQueryNamespace).
|
||||
Filter(filter.Logging).
|
||||
Doc("namespace level log query").
|
||||
Param(ws.PathParameter("namespace", "namespace specify").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("operation", "operation: query statistics").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("workloads", "workloads specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("workload_query", "workload query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("pods", "pods specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("pod_query", "pod query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("containers", "containers specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("container_query", "container query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("log_query", "log query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("interval", "interval of time histogram").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("start_time", "range start time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("end_time", "range end time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort", "sort method").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("from", "begin index of result returned").DataType("int").Required(true)).
|
||||
Param(ws.QueryParameter("size", "size of result returned").DataType("int").Required(true)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloads/{workload}").To(logging.LoggingQueryWorkload).
|
||||
Filter(filter.Logging).
|
||||
Doc("workload level log query").
|
||||
Param(ws.PathParameter("namespace", "namespace specify").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("workload", "workload specify").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("operation", "operation: query statistics").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("pods", "pods specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("pod_query", "pod query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("containers", "containers specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("container_query", "container query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("log_query", "log query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("interval", "interval of time histogram").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("start_time", "range start time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("end_time", "range end time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort", "sort method").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("from", "begin index of result returned").DataType("int").Required(true)).
|
||||
Param(ws.QueryParameter("size", "size of result returned").DataType("int").Required(true)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}").To(logging.LoggingQueryPod).
|
||||
Filter(filter.Logging).
|
||||
Doc("pod level log query").
|
||||
Param(ws.PathParameter("namespace", "namespace specify").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("pod", "pod specify").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("operation", "operation: query statistics").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("containers", "containers specify").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("container_query", "container query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("log_query", "log query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("interval", "interval of time histogram").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("start_time", "range start time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("end_time", "range end time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort", "sort method").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("from", "begin index of result returned").DataType("int").Required(true)).
|
||||
Param(ws.QueryParameter("size", "size of result returned").DataType("int").Required(true)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers/{container}").To(logging.LoggingQueryContainer).
|
||||
Filter(filter.Logging).
|
||||
Doc("container level log query").
|
||||
Param(ws.PathParameter("namespace", "namespace specify").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("pod", "pod specify").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("container", "container specify").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("operation", "operation: query statistics").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("log_query", "log query keywords").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("interval", "interval of time histogram").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("start_time", "range start time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("end_time", "range end time").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort", "sort method").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("from", "begin index of result returned").DataType("int").Required(true)).
|
||||
Param(ws.QueryParameter("size", "size of result returned").DataType("int").Required(true)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/fluentbit/filters").To(logging.LoggingQueryFluentbitFilters).
|
||||
Filter(filter.Logging).
|
||||
Doc("log fluent-bit filters query").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.POST("/fluentbit/filters").To(logging.LoggingUpdateFluentbitFilters).
|
||||
Filter(filter.Logging).
|
||||
Doc("log fluent-bit filters update").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/fluentbit/outputs").To(logging.LoggingQueryFluentbitOutputs).
|
||||
Filter(filter.Logging).
|
||||
Doc("log fluent-bit outputs query").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.POST("/fluentbit/outputs").To(logging.LoggingInsertFluentbitOutput).
|
||||
Filter(filter.Logging).
|
||||
Doc("log fluent-bit outputs insert").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.POST("/fluentbit/outputs/{output}").To(logging.LoggingUpdateFluentbitOutput).
|
||||
Filter(filter.Logging).
|
||||
Doc("log fluent-bit outputs update").
|
||||
Param(ws.PathParameter("output", "output id").DataType("int").Required(true)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.DELETE("/fluentbit/outputs/{output}").To(logging.LoggingDeleteFluentbitOutput).
|
||||
Filter(filter.Logging).
|
||||
Doc("log fluent-bit outputs delete").
|
||||
Param(ws.PathParameter("output", "output id").DataType("int").Required(true)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
c.Add(ws)
|
||||
return nil
|
||||
}
|
||||
@@ -39,168 +39,196 @@ func addWebService(c *restful.Container) error {
|
||||
|
||||
tags := []string{"Monitoring"}
|
||||
|
||||
ws.Route(ws.GET("/clusters").To(monitoring.MonitorCluster).
|
||||
ws.Route(ws.GET("/cluster").To(monitoring.MonitorCluster).
|
||||
Doc("monitor cluster level metrics").
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("cluster_cpu_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("cluster_cpu_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/nodes").To(monitoring.MonitorNode).
|
||||
Doc("monitor nodes level metrics").
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("node_cpu_utilisation")).
|
||||
Param(ws.QueryParameter("nodes_filter", "node re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("node_cpu_utilisation")).
|
||||
Param(ws.QueryParameter("resources_filter", "node re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}").To(monitoring.MonitorNode).
|
||||
Doc("monitor specific node level metrics").
|
||||
Param(ws.PathParameter("node", "specific node").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("node_cpu_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("node", "specific node").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("node_cpu_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces").To(monitoring.MonitorNamespace).
|
||||
Doc("monitor namespaces level metrics").
|
||||
Param(ws.QueryParameter("namespaces_filter", "namespaces re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("namespace_memory_utilisation")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.QueryParameter("resources_filter", "namespaces re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("namespace_memory_utilisation")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}").To(monitoring.MonitorNamespace).
|
||||
Doc("monitor specific namespace level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("namespace_memory_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("namespace", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("namespace_memory_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods").To(monitoring.MonitorPod).
|
||||
Doc("monitor pods level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("namespace", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("resources_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}").To(monitoring.MonitorPod).
|
||||
Doc("monitor specific pod level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("namespace", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod", "specific pod").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}/pods").To(monitoring.MonitorPod).
|
||||
Doc("monitor pods level metrics by nodeid").
|
||||
Param(ws.PathParameter("node", "specific node").Required(true).DefaultValue("i-k89a62il")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").Required(false).DefaultValue("openpitrix.*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("node", "specific node").DataType("string").Required(true).DefaultValue("i-k89a62il")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("resources_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("openpitrix.*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}/pods/{pod}").To(monitoring.MonitorPod).
|
||||
Doc("monitor specific pod level metrics by nodeid").
|
||||
Param(ws.PathParameter("node", "specific node").Required(true).DefaultValue("i-k89a62il")).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("node", "specific node").DataType("string").Required(true).DefaultValue("i-k89a62il")).
|
||||
Param(ws.PathParameter("pod", "specific pod").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}/pods/{pod}/containers").To(monitoring.MonitorContainer).
|
||||
Doc("monitor specific pod level metrics by nodeid").
|
||||
Param(ws.PathParameter("node", "specific node").Required(true)).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true)).
|
||||
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("node", "specific node").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("pod", "specific pod").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("resources_filter", "container re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers").To(monitoring.MonitorContainer).
|
||||
Doc("monitor containers level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("namespace", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod", "specific pod").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("resources_filter", "container re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers/{container}").To(monitoring.MonitorContainer).
|
||||
Doc("monitor specific container level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
|
||||
Param(ws.PathParameter("container", "specific container").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("namespace", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod", "specific pod").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.PathParameter("container", "specific container").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloads/{workload_kind}").To(monitoring.MonitorWorkload).
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloads/{workload_kind}/{workload}").To(monitoring.MonitorWorkload).
|
||||
Doc("monitor specific workload level metrics").
|
||||
Param(ws.PathParameter("namespace", "namespace").Required(true).DefaultValue("kube-system")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
|
||||
Param(ws.PathParameter("workload_kind", "workload kind").Required(false).DefaultValue("daemonset")).
|
||||
Param(ws.QueryParameter("workload_name", "workload name").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").Required(false).DefaultValue("openpitrix.*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "max metric items in a page").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("namespace", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
|
||||
Param(ws.PathParameter("workload_kind", "workload kind").DataType("string").Required(true).DefaultValue("daemonset")).
|
||||
Param(ws.PathParameter("workload", "workload name").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("resources_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("openpitrix.*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "max metric items in a page").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloads").To(monitoring.MonitorWorkload).
|
||||
Doc("monitor all workload level metrics").
|
||||
Param(ws.PathParameter("namespace", "namespace").Required(true).DefaultValue("kube-system")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
|
||||
Param(ws.QueryParameter("workloads_filter", "pod re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("namespace", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("resources_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
// list all namespace in this workspace by selected metrics
|
||||
ws.Route(ws.GET("/workspaces/{workspace}").To(monitoring.MonitorOneWorkspace).
|
||||
Doc("monitor workspaces level metrics").
|
||||
Param(ws.PathParameter("workspace", "workspace name").Required(true)).
|
||||
Param(ws.QueryParameter("namespaces_filter", "namespaces filter").Required(false).DefaultValue("k.*")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("namespace_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.PathParameter("workspace", "workspace name").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("resources_filter", "namespaces filter").DataType("string").Required(false).DefaultValue("k.*")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("namespace_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/workspaces").To(monitoring.MonitorAllWorkspaces).
|
||||
Doc("monitor workspaces level metrics").
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("workspace_memory_utilisation")).
|
||||
Param(ws.QueryParameter("workspaces_filter", "workspaces re2 expression filter").Required(false).DefaultValue(".*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/components").To(monitoring.MonitorComponentStatus).
|
||||
Doc("monitor k8s components status").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("workspace_memory_utilisation")).
|
||||
Param(ws.QueryParameter("resources_filter", "workspaces re2 expression filter").DataType("string").Required(false).DefaultValue(".*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
c.Add(ws)
|
||||
return nil
|
||||
|
||||
@@ -68,8 +68,8 @@ func addWebService(c *restful.Container) error {
|
||||
To(metrics.GetWorkloadMetrics).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get workload metrics from a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of the namespace")).
|
||||
Param(webservice.PathParameter("workload", "name of the workload")).
|
||||
Param(webservice.PathParameter("namespace", "name of the namespace").Required(true)).
|
||||
Param(webservice.PathParameter("workload", "name of the workload").Required(true)).
|
||||
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
|
||||
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
|
||||
@@ -87,7 +87,7 @@ func addWebService(c *restful.Container) error {
|
||||
To(metrics.GetNamespaceMetrics).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get workload metrics from a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of the namespace")).
|
||||
Param(webservice.PathParameter("namespace", "name of the namespace").Required(true)).
|
||||
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
|
||||
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
|
||||
@@ -105,7 +105,7 @@ func addWebService(c *restful.Container) error {
|
||||
To(metrics.GetNamespaceGraph).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get service graph for a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace")).
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
|
||||
Param(webservice.QueryParameter("graphType", "type of the generated service graph, eg. ")).
|
||||
Param(webservice.QueryParameter("groupBy", "group nodes by kind")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which time point, default now")).
|
||||
@@ -118,7 +118,7 @@ func addWebService(c *restful.Container) error {
|
||||
To(metrics.GetNamespacesGraph).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get service graph for a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace")).
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
|
||||
Param(webservice.QueryParameter("graphType", "type of the generated service graph, eg. ")).
|
||||
Param(webservice.QueryParameter("groupBy", "group nodes by kind")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which time point, default now")).
|
||||
@@ -126,6 +126,50 @@ func addWebService(c *restful.Container) error {
|
||||
Param(webservice.QueryParameter("namespaces", "names of namespaces")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
// Get namespace health
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/health").
|
||||
To(metrics.GetNamespaceHealth).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get workload health").
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
|
||||
Param(webservice.PathParameter("type", "the type of health, app/service/workload, default app").DefaultValue("app")).
|
||||
Param(webservice.QueryParameter("rateInterval", "the rate interval used for fetching error rate").DefaultValue("10m").Required(true)).
|
||||
Param(webservice.QueryParameter("queryTime", "the time to use for query")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
// Get workloads health
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/workloads/{workload}/health").
|
||||
To(metrics.GetWorkloadHealth).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get workload health").
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
|
||||
Param(webservice.PathParameter("workload", "workload name").Required(true)).
|
||||
Param(webservice.QueryParameter("rateInterval", "the rate interval used for fetching error rate").DefaultValue("10m").Required(true)).
|
||||
Param(webservice.QueryParameter("queryTime", "the time to use for query")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
// Get app health
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/apps/{app}/health").
|
||||
To(metrics.GetAppHealth).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get workload health").
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
|
||||
Param(webservice.PathParameter("app", "app name").Required(true)).
|
||||
Param(webservice.QueryParameter("rateInterval", "the rate interval used for fetching error rate").DefaultValue("10m").Required(true)).
|
||||
Param(webservice.QueryParameter("queryTime", "the time to use for query")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
// Get service health
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/services/{service}/health").
|
||||
To(metrics.GetServiceHealth).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get workload health").
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
|
||||
Param(webservice.PathParameter("service", "service name").Required(true)).
|
||||
Param(webservice.QueryParameter("rateInterval", "the rate interval used for fetching error rate").DefaultValue("10m").Required(true)).
|
||||
Param(webservice.QueryParameter("queryTime", "the time to use for query")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
c.Add(webservice)
|
||||
|
||||
return nil
|
||||
|
||||
127
pkg/apis/servicemesh/v1alpha2/servicepolicy_types.go
Normal file
127
pkg/apis/servicemesh/v1alpha2/servicepolicy_types.go
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright 2019 The KubeSphere 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 v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||
|
||||
// ServicePolicySpec defines the desired state of ServicePolicy
|
||||
type ServicePolicySpec struct {
|
||||
|
||||
// Label selector for destination rules.
|
||||
// +optional
|
||||
Selector *metav1.LabelSelector `json:"selector,omitempty"`
|
||||
|
||||
// Template used to create a destination rule
|
||||
// +optional
|
||||
Template DestinationRuleSpecTemplate `json:"template,omitempty"`
|
||||
}
|
||||
|
||||
type DestinationRuleSpecTemplate struct {
|
||||
|
||||
// Metadata of the virtual services created from this template
|
||||
// +optional
|
||||
metav1.ObjectMeta
|
||||
|
||||
// Spec indicates the behavior of a destination rule.
|
||||
// +optional
|
||||
Spec v1alpha3.DestinationRuleSpec `json:"spec,omitempty"`
|
||||
}
|
||||
|
||||
type ServicePolicyConditionType string
|
||||
|
||||
// These are valid conditions of a strategy.
|
||||
const (
|
||||
// StrategyComplete means the strategy has been delivered to istio.
|
||||
ServicePolicyComplete ServicePolicyConditionType = "Complete"
|
||||
|
||||
// StrategyFailed means the strategy has failed its delivery to istio.
|
||||
ServicePolicyFailed ServicePolicyConditionType = "Failed"
|
||||
)
|
||||
|
||||
// StrategyCondition describes current state of a strategy.
|
||||
type ServicePolicyCondition struct {
|
||||
// Type of strategy condition, Complete or Failed.
|
||||
Type ServicePolicyConditionType
|
||||
|
||||
// Status of the condition, one of True, False, Unknown
|
||||
Status apiextensions.ConditionStatus
|
||||
|
||||
// Last time the condition was checked.
|
||||
// +optional
|
||||
LastProbeTime metav1.Time
|
||||
|
||||
// Last time the condition transit from one status to another
|
||||
// +optional
|
||||
LastTransitionTime metav1.Time
|
||||
|
||||
// reason for the condition's last transition
|
||||
Reason string
|
||||
|
||||
// Human readable message indicating details about last transition.
|
||||
// +optinal
|
||||
Message string
|
||||
}
|
||||
|
||||
// ServicePolicyStatus defines the observed state of ServicePolicy
|
||||
type ServicePolicyStatus struct {
|
||||
// The latest available observations of an object's current state.
|
||||
// +optional
|
||||
Conditions []ServicePolicyCondition
|
||||
|
||||
// Represents time when the strategy was acknowledged by the controller.
|
||||
// It is represented in RFC3339 form and is in UTC.
|
||||
// +optional
|
||||
StartTime *metav1.Time
|
||||
|
||||
// Represents time when the strategy was completed.
|
||||
// It is represented in RFC3339 form and is in UTC.
|
||||
// +optional
|
||||
CompletionTime *metav1.Time
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ServicePolicy is the Schema for the servicepolicies API
|
||||
// +k8s:openapi-gen=true
|
||||
type ServicePolicy struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ServicePolicySpec `json:"spec,omitempty"`
|
||||
Status ServicePolicyStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ServicePolicyList contains a list of ServicePolicy
|
||||
type ServicePolicyList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []ServicePolicy `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&ServicePolicy{}, &ServicePolicyList{})
|
||||
}
|
||||
58
pkg/apis/servicemesh/v1alpha2/servicepolicy_types_test.go
Normal file
58
pkg/apis/servicemesh/v1alpha2/servicepolicy_types_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2019 The KubeSphere 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 v1alpha2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"golang.org/x/net/context"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func TestStorageServicePolicy(t *testing.T) {
|
||||
key := types.NamespacedName{
|
||||
Name: "foo",
|
||||
Namespace: "default",
|
||||
}
|
||||
created := &ServicePolicy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: "default",
|
||||
}}
|
||||
g := gomega.NewGomegaWithT(t)
|
||||
|
||||
// Test Create
|
||||
fetched := &ServicePolicy{}
|
||||
g.Expect(c.Create(context.TODO(), created)).NotTo(gomega.HaveOccurred())
|
||||
|
||||
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
|
||||
g.Expect(fetched).To(gomega.Equal(created))
|
||||
|
||||
// Test Updating the Labels
|
||||
updated := fetched.DeepCopy()
|
||||
updated.Labels = map[string]string{"hello": "world"}
|
||||
g.Expect(c.Update(context.TODO(), updated)).NotTo(gomega.HaveOccurred())
|
||||
|
||||
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
|
||||
g.Expect(fetched).To(gomega.Equal(updated))
|
||||
|
||||
// Test Delete
|
||||
g.Expect(c.Delete(context.TODO(), fetched)).NotTo(gomega.HaveOccurred())
|
||||
g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.HaveOccurred())
|
||||
}
|
||||
@@ -45,6 +45,16 @@ type StrategySpec struct {
|
||||
// Strategy type
|
||||
Type StrategyType `json:"type,omitempty"`
|
||||
|
||||
// Principal version, the one as reference version
|
||||
// label version value
|
||||
// +optional
|
||||
PrincipalVersion string `json:"principal,omitempty"`
|
||||
|
||||
// Governor version, the version takes control of all incoming traffic
|
||||
// label version value
|
||||
// +optional
|
||||
GovernorVersion string `json:"governor,omitempty"`
|
||||
|
||||
// Label selector for virtual services.
|
||||
// +optional
|
||||
Selector *metav1.LabelSelector `json:"selector,omitempty"`
|
||||
@@ -128,6 +138,9 @@ type StrategyCondition struct {
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Strategy is the Schema for the strategies API
|
||||
// +kubebuilder:printcolumn:name="Type",type="string",JSONPath=".spec.type",description="type of strategy"
|
||||
// +kubebuilder:printcolumn:name="Hosts",type="string",JSONPath=".spec.template.spec.hosts",description="destination hosts"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
|
||||
// +k8s:openapi-gen=true
|
||||
type Strategy struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -25,6 +25,156 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DestinationRuleSpecTemplate) DeepCopyInto(out *DestinationRuleSpecTemplate) {
|
||||
*out = *in
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DestinationRuleSpecTemplate.
|
||||
func (in *DestinationRuleSpecTemplate) DeepCopy() *DestinationRuleSpecTemplate {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DestinationRuleSpecTemplate)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServicePolicy) DeepCopyInto(out *ServicePolicy) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicy.
|
||||
func (in *ServicePolicy) DeepCopy() *ServicePolicy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServicePolicy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ServicePolicy) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServicePolicyCondition) DeepCopyInto(out *ServicePolicyCondition) {
|
||||
*out = *in
|
||||
in.LastProbeTime.DeepCopyInto(&out.LastProbeTime)
|
||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicyCondition.
|
||||
func (in *ServicePolicyCondition) DeepCopy() *ServicePolicyCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServicePolicyCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServicePolicyList) DeepCopyInto(out *ServicePolicyList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ServicePolicy, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicyList.
|
||||
func (in *ServicePolicyList) DeepCopy() *ServicePolicyList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServicePolicyList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ServicePolicyList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServicePolicySpec) DeepCopyInto(out *ServicePolicySpec) {
|
||||
*out = *in
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = new(v1.LabelSelector)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.Template.DeepCopyInto(&out.Template)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicySpec.
|
||||
func (in *ServicePolicySpec) DeepCopy() *ServicePolicySpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServicePolicySpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServicePolicyStatus) DeepCopyInto(out *ServicePolicyStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]ServicePolicyCondition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.StartTime != nil {
|
||||
in, out := &in.StartTime, &out.StartTime
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
if in.CompletionTime != nil {
|
||||
in, out := &in.CompletionTime, &out.CompletionTime
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicyStatus.
|
||||
func (in *ServicePolicyStatus) DeepCopy() *ServicePolicyStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServicePolicyStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Strategy) DeepCopyInto(out *Strategy) {
|
||||
*out = *in
|
||||
|
||||
216
pkg/apiserver/logging/logging.go
Normal file
216
pkg/apiserver/logging/logging.go
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 logging
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/golang/glog"
|
||||
"kubesphere.io/kubesphere/pkg/models/log"
|
||||
es "kubesphere.io/kubesphere/pkg/simple/client/elasticsearch"
|
||||
fb "kubesphere.io/kubesphere/pkg/simple/client/fluentbit"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func LoggingQueryCluster(request *restful.Request, response *restful.Response) {
|
||||
res := logQuery(log.QueryLevelCluster, request)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingQueryWorkspace(request *restful.Request, response *restful.Response) {
|
||||
res := logQuery(log.QueryLevelWorkspace, request)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingQueryNamespace(request *restful.Request, response *restful.Response) {
|
||||
res := logQuery(log.QueryLevelNamespace, request)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingQueryWorkload(request *restful.Request, response *restful.Response) {
|
||||
res := logQuery(log.QueryLevelWorkload, request)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingQueryPod(request *restful.Request, response *restful.Response) {
|
||||
res := logQuery(log.QueryLevelPod, request)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingQueryContainer(request *restful.Request, response *restful.Response) {
|
||||
res := logQuery(log.QueryLevelContainer, request)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingQueryFluentbitFilters(request *restful.Request, response *restful.Response) {
|
||||
res := log.FluentbitFiltersQuery()
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingUpdateFluentbitFilters(request *restful.Request, response *restful.Response) {
|
||||
|
||||
var res *log.FluentbitFiltersResult
|
||||
|
||||
filters := new([]log.FluentbitFilter)
|
||||
|
||||
err := request.ReadEntity(&filters)
|
||||
if err != nil {
|
||||
res = &log.FluentbitFiltersResult{Status: http.StatusBadRequest}
|
||||
} else {
|
||||
res = log.FluentbitFiltersUpdate(filters)
|
||||
}
|
||||
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingQueryFluentbitOutputs(request *restful.Request, response *restful.Response) {
|
||||
res := log.FluentbitOutputsQuery()
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingInsertFluentbitOutput(request *restful.Request, response *restful.Response) {
|
||||
|
||||
var output fb.OutputPlugin
|
||||
var res *log.FluentbitOutputsResult
|
||||
|
||||
err := request.ReadEntity(&output)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
res = &log.FluentbitOutputsResult{Status: http.StatusBadRequest}
|
||||
} else {
|
||||
res = log.FluentbitOutputInsert(output)
|
||||
}
|
||||
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingUpdateFluentbitOutput(request *restful.Request, response *restful.Response) {
|
||||
|
||||
var output fb.OutputPlugin
|
||||
|
||||
id := request.PathParameter("output")
|
||||
|
||||
err := request.ReadEntity(&output)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
res := &log.FluentbitOutputsResult{Status: http.StatusBadRequest}
|
||||
response.WriteAsJson(res)
|
||||
return
|
||||
}
|
||||
|
||||
res := log.FluentbitOutputUpdate(output, id)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func LoggingDeleteFluentbitOutput(request *restful.Request, response *restful.Response) {
|
||||
|
||||
var res *log.FluentbitOutputsResult
|
||||
|
||||
id := request.PathParameter("output")
|
||||
res = log.FluentbitOutputDelete(id)
|
||||
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func logQuery(level log.LogQueryLevel, request *restful.Request) *es.QueryResult {
|
||||
var param es.QueryParameters
|
||||
|
||||
param.Operation = request.QueryParameter("operation")
|
||||
|
||||
switch level {
|
||||
case log.QueryLevelCluster:
|
||||
{
|
||||
param.NamespaceFilled, param.Namespaces = log.QueryWorkspace(request.QueryParameter("workspaces"), request.QueryParameter("workspace_query"))
|
||||
param.NamespaceFilled, param.Namespaces = log.MatchNamespace(request.QueryParameter("namespaces"), param.NamespaceFilled, param.Namespaces)
|
||||
param.NamespaceQuery = request.QueryParameter("namespace_query")
|
||||
param.PodFilled, param.Pods = log.QueryWorkload(request.QueryParameter("workloads"), request.QueryParameter("workload_query"), param.Namespaces)
|
||||
param.PodFilled, param.Pods = log.MatchPod(request.QueryParameter("pods"), param.PodFilled, param.Pods)
|
||||
param.PodQuery = request.QueryParameter("pod_query")
|
||||
param.ContainerFilled, param.Containers = log.MatchContainer(request.QueryParameter("containers"))
|
||||
param.ContainerQuery = request.QueryParameter("container_query")
|
||||
}
|
||||
case log.QueryLevelWorkspace:
|
||||
{
|
||||
param.NamespaceFilled, param.Namespaces = log.QueryWorkspace(request.PathParameter("workspace"), "")
|
||||
param.NamespaceFilled, param.Namespaces = log.MatchNamespace(request.QueryParameter("namespaces"), param.NamespaceFilled, param.Namespaces)
|
||||
param.NamespaceQuery = request.QueryParameter("namespace_query")
|
||||
param.PodFilled, param.Pods = log.QueryWorkload(request.QueryParameter("workloads"), request.QueryParameter("workload_query"), param.Namespaces)
|
||||
param.PodFilled, param.Pods = log.MatchPod(request.QueryParameter("pods"), param.PodFilled, param.Pods)
|
||||
param.PodQuery = request.QueryParameter("pod_query")
|
||||
param.ContainerFilled, param.Containers = log.MatchContainer(request.QueryParameter("containers"))
|
||||
param.ContainerQuery = request.QueryParameter("container_query")
|
||||
}
|
||||
case log.QueryLevelNamespace:
|
||||
{
|
||||
param.NamespaceFilled, param.Namespaces = log.MatchNamespace(request.PathParameter("namespace"), false, nil)
|
||||
param.PodFilled, param.Pods = log.QueryWorkload(request.QueryParameter("workloads"), request.QueryParameter("workload_query"), param.Namespaces)
|
||||
param.PodFilled, param.Pods = log.MatchPod(request.QueryParameter("pods"), param.PodFilled, param.Pods)
|
||||
param.PodQuery = request.QueryParameter("pod_query")
|
||||
param.ContainerFilled, param.Containers = log.MatchContainer(request.QueryParameter("containers"))
|
||||
param.ContainerQuery = request.QueryParameter("container_query")
|
||||
}
|
||||
case log.QueryLevelWorkload:
|
||||
{
|
||||
param.NamespaceFilled, param.Namespaces = log.MatchNamespace(request.PathParameter("namespace"), false, nil)
|
||||
param.PodFilled, param.Pods = log.QueryWorkload(request.PathParameter("workload"), "", param.Namespaces)
|
||||
param.PodFilled, param.Pods = log.MatchPod(request.QueryParameter("pods"), param.PodFilled, param.Pods)
|
||||
param.PodQuery = request.QueryParameter("pod_query")
|
||||
param.ContainerFilled, param.Containers = log.MatchContainer(request.QueryParameter("containers"))
|
||||
param.ContainerQuery = request.QueryParameter("container_query")
|
||||
}
|
||||
case log.QueryLevelPod:
|
||||
{
|
||||
param.NamespaceFilled, param.Namespaces = log.MatchNamespace(request.PathParameter("namespace"), false, nil)
|
||||
param.PodFilled, param.Pods = log.MatchPod(request.PathParameter("pod"), false, nil)
|
||||
param.ContainerFilled, param.Containers = log.MatchContainer(request.QueryParameter("containers"))
|
||||
param.ContainerQuery = request.QueryParameter("container_query")
|
||||
}
|
||||
case log.QueryLevelContainer:
|
||||
{
|
||||
param.NamespaceFilled, param.Namespaces = log.MatchNamespace(request.PathParameter("namespace"), false, nil)
|
||||
param.PodFilled, param.Pods = log.MatchPod(request.PathParameter("pod"), false, nil)
|
||||
param.ContainerFilled, param.Containers = log.MatchContainer(request.PathParameter("container"))
|
||||
}
|
||||
}
|
||||
|
||||
if len(param.Namespaces) == 1 {
|
||||
param.Workspace = log.GetWorkspaceOfNamesapce(param.Namespaces[0])
|
||||
}
|
||||
|
||||
param.Interval = request.QueryParameter("interval")
|
||||
|
||||
param.LogQuery = request.QueryParameter("log_query")
|
||||
param.StartTime = request.QueryParameter("start_time")
|
||||
param.EndTime = request.QueryParameter("end_time")
|
||||
param.Sort = request.QueryParameter("sort")
|
||||
|
||||
var err error
|
||||
param.From, err = strconv.ParseInt(request.QueryParameter("from"), 10, 64)
|
||||
if err != nil {
|
||||
param.From = 0
|
||||
}
|
||||
param.Size, err = strconv.ParseInt(request.QueryParameter("size"), 10, 64)
|
||||
if err != nil {
|
||||
param.Size = 10
|
||||
}
|
||||
|
||||
glog.Infof("LogQuery with %v", param)
|
||||
|
||||
return es.Query(param)
|
||||
}
|
||||
@@ -20,11 +20,11 @@ package monitoring
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
prom "kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
)
|
||||
|
||||
func MonitorPod(request *restful.Request, response *restful.Response) {
|
||||
requestParams := prometheus.ParseMonitoringRequestParams(request)
|
||||
requestParams := prom.ParseMonitoringRequestParams(request)
|
||||
podName := requestParams.PodName
|
||||
metricName := requestParams.MetricsName
|
||||
if podName != "" {
|
||||
@@ -32,7 +32,8 @@ func MonitorPod(request *restful.Request, response *restful.Response) {
|
||||
queryType, params, nullRule := metrics.AssemblePodMetricRequestInfo(requestParams, metricName)
|
||||
var res *metrics.FormatedMetric
|
||||
if !nullRule {
|
||||
res = metrics.GetMetric(queryType, params, metricName)
|
||||
metricsStr := prom.SendMonitoringRequest(queryType, params)
|
||||
res = metrics.ReformatJson(metricsStr, metricName, map[string]string{"pod_name": ""})
|
||||
}
|
||||
response.WriteAsJson(res)
|
||||
|
||||
@@ -40,21 +41,20 @@ func MonitorPod(request *restful.Request, response *restful.Response) {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelPod)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
func MonitorContainer(request *restful.Request, response *restful.Response) {
|
||||
requestParams := prometheus.ParseMonitoringRequestParams(request)
|
||||
requestParams := prom.ParseMonitoringRequestParams(request)
|
||||
metricName := requestParams.MetricsName
|
||||
if requestParams.MetricsFilter != "" {
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelContainer)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelContainerName)
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
@@ -68,7 +68,7 @@ func MonitorContainer(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
func MonitorWorkload(request *restful.Request, response *restful.Response) {
|
||||
requestParams := prometheus.ParseMonitoringRequestParams(request)
|
||||
requestParams := prom.ParseMonitoringRequestParams(request)
|
||||
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkload)
|
||||
|
||||
@@ -80,10 +80,10 @@ func MonitorWorkload(request *restful.Request, response *restful.Response) {
|
||||
// sorting
|
||||
if wlKind == "" {
|
||||
|
||||
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkload)
|
||||
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
|
||||
} else {
|
||||
|
||||
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
|
||||
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
|
||||
}
|
||||
|
||||
// paging
|
||||
@@ -95,19 +95,18 @@ func MonitorWorkload(request *restful.Request, response *restful.Response) {
|
||||
|
||||
func MonitorAllWorkspaces(request *restful.Request, response *restful.Response) {
|
||||
|
||||
requestParams := prometheus.ParseMonitoringRequestParams(request)
|
||||
requestParams := prom.ParseMonitoringRequestParams(request)
|
||||
|
||||
tp := requestParams.Tp
|
||||
if tp == "_statistics" {
|
||||
if tp == "statistics" {
|
||||
// merge multiple metric: all-devops, all-roles, all-projects...this api is designed for admin
|
||||
res := metrics.MonitorAllWorkspacesStatistics()
|
||||
|
||||
response.WriteAsJson(res)
|
||||
|
||||
} else if tp == "rank" {
|
||||
rawMetrics := metrics.MonitorAllWorkspaces(requestParams)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkspace)
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
@@ -119,20 +118,19 @@ func MonitorAllWorkspaces(request *restful.Request, response *restful.Response)
|
||||
}
|
||||
|
||||
func MonitorOneWorkspace(request *restful.Request, response *restful.Response) {
|
||||
requestParams := prometheus.ParseMonitoringRequestParams(request)
|
||||
requestParams := prom.ParseMonitoringRequestParams(request)
|
||||
|
||||
tp := requestParams.Tp
|
||||
if tp == "rank" {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
|
||||
} else if tp == "_statistics" {
|
||||
} else if tp == "statistics" {
|
||||
wsName := requestParams.WsName
|
||||
|
||||
// merge multiple metric: devops, roles, projects...
|
||||
@@ -145,34 +143,35 @@ func MonitorOneWorkspace(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
func MonitorNamespace(request *restful.Request, response *restful.Response) {
|
||||
requestParams := prometheus.ParseMonitoringRequestParams(request)
|
||||
requestParams := prom.ParseMonitoringRequestParams(request)
|
||||
metricName := requestParams.MetricsName
|
||||
nsName := requestParams.NsName
|
||||
if nsName != "" {
|
||||
// single
|
||||
queryType, params := metrics.AssembleNamespaceMetricRequestInfo(requestParams, metricName)
|
||||
res := metrics.GetMetric(queryType, params, metricName)
|
||||
metricsStr := prom.SendMonitoringRequest(queryType, params)
|
||||
res := metrics.ReformatJson(metricsStr, metricName, map[string]string{"namespace": ""})
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNamespace)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
func MonitorCluster(request *restful.Request, response *restful.Response) {
|
||||
requestParams := prometheus.ParseMonitoringRequestParams(request)
|
||||
requestParams := prom.ParseMonitoringRequestParams(request)
|
||||
|
||||
metricName := requestParams.MetricsName
|
||||
if metricName != "" {
|
||||
// single
|
||||
queryType, params := metrics.AssembleClusterMetricRequestInfo(requestParams, metricName)
|
||||
res := metrics.GetMetric(queryType, params, metricName)
|
||||
metricsStr := prom.SendMonitoringRequest(queryType, params)
|
||||
res := metrics.ReformatJson(metricsStr, metricName, map[string]string{"cluster": "local"})
|
||||
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
@@ -183,15 +182,17 @@ func MonitorCluster(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
func MonitorNode(request *restful.Request, response *restful.Response) {
|
||||
requestParams := prometheus.ParseMonitoringRequestParams(request)
|
||||
requestParams := prom.ParseMonitoringRequestParams(request)
|
||||
|
||||
metricName := requestParams.MetricsName
|
||||
if metricName != "" {
|
||||
// single
|
||||
queryType, params := metrics.AssembleNodeMetricRequestInfo(requestParams, metricName)
|
||||
res := metrics.GetMetric(queryType, params, metricName)
|
||||
metricsStr := prom.SendMonitoringRequest(queryType, params)
|
||||
res := metrics.ReformatJson(metricsStr, metricName, map[string]string{"node": ""})
|
||||
nodeAddress := metrics.GetNodeAddressInfo()
|
||||
metrics.AddNodeAddressMetric(res, nodeAddress)
|
||||
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
// multiple
|
||||
@@ -203,18 +204,10 @@ func MonitorNode(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNode)
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
// k8s component(controller, scheduler, etcd) status
|
||||
func MonitorComponentStatus(request *restful.Request, response *restful.Response) {
|
||||
requestParams := prometheus.ParseMonitoringRequestParams(request)
|
||||
|
||||
status := metrics.MonitorComponentStatus(requestParams)
|
||||
response.WriteAsJson(status)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ApiRootPath = "/apis"
|
||||
ApiRootPath = "/kapis"
|
||||
)
|
||||
|
||||
// container holds all webservice of apiserver
|
||||
|
||||
@@ -8,22 +8,29 @@ import (
|
||||
|
||||
// Get app metrics
|
||||
func GetAppMetrics(request *restful.Request, response *restful.Response) {
|
||||
handlers.AppMetrics(response.ResponseWriter, request.Request)
|
||||
handlers.AppMetrics(request, response)
|
||||
}
|
||||
|
||||
// Get workload metrics
|
||||
func GetWorkloadMetrics(request *restful.Request, response *restful.Response) {
|
||||
handlers.WorkloadMetrics(response.ResponseWriter, request.Request)
|
||||
namespace := request.PathParameter("namespace")
|
||||
workload := request.PathParameter("workload")
|
||||
|
||||
if len(namespace) > 0 && len(workload) > 0 {
|
||||
request.Request.URL.RawQuery = fmt.Sprintf("%s&namespaces=%s&workload=%s", request.Request.URL.RawQuery, namespace, workload)
|
||||
}
|
||||
|
||||
handlers.WorkloadMetrics(request, response)
|
||||
}
|
||||
|
||||
// Get service metrics
|
||||
func GetServiceMetrics(request *restful.Request, response *restful.Response) {
|
||||
handlers.ServiceMetrics(response.ResponseWriter, request.Request)
|
||||
handlers.ServiceMetrics(request, response)
|
||||
}
|
||||
|
||||
// Get namespace metrics
|
||||
func GetNamespaceMetrics(request *restful.Request, response *restful.Response) {
|
||||
handlers.NamespaceMetrics(response.ResponseWriter, request.Request)
|
||||
handlers.NamespaceMetrics(request, response)
|
||||
}
|
||||
|
||||
// Get service graph for namespace
|
||||
@@ -34,10 +41,30 @@ func GetNamespaceGraph(request *restful.Request, response *restful.Response) {
|
||||
request.Request.URL.RawQuery = fmt.Sprintf("%s&namespaces=%s", request.Request.URL.RawQuery, namespace)
|
||||
}
|
||||
|
||||
handlers.GraphNamespaces(response.ResponseWriter, request.Request)
|
||||
handlers.GetNamespaceGraph(request, response)
|
||||
}
|
||||
|
||||
// Get service graph for namespaces
|
||||
func GetNamespacesGraph(request *restful.Request, response *restful.Response) {
|
||||
handlers.GraphNamespaces(response.ResponseWriter, request.Request)
|
||||
handlers.GraphNamespaces(request, response)
|
||||
}
|
||||
|
||||
// Get namespace health
|
||||
func GetNamespaceHealth(request *restful.Request, response *restful.Response) {
|
||||
handlers.NamespaceHealth(request, response)
|
||||
}
|
||||
|
||||
// Get workload health
|
||||
func GetWorkloadHealth(request *restful.Request, response *restful.Response) {
|
||||
handlers.WorkloadHealth(request, response)
|
||||
}
|
||||
|
||||
// Get app health
|
||||
func GetAppHealth(request *restful.Request, response *restful.Response) {
|
||||
handlers.AppHealth(request, response)
|
||||
}
|
||||
|
||||
// Get service health
|
||||
func GetServiceHealth(request *restful.Request, response *restful.Response) {
|
||||
handlers.ServiceHealth(request, response)
|
||||
}
|
||||
|
||||
98
pkg/client/clientset/versioned/clientset.go
Normal file
98
pkg/client/clientset/versioned/clientset.go
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package versioned
|
||||
|
||||
import (
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Discovery() discovery.DiscoveryInterface
|
||||
ServicemeshV1alpha2() servicemeshv1alpha2.ServicemeshV1alpha2Interface
|
||||
// Deprecated: please explicitly pick a version if possible.
|
||||
Servicemesh() servicemeshv1alpha2.ServicemeshV1alpha2Interface
|
||||
}
|
||||
|
||||
// Clientset contains the clients for groups. Each group has exactly one
|
||||
// version included in a Clientset.
|
||||
type Clientset struct {
|
||||
*discovery.DiscoveryClient
|
||||
servicemeshV1alpha2 *servicemeshv1alpha2.ServicemeshV1alpha2Client
|
||||
}
|
||||
|
||||
// ServicemeshV1alpha2 retrieves the ServicemeshV1alpha2Client
|
||||
func (c *Clientset) ServicemeshV1alpha2() servicemeshv1alpha2.ServicemeshV1alpha2Interface {
|
||||
return c.servicemeshV1alpha2
|
||||
}
|
||||
|
||||
// Deprecated: Servicemesh retrieves the default version of ServicemeshClient.
|
||||
// Please explicitly pick a version.
|
||||
func (c *Clientset) Servicemesh() servicemeshv1alpha2.ServicemeshV1alpha2Interface {
|
||||
return c.servicemeshV1alpha2
|
||||
}
|
||||
|
||||
// Discovery retrieves the DiscoveryClient
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.DiscoveryClient
|
||||
}
|
||||
|
||||
// NewForConfig creates a new Clientset for the given config.
|
||||
func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
configShallowCopy := *c
|
||||
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
|
||||
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
|
||||
}
|
||||
var cs Clientset
|
||||
var err error
|
||||
cs.servicemeshV1alpha2, err = servicemeshv1alpha2.NewForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cs, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new Clientset for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *Clientset {
|
||||
var cs Clientset
|
||||
cs.servicemeshV1alpha2 = servicemeshv1alpha2.NewForConfigOrDie(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
|
||||
return &cs
|
||||
}
|
||||
|
||||
// New creates a new Clientset for the given RESTClient.
|
||||
func New(c rest.Interface) *Clientset {
|
||||
var cs Clientset
|
||||
cs.servicemeshV1alpha2 = servicemeshv1alpha2.New(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
|
||||
return &cs
|
||||
}
|
||||
20
pkg/client/clientset/versioned/doc.go
Normal file
20
pkg/client/clientset/versioned/doc.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated clientset.
|
||||
package versioned
|
||||
82
pkg/client/clientset/versioned/fake/clientset_generated.go
Normal file
82
pkg/client/clientset/versioned/fake/clientset_generated.go
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
"k8s.io/client-go/testing"
|
||||
clientset "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/servicemesh/v1alpha2"
|
||||
fakeservicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/servicemesh/v1alpha2/fake"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
// It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
|
||||
// without applying any validations and/or defaults. It shouldn't be considered a replacement
|
||||
// for a real clientset and is mostly useful in simple unit tests.
|
||||
func NewSimpleClientset(objects ...runtime.Object) *Clientset {
|
||||
o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
|
||||
for _, obj := range objects {
|
||||
if err := o.Add(obj); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
cs := &Clientset{}
|
||||
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
|
||||
cs.AddReactor("*", "*", testing.ObjectReaction(o))
|
||||
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
|
||||
gvr := action.GetResource()
|
||||
ns := action.GetNamespace()
|
||||
watch, err := o.Watch(gvr, ns)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, watch, nil
|
||||
})
|
||||
|
||||
return cs
|
||||
}
|
||||
|
||||
// Clientset implements clientset.Interface. Meant to be embedded into a
|
||||
// struct to get a default implementation. This makes faking out just the method
|
||||
// you want to test easier.
|
||||
type Clientset struct {
|
||||
testing.Fake
|
||||
discovery *fakediscovery.FakeDiscovery
|
||||
}
|
||||
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
return c.discovery
|
||||
}
|
||||
|
||||
var _ clientset.Interface = &Clientset{}
|
||||
|
||||
// ServicemeshV1alpha2 retrieves the ServicemeshV1alpha2Client
|
||||
func (c *Clientset) ServicemeshV1alpha2() servicemeshv1alpha2.ServicemeshV1alpha2Interface {
|
||||
return &fakeservicemeshv1alpha2.FakeServicemeshV1alpha2{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// Servicemesh retrieves the ServicemeshV1alpha2Client
|
||||
func (c *Clientset) Servicemesh() servicemeshv1alpha2.ServicemeshV1alpha2Interface {
|
||||
return &fakeservicemeshv1alpha2.FakeServicemeshV1alpha2{Fake: &c.Fake}
|
||||
}
|
||||
20
pkg/client/clientset/versioned/fake/doc.go
Normal file
20
pkg/client/clientset/versioned/fake/doc.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated fake clientset.
|
||||
package fake
|
||||
56
pkg/client/clientset/versioned/fake/register.go
Normal file
56
pkg/client/clientset/versioned/fake/register.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var codecs = serializer.NewCodecFactory(scheme)
|
||||
var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
servicemeshv1alpha2.AddToScheme,
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
var AddToScheme = localSchemeBuilder.AddToScheme
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
|
||||
utilruntime.Must(AddToScheme(scheme))
|
||||
}
|
||||
20
pkg/client/clientset/versioned/scheme/doc.go
Normal file
20
pkg/client/clientset/versioned/scheme/doc.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package contains the scheme of the automatically generated clientset.
|
||||
package scheme
|
||||
56
pkg/client/clientset/versioned/scheme/register.go
Normal file
56
pkg/client/clientset/versioned/scheme/register.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package scheme
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
var Scheme = runtime.NewScheme()
|
||||
var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
var ParameterCodec = runtime.NewParameterCodec(Scheme)
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
servicemeshv1alpha2.AddToScheme,
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
var AddToScheme = localSchemeBuilder.AddToScheme
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
||||
utilruntime.Must(AddToScheme(Scheme))
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1alpha2
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// Package fake has the automatically generated clients.
|
||||
package fake
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
rest "k8s.io/client-go/rest"
|
||||
testing "k8s.io/client-go/testing"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
type FakeServicemeshV1alpha2 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeServicemeshV1alpha2) ServicePolicies(namespace string) v1alpha2.ServicePolicyInterface {
|
||||
return &FakeServicePolicies{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeServicemeshV1alpha2) Strategies(namespace string) v1alpha2.StrategyInterface {
|
||||
return &FakeStrategies{c, namespace}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeServicemeshV1alpha2) RESTClient() rest.Interface {
|
||||
var ret *rest.RESTClient
|
||||
return ret
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
// FakeServicePolicies implements ServicePolicyInterface
|
||||
type FakeServicePolicies struct {
|
||||
Fake *FakeServicemeshV1alpha2
|
||||
ns string
|
||||
}
|
||||
|
||||
var servicepoliciesResource = schema.GroupVersionResource{Group: "servicemesh.kubesphere.io", Version: "v1alpha2", Resource: "servicepolicies"}
|
||||
|
||||
var servicepoliciesKind = schema.GroupVersionKind{Group: "servicemesh.kubesphere.io", Version: "v1alpha2", Kind: "ServicePolicy"}
|
||||
|
||||
// Get takes name of the servicePolicy, and returns the corresponding servicePolicy object, and an error if there is any.
|
||||
func (c *FakeServicePolicies) Get(name string, options v1.GetOptions) (result *v1alpha2.ServicePolicy, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(servicepoliciesResource, c.ns, name), &v1alpha2.ServicePolicy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.ServicePolicy), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of ServicePolicies that match those selectors.
|
||||
func (c *FakeServicePolicies) List(opts v1.ListOptions) (result *v1alpha2.ServicePolicyList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(servicepoliciesResource, servicepoliciesKind, c.ns, opts), &v1alpha2.ServicePolicyList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha2.ServicePolicyList{ListMeta: obj.(*v1alpha2.ServicePolicyList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha2.ServicePolicyList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested servicePolicies.
|
||||
func (c *FakeServicePolicies) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(servicepoliciesResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a servicePolicy and creates it. Returns the server's representation of the servicePolicy, and an error, if there is any.
|
||||
func (c *FakeServicePolicies) Create(servicePolicy *v1alpha2.ServicePolicy) (result *v1alpha2.ServicePolicy, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(servicepoliciesResource, c.ns, servicePolicy), &v1alpha2.ServicePolicy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.ServicePolicy), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a servicePolicy and updates it. Returns the server's representation of the servicePolicy, and an error, if there is any.
|
||||
func (c *FakeServicePolicies) Update(servicePolicy *v1alpha2.ServicePolicy) (result *v1alpha2.ServicePolicy, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(servicepoliciesResource, c.ns, servicePolicy), &v1alpha2.ServicePolicy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.ServicePolicy), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeServicePolicies) UpdateStatus(servicePolicy *v1alpha2.ServicePolicy) (*v1alpha2.ServicePolicy, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(servicepoliciesResource, "status", c.ns, servicePolicy), &v1alpha2.ServicePolicy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.ServicePolicy), err
|
||||
}
|
||||
|
||||
// Delete takes name of the servicePolicy and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeServicePolicies) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(servicepoliciesResource, c.ns, name), &v1alpha2.ServicePolicy{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeServicePolicies) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(servicepoliciesResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha2.ServicePolicyList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched servicePolicy.
|
||||
func (c *FakeServicePolicies) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.ServicePolicy, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(servicepoliciesResource, c.ns, name, pt, data, subresources...), &v1alpha2.ServicePolicy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.ServicePolicy), err
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
// FakeStrategies implements StrategyInterface
|
||||
type FakeStrategies struct {
|
||||
Fake *FakeServicemeshV1alpha2
|
||||
ns string
|
||||
}
|
||||
|
||||
var strategiesResource = schema.GroupVersionResource{Group: "servicemesh.kubesphere.io", Version: "v1alpha2", Resource: "strategies"}
|
||||
|
||||
var strategiesKind = schema.GroupVersionKind{Group: "servicemesh.kubesphere.io", Version: "v1alpha2", Kind: "Strategy"}
|
||||
|
||||
// Get takes name of the strategy, and returns the corresponding strategy object, and an error if there is any.
|
||||
func (c *FakeStrategies) Get(name string, options v1.GetOptions) (result *v1alpha2.Strategy, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(strategiesResource, c.ns, name), &v1alpha2.Strategy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.Strategy), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Strategies that match those selectors.
|
||||
func (c *FakeStrategies) List(opts v1.ListOptions) (result *v1alpha2.StrategyList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(strategiesResource, strategiesKind, c.ns, opts), &v1alpha2.StrategyList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha2.StrategyList{ListMeta: obj.(*v1alpha2.StrategyList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha2.StrategyList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested strategies.
|
||||
func (c *FakeStrategies) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(strategiesResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a strategy and creates it. Returns the server's representation of the strategy, and an error, if there is any.
|
||||
func (c *FakeStrategies) Create(strategy *v1alpha2.Strategy) (result *v1alpha2.Strategy, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(strategiesResource, c.ns, strategy), &v1alpha2.Strategy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.Strategy), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a strategy and updates it. Returns the server's representation of the strategy, and an error, if there is any.
|
||||
func (c *FakeStrategies) Update(strategy *v1alpha2.Strategy) (result *v1alpha2.Strategy, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(strategiesResource, c.ns, strategy), &v1alpha2.Strategy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.Strategy), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeStrategies) UpdateStatus(strategy *v1alpha2.Strategy) (*v1alpha2.Strategy, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(strategiesResource, "status", c.ns, strategy), &v1alpha2.Strategy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.Strategy), err
|
||||
}
|
||||
|
||||
// Delete takes name of the strategy and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeStrategies) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(strategiesResource, c.ns, name), &v1alpha2.Strategy{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeStrategies) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(strategiesResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha2.StrategyList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched strategy.
|
||||
func (c *FakeStrategies) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.Strategy, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(strategiesResource, c.ns, name, pt, data, subresources...), &v1alpha2.Strategy{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha2.Strategy), err
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
type ServicePolicyExpansion interface{}
|
||||
|
||||
type StrategyExpansion interface{}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
rest "k8s.io/client-go/rest"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme"
|
||||
)
|
||||
|
||||
type ServicemeshV1alpha2Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
ServicePoliciesGetter
|
||||
StrategiesGetter
|
||||
}
|
||||
|
||||
// ServicemeshV1alpha2Client is used to interact with features provided by the servicemesh.kubesphere.io group.
|
||||
type ServicemeshV1alpha2Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *ServicemeshV1alpha2Client) ServicePolicies(namespace string) ServicePolicyInterface {
|
||||
return newServicePolicies(c, namespace)
|
||||
}
|
||||
|
||||
func (c *ServicemeshV1alpha2Client) Strategies(namespace string) StrategyInterface {
|
||||
return newStrategies(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new ServicemeshV1alpha2Client for the given config.
|
||||
func NewForConfig(c *rest.Config) (*ServicemeshV1alpha2Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ServicemeshV1alpha2Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new ServicemeshV1alpha2Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *ServicemeshV1alpha2Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new ServicemeshV1alpha2Client for the given RESTClient.
|
||||
func New(c rest.Interface) *ServicemeshV1alpha2Client {
|
||||
return &ServicemeshV1alpha2Client{c}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := v1alpha2.SchemeGroupVersion
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *ServicemeshV1alpha2Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme"
|
||||
)
|
||||
|
||||
// ServicePoliciesGetter has a method to return a ServicePolicyInterface.
|
||||
// A group's client should implement this interface.
|
||||
type ServicePoliciesGetter interface {
|
||||
ServicePolicies(namespace string) ServicePolicyInterface
|
||||
}
|
||||
|
||||
// ServicePolicyInterface has methods to work with ServicePolicy resources.
|
||||
type ServicePolicyInterface interface {
|
||||
Create(*v1alpha2.ServicePolicy) (*v1alpha2.ServicePolicy, error)
|
||||
Update(*v1alpha2.ServicePolicy) (*v1alpha2.ServicePolicy, error)
|
||||
UpdateStatus(*v1alpha2.ServicePolicy) (*v1alpha2.ServicePolicy, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha2.ServicePolicy, error)
|
||||
List(opts v1.ListOptions) (*v1alpha2.ServicePolicyList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.ServicePolicy, err error)
|
||||
ServicePolicyExpansion
|
||||
}
|
||||
|
||||
// servicePolicies implements ServicePolicyInterface
|
||||
type servicePolicies struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newServicePolicies returns a ServicePolicies
|
||||
func newServicePolicies(c *ServicemeshV1alpha2Client, namespace string) *servicePolicies {
|
||||
return &servicePolicies{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the servicePolicy, and returns the corresponding servicePolicy object, and an error if there is any.
|
||||
func (c *servicePolicies) Get(name string, options v1.GetOptions) (result *v1alpha2.ServicePolicy, err error) {
|
||||
result = &v1alpha2.ServicePolicy{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("servicepolicies").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of ServicePolicies that match those selectors.
|
||||
func (c *servicePolicies) List(opts v1.ListOptions) (result *v1alpha2.ServicePolicyList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1alpha2.ServicePolicyList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("servicepolicies").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested servicePolicies.
|
||||
func (c *servicePolicies) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("servicepolicies").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a servicePolicy and creates it. Returns the server's representation of the servicePolicy, and an error, if there is any.
|
||||
func (c *servicePolicies) Create(servicePolicy *v1alpha2.ServicePolicy) (result *v1alpha2.ServicePolicy, err error) {
|
||||
result = &v1alpha2.ServicePolicy{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("servicepolicies").
|
||||
Body(servicePolicy).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a servicePolicy and updates it. Returns the server's representation of the servicePolicy, and an error, if there is any.
|
||||
func (c *servicePolicies) Update(servicePolicy *v1alpha2.ServicePolicy) (result *v1alpha2.ServicePolicy, err error) {
|
||||
result = &v1alpha2.ServicePolicy{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("servicepolicies").
|
||||
Name(servicePolicy.Name).
|
||||
Body(servicePolicy).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *servicePolicies) UpdateStatus(servicePolicy *v1alpha2.ServicePolicy) (result *v1alpha2.ServicePolicy, err error) {
|
||||
result = &v1alpha2.ServicePolicy{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("servicepolicies").
|
||||
Name(servicePolicy.Name).
|
||||
SubResource("status").
|
||||
Body(servicePolicy).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the servicePolicy and deletes it. Returns an error if one occurs.
|
||||
func (c *servicePolicies) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("servicepolicies").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *servicePolicies) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("servicepolicies").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched servicePolicy.
|
||||
func (c *servicePolicies) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.ServicePolicy, err error) {
|
||||
result = &v1alpha2.ServicePolicy{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("servicepolicies").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme"
|
||||
)
|
||||
|
||||
// StrategiesGetter has a method to return a StrategyInterface.
|
||||
// A group's client should implement this interface.
|
||||
type StrategiesGetter interface {
|
||||
Strategies(namespace string) StrategyInterface
|
||||
}
|
||||
|
||||
// StrategyInterface has methods to work with Strategy resources.
|
||||
type StrategyInterface interface {
|
||||
Create(*v1alpha2.Strategy) (*v1alpha2.Strategy, error)
|
||||
Update(*v1alpha2.Strategy) (*v1alpha2.Strategy, error)
|
||||
UpdateStatus(*v1alpha2.Strategy) (*v1alpha2.Strategy, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha2.Strategy, error)
|
||||
List(opts v1.ListOptions) (*v1alpha2.StrategyList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.Strategy, err error)
|
||||
StrategyExpansion
|
||||
}
|
||||
|
||||
// strategies implements StrategyInterface
|
||||
type strategies struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newStrategies returns a Strategies
|
||||
func newStrategies(c *ServicemeshV1alpha2Client, namespace string) *strategies {
|
||||
return &strategies{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the strategy, and returns the corresponding strategy object, and an error if there is any.
|
||||
func (c *strategies) Get(name string, options v1.GetOptions) (result *v1alpha2.Strategy, err error) {
|
||||
result = &v1alpha2.Strategy{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("strategies").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Strategies that match those selectors.
|
||||
func (c *strategies) List(opts v1.ListOptions) (result *v1alpha2.StrategyList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1alpha2.StrategyList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("strategies").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested strategies.
|
||||
func (c *strategies) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("strategies").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a strategy and creates it. Returns the server's representation of the strategy, and an error, if there is any.
|
||||
func (c *strategies) Create(strategy *v1alpha2.Strategy) (result *v1alpha2.Strategy, err error) {
|
||||
result = &v1alpha2.Strategy{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("strategies").
|
||||
Body(strategy).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a strategy and updates it. Returns the server's representation of the strategy, and an error, if there is any.
|
||||
func (c *strategies) Update(strategy *v1alpha2.Strategy) (result *v1alpha2.Strategy, err error) {
|
||||
result = &v1alpha2.Strategy{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("strategies").
|
||||
Name(strategy.Name).
|
||||
Body(strategy).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *strategies) UpdateStatus(strategy *v1alpha2.Strategy) (result *v1alpha2.Strategy, err error) {
|
||||
result = &v1alpha2.Strategy{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("strategies").
|
||||
Name(strategy.Name).
|
||||
SubResource("status").
|
||||
Body(strategy).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the strategy and deletes it. Returns an error if one occurs.
|
||||
func (c *strategies) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("strategies").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *strategies) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("strategies").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched strategy.
|
||||
func (c *strategies) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.Strategy, err error) {
|
||||
result = &v1alpha2.Strategy{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("strategies").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
180
pkg/client/informers/externalversions/factory.go
Normal file
180
pkg/client/informers/externalversions/factory.go
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
time "time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||
internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces"
|
||||
servicemesh "kubesphere.io/kubesphere/pkg/client/informers/externalversions/servicemesh"
|
||||
)
|
||||
|
||||
// SharedInformerOption defines the functional option type for SharedInformerFactory.
|
||||
type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory
|
||||
|
||||
type sharedInformerFactory struct {
|
||||
client versioned.Interface
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
lock sync.Mutex
|
||||
defaultResync time.Duration
|
||||
customResync map[reflect.Type]time.Duration
|
||||
|
||||
informers map[reflect.Type]cache.SharedIndexInformer
|
||||
// startedInformers is used for tracking which informers have been started.
|
||||
// This allows Start() to be called multiple times safely.
|
||||
startedInformers map[reflect.Type]bool
|
||||
}
|
||||
|
||||
// WithCustomResyncConfig sets a custom resync period for the specified informer types.
|
||||
func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
for k, v := range resyncConfig {
|
||||
factory.customResync[reflect.TypeOf(k)] = v
|
||||
}
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory.
|
||||
func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
factory.tweakListOptions = tweakListOptions
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// WithNamespace limits the SharedInformerFactory to the specified namespace.
|
||||
func WithNamespace(namespace string) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
factory.namespace = namespace
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces.
|
||||
func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
|
||||
return NewSharedInformerFactoryWithOptions(client, defaultResync)
|
||||
}
|
||||
|
||||
// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
|
||||
// Listers obtained via this SharedInformerFactory will be subject to the same filters
|
||||
// as specified here.
|
||||
// Deprecated: Please use NewSharedInformerFactoryWithOptions instead
|
||||
func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory {
|
||||
return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions))
|
||||
}
|
||||
|
||||
// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options.
|
||||
func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory {
|
||||
factory := &sharedInformerFactory{
|
||||
client: client,
|
||||
namespace: v1.NamespaceAll,
|
||||
defaultResync: defaultResync,
|
||||
informers: make(map[reflect.Type]cache.SharedIndexInformer),
|
||||
startedInformers: make(map[reflect.Type]bool),
|
||||
customResync: make(map[reflect.Type]time.Duration),
|
||||
}
|
||||
|
||||
// Apply all options
|
||||
for _, opt := range options {
|
||||
factory = opt(factory)
|
||||
}
|
||||
|
||||
return factory
|
||||
}
|
||||
|
||||
// Start initializes all requested informers.
|
||||
func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
for informerType, informer := range f.informers {
|
||||
if !f.startedInformers[informerType] {
|
||||
go informer.Run(stopCh)
|
||||
f.startedInformers[informerType] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForCacheSync waits for all started informers' cache were synced.
|
||||
func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
|
||||
informers := func() map[reflect.Type]cache.SharedIndexInformer {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
informers := map[reflect.Type]cache.SharedIndexInformer{}
|
||||
for informerType, informer := range f.informers {
|
||||
if f.startedInformers[informerType] {
|
||||
informers[informerType] = informer
|
||||
}
|
||||
}
|
||||
return informers
|
||||
}()
|
||||
|
||||
res := map[reflect.Type]bool{}
|
||||
for informType, informer := range informers {
|
||||
res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// InternalInformerFor returns the SharedIndexInformer for obj using an internal
|
||||
// client.
|
||||
func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
informerType := reflect.TypeOf(obj)
|
||||
informer, exists := f.informers[informerType]
|
||||
if exists {
|
||||
return informer
|
||||
}
|
||||
|
||||
resyncPeriod, exists := f.customResync[informerType]
|
||||
if !exists {
|
||||
resyncPeriod = f.defaultResync
|
||||
}
|
||||
|
||||
informer = newFunc(f.client, resyncPeriod)
|
||||
f.informers[informerType] = informer
|
||||
|
||||
return informer
|
||||
}
|
||||
|
||||
// SharedInformerFactory provides shared informers for resources in all known
|
||||
// API group versions.
|
||||
type SharedInformerFactory interface {
|
||||
internalinterfaces.SharedInformerFactory
|
||||
ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
|
||||
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
|
||||
|
||||
Servicemesh() servicemesh.Interface
|
||||
}
|
||||
|
||||
func (f *sharedInformerFactory) Servicemesh() servicemesh.Interface {
|
||||
return servicemesh.New(f, f.namespace, f.tweakListOptions)
|
||||
}
|
||||
64
pkg/client/informers/externalversions/generic.go
Normal file
64
pkg/client/informers/externalversions/generic.go
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
// GenericInformer is type of SharedIndexInformer which will locate and delegate to other
|
||||
// sharedInformers based on type
|
||||
type GenericInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() cache.GenericLister
|
||||
}
|
||||
|
||||
type genericInformer struct {
|
||||
informer cache.SharedIndexInformer
|
||||
resource schema.GroupResource
|
||||
}
|
||||
|
||||
// Informer returns the SharedIndexInformer.
|
||||
func (f *genericInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.informer
|
||||
}
|
||||
|
||||
// Lister returns the GenericLister.
|
||||
func (f *genericInformer) Lister() cache.GenericLister {
|
||||
return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
|
||||
}
|
||||
|
||||
// ForResource gives generic access to a shared informer of the matching type
|
||||
// TODO extend this to unknown resources with a client pool
|
||||
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
|
||||
switch resource {
|
||||
// Group=servicemesh.kubesphere.io, Version=v1alpha2
|
||||
case v1alpha2.SchemeGroupVersion.WithResource("servicepolicies"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Servicemesh().V1alpha2().ServicePolicies().Informer()}, nil
|
||||
case v1alpha2.SchemeGroupVersion.WithResource("strategies"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Servicemesh().V1alpha2().Strategies().Informer()}, nil
|
||||
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no informer found for %v", resource)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package internalinterfaces
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
|
||||
type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
|
||||
|
||||
// SharedInformerFactory a small interface to allow for adding an informer without an import cycle
|
||||
type SharedInformerFactory interface {
|
||||
Start(stopCh <-chan struct{})
|
||||
InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
|
||||
}
|
||||
|
||||
// TweakListOptionsFunc is a function that transforms a v1.ListOptions.
|
||||
type TweakListOptionsFunc func(*v1.ListOptions)
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package servicemesh
|
||||
|
||||
import (
|
||||
internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/client/informers/externalversions/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
// Interface provides access to each of this group's versions.
|
||||
type Interface interface {
|
||||
// V1alpha2 provides access to shared informers for resources in V1alpha2.
|
||||
V1alpha2() v1alpha2.Interface
|
||||
}
|
||||
|
||||
type group struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// V1alpha2 returns a new v1alpha2.Interface.
|
||||
func (g *group) V1alpha2() v1alpha2.Interface {
|
||||
return v1alpha2.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// ServicePolicies returns a ServicePolicyInformer.
|
||||
ServicePolicies() ServicePolicyInformer
|
||||
// Strategies returns a StrategyInformer.
|
||||
Strategies() StrategyInformer
|
||||
}
|
||||
|
||||
type version struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// ServicePolicies returns a ServicePolicyInformer.
|
||||
func (v *version) ServicePolicies() ServicePolicyInformer {
|
||||
return &servicePolicyInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// Strategies returns a StrategyInformer.
|
||||
func (v *version) Strategies() StrategyInformer {
|
||||
return &strategyInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||
internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/client/listers/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
// ServicePolicyInformer provides access to a shared informer and lister for
|
||||
// ServicePolicies.
|
||||
type ServicePolicyInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha2.ServicePolicyLister
|
||||
}
|
||||
|
||||
type servicePolicyInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewServicePolicyInformer constructs a new informer for ServicePolicy type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewServicePolicyInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredServicePolicyInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredServicePolicyInformer constructs a new informer for ServicePolicy type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredServicePolicyInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.ServicemeshV1alpha2().ServicePolicies(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.ServicemeshV1alpha2().ServicePolicies(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&servicemeshv1alpha2.ServicePolicy{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *servicePolicyInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredServicePolicyInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *servicePolicyInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&servicemeshv1alpha2.ServicePolicy{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *servicePolicyInformer) Lister() v1alpha2.ServicePolicyLister {
|
||||
return v1alpha2.NewServicePolicyLister(f.Informer().GetIndexer())
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||
internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/client/listers/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
// StrategyInformer provides access to a shared informer and lister for
|
||||
// Strategies.
|
||||
type StrategyInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha2.StrategyLister
|
||||
}
|
||||
|
||||
type strategyInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewStrategyInformer constructs a new informer for Strategy type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewStrategyInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredStrategyInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredStrategyInformer constructs a new informer for Strategy type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredStrategyInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.ServicemeshV1alpha2().Strategies(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.ServicemeshV1alpha2().Strategies(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&servicemeshv1alpha2.Strategy{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *strategyInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredStrategyInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *strategyInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&servicemeshv1alpha2.Strategy{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *strategyInformer) Lister() v1alpha2.StrategyLister {
|
||||
return v1alpha2.NewStrategyLister(f.Informer().GetIndexer())
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
// ServicePolicyListerExpansion allows custom methods to be added to
|
||||
// ServicePolicyLister.
|
||||
type ServicePolicyListerExpansion interface{}
|
||||
|
||||
// ServicePolicyNamespaceListerExpansion allows custom methods to be added to
|
||||
// ServicePolicyNamespaceLister.
|
||||
type ServicePolicyNamespaceListerExpansion interface{}
|
||||
|
||||
// StrategyListerExpansion allows custom methods to be added to
|
||||
// StrategyLister.
|
||||
type StrategyListerExpansion interface{}
|
||||
|
||||
// StrategyNamespaceListerExpansion allows custom methods to be added to
|
||||
// StrategyNamespaceLister.
|
||||
type StrategyNamespaceListerExpansion interface{}
|
||||
94
pkg/client/listers/servicemesh/v1alpha2/servicepolicy.go
Normal file
94
pkg/client/listers/servicemesh/v1alpha2/servicepolicy.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
// ServicePolicyLister helps list ServicePolicies.
|
||||
type ServicePolicyLister interface {
|
||||
// List lists all ServicePolicies in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha2.ServicePolicy, err error)
|
||||
// ServicePolicies returns an object that can list and get ServicePolicies.
|
||||
ServicePolicies(namespace string) ServicePolicyNamespaceLister
|
||||
ServicePolicyListerExpansion
|
||||
}
|
||||
|
||||
// servicePolicyLister implements the ServicePolicyLister interface.
|
||||
type servicePolicyLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewServicePolicyLister returns a new ServicePolicyLister.
|
||||
func NewServicePolicyLister(indexer cache.Indexer) ServicePolicyLister {
|
||||
return &servicePolicyLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all ServicePolicies in the indexer.
|
||||
func (s *servicePolicyLister) List(selector labels.Selector) (ret []*v1alpha2.ServicePolicy, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha2.ServicePolicy))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// ServicePolicies returns an object that can list and get ServicePolicies.
|
||||
func (s *servicePolicyLister) ServicePolicies(namespace string) ServicePolicyNamespaceLister {
|
||||
return servicePolicyNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// ServicePolicyNamespaceLister helps list and get ServicePolicies.
|
||||
type ServicePolicyNamespaceLister interface {
|
||||
// List lists all ServicePolicies in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha2.ServicePolicy, err error)
|
||||
// Get retrieves the ServicePolicy from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha2.ServicePolicy, error)
|
||||
ServicePolicyNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// servicePolicyNamespaceLister implements the ServicePolicyNamespaceLister
|
||||
// interface.
|
||||
type servicePolicyNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all ServicePolicies in the indexer for a given namespace.
|
||||
func (s servicePolicyNamespaceLister) List(selector labels.Selector) (ret []*v1alpha2.ServicePolicy, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha2.ServicePolicy))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the ServicePolicy from the indexer for a given namespace and name.
|
||||
func (s servicePolicyNamespaceLister) Get(name string) (*v1alpha2.ServicePolicy, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha2.Resource("servicepolicy"), name)
|
||||
}
|
||||
return obj.(*v1alpha2.ServicePolicy), nil
|
||||
}
|
||||
94
pkg/client/listers/servicemesh/v1alpha2/strategy.go
Normal file
94
pkg/client/listers/servicemesh/v1alpha2/strategy.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
v1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
// StrategyLister helps list Strategies.
|
||||
type StrategyLister interface {
|
||||
// List lists all Strategies in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha2.Strategy, err error)
|
||||
// Strategies returns an object that can list and get Strategies.
|
||||
Strategies(namespace string) StrategyNamespaceLister
|
||||
StrategyListerExpansion
|
||||
}
|
||||
|
||||
// strategyLister implements the StrategyLister interface.
|
||||
type strategyLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewStrategyLister returns a new StrategyLister.
|
||||
func NewStrategyLister(indexer cache.Indexer) StrategyLister {
|
||||
return &strategyLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all Strategies in the indexer.
|
||||
func (s *strategyLister) List(selector labels.Selector) (ret []*v1alpha2.Strategy, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha2.Strategy))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Strategies returns an object that can list and get Strategies.
|
||||
func (s *strategyLister) Strategies(namespace string) StrategyNamespaceLister {
|
||||
return strategyNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// StrategyNamespaceLister helps list and get Strategies.
|
||||
type StrategyNamespaceLister interface {
|
||||
// List lists all Strategies in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha2.Strategy, err error)
|
||||
// Get retrieves the Strategy from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha2.Strategy, error)
|
||||
StrategyNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// strategyNamespaceLister implements the StrategyNamespaceLister
|
||||
// interface.
|
||||
type strategyNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all Strategies in the indexer for a given namespace.
|
||||
func (s strategyNamespaceLister) List(selector labels.Selector) (ret []*v1alpha2.Strategy, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha2.Strategy))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the Strategy from the indexer for a given namespace and name.
|
||||
func (s strategyNamespaceLister) Get(name string) (*v1alpha2.Strategy, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha2.Resource("strategy"), name)
|
||||
}
|
||||
return obj.(*v1alpha2.Strategy), nil
|
||||
}
|
||||
@@ -17,14 +17,14 @@ limitations under the License.
|
||||
package controller
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/controller/strategy"
|
||||
"sigs.k8s.io/application/pkg/controller/application"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
|
||||
AddToManagerFuncs = append(AddToManagerFuncs, strategy.Add)
|
||||
//AddToManagerFuncs = append(AddToManagerFuncs, strategy.Add)
|
||||
|
||||
// Add application to manager functions
|
||||
//AddToManagerFuncs = append(AddToManagerFuncs, application.Add)
|
||||
AddToManagerFuncs = append(AddToManagerFuncs, application.Add)
|
||||
|
||||
}
|
||||
|
||||
469
pkg/controller/destinationrule/destinationrule_controller.go
Normal file
469
pkg/controller/destinationrule/destinationrule_controller.go
Normal file
@@ -0,0 +1,469 @@
|
||||
package destinationrule
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/util/metrics"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/controller/virtualservice/util"
|
||||
"reflect"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
|
||||
istioclientset "github.com/knative/pkg/client/clientset/versioned"
|
||||
istioinformers "github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3"
|
||||
istiolisters "github.com/knative/pkg/client/listers/istio/v1alpha3"
|
||||
informersv1 "k8s.io/client-go/informers/apps/v1"
|
||||
coreinformers "k8s.io/client-go/informers/core/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
listersv1 "k8s.io/client-go/listers/apps/v1"
|
||||
corelisters "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"time"
|
||||
|
||||
servicemeshinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions/servicemesh/v1alpha2"
|
||||
servicemeshlisters "kubesphere.io/kubesphere/pkg/client/listers/servicemesh/v1alpha2"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxRetries is the number of times a service will be retried before it is dropped out of the queue.
|
||||
// With the current rate-limiter in use (5ms*2^(maxRetries-1)) the following numbers represent the
|
||||
// sequence of delays between successive queuings of a service.
|
||||
//
|
||||
// 5ms, 10ms, 20ms, 40ms, 80ms, 160ms, 320ms, 640ms, 1.3s, 2.6s, 5.1s, 10.2s, 20.4s, 41s, 82s
|
||||
maxRetries = 15
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("destinationrule-controller")
|
||||
|
||||
type DestinationRuleController struct {
|
||||
client clientset.Interface
|
||||
|
||||
destinationRuleClient istioclientset.Interface
|
||||
|
||||
eventBroadcaster record.EventBroadcaster
|
||||
eventRecorder record.EventRecorder
|
||||
|
||||
serviceLister corelisters.ServiceLister
|
||||
serviceSynced cache.InformerSynced
|
||||
|
||||
deploymentLister listersv1.DeploymentLister
|
||||
deploymentSynced cache.InformerSynced
|
||||
|
||||
servicePolicyLister servicemeshlisters.ServicePolicyLister
|
||||
servicePolicySynced cache.InformerSynced
|
||||
|
||||
destinationRuleLister istiolisters.DestinationRuleLister
|
||||
destinationRuleSynced cache.InformerSynced
|
||||
|
||||
queue workqueue.RateLimitingInterface
|
||||
|
||||
workerLoopPeriod time.Duration
|
||||
}
|
||||
|
||||
func NewDestinationRuleController(deploymentInformer informersv1.DeploymentInformer,
|
||||
destinationRuleInformer istioinformers.DestinationRuleInformer,
|
||||
serviceInformer coreinformers.ServiceInformer,
|
||||
servicePolicyInformer servicemeshinformers.ServicePolicyInformer,
|
||||
client clientset.Interface,
|
||||
destinationRuleClient istioclientset.Interface) *DestinationRuleController {
|
||||
|
||||
broadcaster := record.NewBroadcaster()
|
||||
broadcaster.StartLogging(func(format string, args ...interface{}) {
|
||||
log.Info(fmt.Sprintf(format, args))
|
||||
})
|
||||
broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: client.CoreV1().Events("")})
|
||||
recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "destinationrule-controller"})
|
||||
|
||||
if client != nil && client.CoreV1().RESTClient().GetRateLimiter() != nil {
|
||||
metrics.RegisterMetricAndTrackRateLimiterUsage("virtualservice_controller", client.CoreV1().RESTClient().GetRateLimiter())
|
||||
}
|
||||
|
||||
v := &DestinationRuleController{
|
||||
client: client,
|
||||
destinationRuleClient: destinationRuleClient,
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "destinationrule"),
|
||||
workerLoopPeriod: time.Second,
|
||||
}
|
||||
|
||||
v.deploymentLister = deploymentInformer.Lister()
|
||||
v.deploymentSynced = deploymentInformer.Informer().HasSynced
|
||||
|
||||
deploymentInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: v.addDeployment,
|
||||
DeleteFunc: v.deleteDeployment,
|
||||
UpdateFunc: func(old, cur interface{}) {
|
||||
v.addDeployment(cur)
|
||||
},
|
||||
})
|
||||
|
||||
v.serviceLister = serviceInformer.Lister()
|
||||
v.serviceSynced = serviceInformer.Informer().HasSynced
|
||||
|
||||
serviceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: v.enqueueService,
|
||||
DeleteFunc: v.enqueueService,
|
||||
UpdateFunc: func(old, cur interface{}) {
|
||||
v.enqueueService(cur)
|
||||
},
|
||||
})
|
||||
|
||||
v.destinationRuleLister = destinationRuleInformer.Lister()
|
||||
v.destinationRuleSynced = destinationRuleInformer.Informer().HasSynced
|
||||
|
||||
v.servicePolicyLister = servicePolicyInformer.Lister()
|
||||
v.servicePolicySynced = servicePolicyInformer.Informer().HasSynced
|
||||
|
||||
servicePolicyInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: v.addServicePolicy,
|
||||
UpdateFunc: func(old, cur interface{}) {
|
||||
v.addServicePolicy(cur)
|
||||
},
|
||||
DeleteFunc: v.addServicePolicy,
|
||||
})
|
||||
|
||||
v.eventBroadcaster = broadcaster
|
||||
v.eventRecorder = recorder
|
||||
|
||||
return v
|
||||
|
||||
}
|
||||
|
||||
func (v *DestinationRuleController) Start(stopCh <-chan struct{}) error {
|
||||
v.Run(5, stopCh)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *DestinationRuleController) Run(workers int, stopCh <-chan struct{}) {
|
||||
defer utilruntime.HandleCrash()
|
||||
defer v.queue.ShutDown()
|
||||
|
||||
log.Info("starting destinationrule controller")
|
||||
defer log.Info("shutting down destinationrule controller")
|
||||
|
||||
if !controller.WaitForCacheSync("destinationrule-controller", stopCh, v.serviceSynced, v.destinationRuleSynced, v.deploymentSynced, v.servicePolicySynced) {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < workers; i++ {
|
||||
go wait.Until(v.worker, v.workerLoopPeriod, stopCh)
|
||||
}
|
||||
|
||||
<-stopCh
|
||||
}
|
||||
|
||||
func (v *DestinationRuleController) enqueueService(obj interface{}) {
|
||||
key, err := controller.KeyFunc(obj)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("couldn't get key for object %+v: %v", obj, err))
|
||||
return
|
||||
}
|
||||
|
||||
v.queue.Add(key)
|
||||
}
|
||||
|
||||
func (v *DestinationRuleController) worker() {
|
||||
for v.processNextWorkItem() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (v *DestinationRuleController) processNextWorkItem() bool {
|
||||
eKey, quit := v.queue.Get()
|
||||
if quit {
|
||||
return false
|
||||
}
|
||||
|
||||
defer v.queue.Done(eKey)
|
||||
|
||||
err := v.syncService(eKey.(string))
|
||||
v.handleErr(err, eKey)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// main function of the reconcile for destinationrule
|
||||
// destinationrule's name is same with the service that created it
|
||||
func (v *DestinationRuleController) syncService(key string) error {
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
log.V(4).Info("Finished syncing service destinationrule.", "key", key, "duration", time.Since(startTime))
|
||||
}()
|
||||
|
||||
namespace, name, err := cache.SplitMetaNamespaceKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
service, err := v.serviceLister.Services(namespace).Get(name)
|
||||
if err != nil {
|
||||
// Delete the corresponding destinationrule, as the service has been deleted.
|
||||
err = v.destinationRuleClient.NetworkingV1alpha3().DestinationRules(namespace).Delete(name, nil)
|
||||
if !errors.IsNotFound(err) {
|
||||
log.Error(err, "delete destination rule failed", "namespace", namespace, "name", name)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(service.Labels) < len(util.ApplicationLabels) || !util.IsApplicationComponent(service.Labels) ||
|
||||
len(service.Spec.Ports) == 0 {
|
||||
// services don't have enough labels to create a virtualservice
|
||||
// or they don't have necessary labels
|
||||
// or they don't have any ports defined
|
||||
return nil
|
||||
}
|
||||
|
||||
appName := util.GetComponentName(&service.ObjectMeta)
|
||||
|
||||
// fetch all deployments that match with service selector
|
||||
deployments, err := v.deploymentLister.Deployments(namespace).List(labels.Set(service.Spec.Selector).AsSelectorPreValidated())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subsets := make([]v1alpha3.Subset, 0)
|
||||
for _, deployment := range deployments {
|
||||
|
||||
// not a valid deployment we required
|
||||
if !util.IsApplicationComponent(deployment.Labels) || !util.IsApplicationComponent(deployment.Spec.Selector.MatchLabels) {
|
||||
continue
|
||||
}
|
||||
|
||||
version := util.GetComponentVersion(&deployment.ObjectMeta)
|
||||
|
||||
if len(version) == 0 {
|
||||
log.V(4).Info("Deployment doesn't have a version label", "key", types.NamespacedName{Namespace: deployment.Namespace, Name: deployment.Name}.String())
|
||||
continue
|
||||
}
|
||||
|
||||
subset := v1alpha3.Subset{
|
||||
Name: util.NormalizeVersionName(version),
|
||||
Labels: map[string]string{
|
||||
util.VersionLabel: version,
|
||||
},
|
||||
}
|
||||
|
||||
subsets = append(subsets, subset)
|
||||
}
|
||||
|
||||
currentDestinationRule, err := v.destinationRuleLister.DestinationRules(namespace).Get(name)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
currentDestinationRule = &v1alpha3.DestinationRule{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: service.Name,
|
||||
Labels: service.Labels,
|
||||
},
|
||||
Spec: v1alpha3.DestinationRuleSpec{
|
||||
Host: name,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
log.Error(err, "Couldn't get destinationrule for service", "key", key)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// fetch all servicepolicies associated to this service
|
||||
servicePolicies, err := v.servicePolicyLister.ServicePolicies(namespace).List(labels.SelectorFromSet(map[string]string{util.AppLabel: appName}))
|
||||
if err != nil {
|
||||
log.Error(err, "could not list service policies is namespace with component name", "namespace", namespace, "name", appName)
|
||||
return err
|
||||
}
|
||||
|
||||
dr := currentDestinationRule.DeepCopy()
|
||||
dr.Spec.Subsets = subsets
|
||||
//
|
||||
if len(servicePolicies) > 0 {
|
||||
if len(servicePolicies) > 1 {
|
||||
err = fmt.Errorf("more than one service policy associated with service %s/%s is forbidden", namespace, name)
|
||||
log.Error(err, "")
|
||||
return err
|
||||
}
|
||||
|
||||
sp := servicePolicies[0]
|
||||
if sp.Spec.Template.Spec.TrafficPolicy != nil {
|
||||
dr.Spec.TrafficPolicy = sp.Spec.Template.Spec.TrafficPolicy
|
||||
}
|
||||
|
||||
for _, subset := range sp.Spec.Template.Spec.Subsets {
|
||||
for i := range dr.Spec.Subsets {
|
||||
if subset.Name == dr.Spec.Subsets[i].Name && subset.TrafficPolicy != nil {
|
||||
dr.Spec.Subsets[i].TrafficPolicy = subset.TrafficPolicy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createDestinationRule := len(currentDestinationRule.ResourceVersion) == 0
|
||||
|
||||
if !createDestinationRule && reflect.DeepEqual(currentDestinationRule.Spec, dr.Spec) &&
|
||||
reflect.DeepEqual(currentDestinationRule.Labels, service.Labels) {
|
||||
log.V(5).Info("destinationrule are equal, skipping update", "key", types.NamespacedName{Namespace: service.Namespace, Name: service.Name}.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
newDestinationRule := currentDestinationRule.DeepCopy()
|
||||
newDestinationRule.Spec = dr.Spec
|
||||
newDestinationRule.Labels = service.Labels
|
||||
if newDestinationRule.Annotations == nil {
|
||||
newDestinationRule.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
if createDestinationRule {
|
||||
_, err = v.destinationRuleClient.NetworkingV1alpha3().DestinationRules(namespace).Create(newDestinationRule)
|
||||
} else {
|
||||
_, err = v.destinationRuleClient.NetworkingV1alpha3().DestinationRules(namespace).Update(newDestinationRule)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if createDestinationRule && errors.IsForbidden(err) {
|
||||
// A request is forbidden primarily for two reasons:
|
||||
// 1. namespace is terminating, endpoint creation is not allowed by default.
|
||||
// 2. policy is misconfigured, in which case no service would function anywhere.
|
||||
// Given the frequency of 1, we log at a lower level.
|
||||
log.V(5).Info("Forbidden from creating endpoints", "error", err)
|
||||
}
|
||||
|
||||
if createDestinationRule {
|
||||
v.eventRecorder.Event(newDestinationRule, v1.EventTypeWarning, "FailedToCreateDestinationRule", fmt.Sprintf("Failed to create destinationrule for service %v/%v: %v", service.Namespace, service.Name, err))
|
||||
} else {
|
||||
v.eventRecorder.Event(newDestinationRule, v1.EventTypeWarning, "FailedToUpdateDestinationRule", fmt.Sprintf("Failed to update destinationrule for service %v/%v: %v", service.Namespace, service.Name, err))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// When a destinationrule is added, figure out which service it will be used
|
||||
// and enqueue it. obj must have *appsv1.Deployment type
|
||||
func (v *DestinationRuleController) addDeployment(obj interface{}) {
|
||||
deploy := obj.(*appsv1.Deployment)
|
||||
|
||||
// not a application component
|
||||
if !util.IsApplicationComponent(deploy.Labels) || !util.IsApplicationComponent(deploy.Spec.Selector.MatchLabels) {
|
||||
return
|
||||
}
|
||||
|
||||
services, err := v.getDeploymentServiceMemberShip(deploy)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("unable to get deployment %s/%s's service memberships", deploy.Namespace, deploy.Name))
|
||||
return
|
||||
}
|
||||
|
||||
for key := range services {
|
||||
v.queue.Add(key)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (v *DestinationRuleController) deleteDeployment(obj interface{}) {
|
||||
if _, ok := obj.(*appsv1.Deployment); ok {
|
||||
v.addDeployment(obj)
|
||||
return
|
||||
}
|
||||
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
utilruntime.HandleError(fmt.Errorf("couldn't get object from tombstone %#v", obj))
|
||||
return
|
||||
}
|
||||
|
||||
deploy, ok := tombstone.Obj.(*appsv1.Deployment)
|
||||
if !ok {
|
||||
utilruntime.HandleError(fmt.Errorf("tombstone contained object that is not a deployment %#v", obj))
|
||||
return
|
||||
}
|
||||
|
||||
v.addDeployment(deploy)
|
||||
}
|
||||
|
||||
func (v *DestinationRuleController) getDeploymentServiceMemberShip(deployment *appsv1.Deployment) (sets.String, error) {
|
||||
set := sets.String{}
|
||||
|
||||
allServices, err := v.serviceLister.Services(deployment.Namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return set, err
|
||||
}
|
||||
|
||||
for i := range allServices {
|
||||
service := allServices[i]
|
||||
if service.Spec.Selector == nil || !util.IsApplicationComponent(service.Labels) {
|
||||
// services with nil selectors match nothing, not everything.
|
||||
continue
|
||||
}
|
||||
selector := labels.Set(service.Spec.Selector).AsSelectorPreValidated()
|
||||
if selector.Matches(labels.Set(deployment.Spec.Selector.MatchLabels)) {
|
||||
key, err := controller.KeyFunc(service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
set.Insert(key)
|
||||
}
|
||||
}
|
||||
|
||||
return set, nil
|
||||
}
|
||||
|
||||
func (v *DestinationRuleController) addServicePolicy(obj interface{}) {
|
||||
servicePolicy := obj.(*servicemeshv1alpha2.ServicePolicy)
|
||||
|
||||
appName := servicePolicy.Labels[util.AppLabel]
|
||||
|
||||
services, err := v.serviceLister.Services(servicePolicy.Namespace).List(labels.SelectorFromSet(map[string]string{util.AppLabel: appName}))
|
||||
if err != nil {
|
||||
log.Error(err, "cannot list services", "namespace", servicePolicy.Namespace, "name", appName)
|
||||
utilruntime.HandleError(fmt.Errorf("cannot list services in namespace %s, with component name %v", servicePolicy.Namespace, appName))
|
||||
return
|
||||
}
|
||||
|
||||
set := sets.String{}
|
||||
for _, service := range services {
|
||||
key, err := controller.KeyFunc(service)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
continue
|
||||
}
|
||||
set.Insert(key)
|
||||
}
|
||||
|
||||
// avoid enqueue a key multiple times
|
||||
for key := range set {
|
||||
v.queue.Add(key)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *DestinationRuleController) handleErr(err error, key interface{}) {
|
||||
if err != nil {
|
||||
v.queue.Forget(key)
|
||||
return
|
||||
}
|
||||
|
||||
if v.queue.NumRequeues(key) < maxRetries {
|
||||
log.V(2).Info("Error syncing virtualservice for service, retrying.", "key", key, "error", err)
|
||||
v.queue.AddRateLimited(key)
|
||||
return
|
||||
}
|
||||
|
||||
log.V(4).Info("Dropping service out of the queue", "key", key, "error", err)
|
||||
v.queue.Forget(key)
|
||||
utilruntime.HandleError(err)
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package destinationrule
|
||||
|
||||
import (
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// TODO(jeff): add test cases
|
||||
|
||||
var namespace = "default"
|
||||
var lbs = map[string]string{
|
||||
"app.kubernetes.io/name": "bookinfo",
|
||||
"servicemesh.kubesphere.io/enabled": "",
|
||||
"app": "reviews",
|
||||
}
|
||||
|
||||
var service = corev1.Service{}
|
||||
|
||||
var deployments = []appsv1.Deployment{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: "deploy-v1",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/name": "bookinfo",
|
||||
"servicemesh.kubesphere.io/enabled": "",
|
||||
"app": "reviews",
|
||||
"version": "v1",
|
||||
},
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app.kubernetes.io/name": "bookinfo",
|
||||
"servicemesh.kubesphere.io/enabled": "",
|
||||
"app": "reviews",
|
||||
"version": "v1",
|
||||
},
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/name": "bookinfo",
|
||||
"servicemesh.kubesphere.io/enabled": "",
|
||||
"app": "reviews",
|
||||
"version": "v1",
|
||||
},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 The KubeSphere 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 strategy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller")
|
||||
|
||||
// Add creates a new Strategy Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager) error {
|
||||
return add(mgr, newReconciler(mgr))
|
||||
}
|
||||
|
||||
// newReconciler returns a new reconcile.Reconciler
|
||||
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
|
||||
return &ReconcileStrategy{Client: mgr.GetClient(), scheme: mgr.GetScheme()}
|
||||
}
|
||||
|
||||
// add adds a new Controller to mgr with r as the reconcile.Reconciler
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New("strategy-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for changes to Strategy
|
||||
err = c.Watch(&source.Kind{Type: &servicemeshv1alpha2.Strategy{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.Watch(&source.Kind{Type: &v1alpha3.VirtualService{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(user): Modify this to be the types you create
|
||||
// Watch a VirtualService created by Strategy
|
||||
err = c.Watch(&source.Kind{Type: &v1alpha3.VirtualService{}}, &handler.EnqueueRequestForOwner{
|
||||
IsController: true,
|
||||
OwnerType: &servicemeshv1alpha2.Strategy{},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ reconcile.Reconciler = &ReconcileStrategy{}
|
||||
|
||||
// ReconcileStrategy reconciles a Strategy object
|
||||
type ReconcileStrategy struct {
|
||||
client.Client
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a Strategy object and makes changes based on the state read
|
||||
// and what is in the Strategy.Spec
|
||||
// a Deployment as an example
|
||||
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
|
||||
// +kubebuilder:rbac:groups=networking.istio.io,resources=virtualservices,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=networking.istio.io,resources=virtualservices/status,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=servicemesh.kubesphere.io,resources=strategies,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=servicemesh.kubesphere.io,resources=strategies/status,verbs=get;update;patch
|
||||
func (r *ReconcileStrategy) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
// Fetch the Strategy instance
|
||||
strategy := &servicemeshv1alpha2.Strategy{}
|
||||
err := r.Get(context.TODO(), request.NamespacedName, strategy)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
// Object not found, return. Created objects are automatically garbage collected.
|
||||
// For additional cleanup logic use finalizers.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Define VirtualService to be created
|
||||
vs := &v1alpha3.VirtualService{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: strategy.Name + "-virtualservice",
|
||||
Namespace: strategy.Namespace,
|
||||
Labels: strategy.Spec.Selector.MatchLabels,
|
||||
},
|
||||
Spec: strategy.Spec.Template.Spec,
|
||||
}
|
||||
|
||||
if err := controllerutil.SetControllerReference(strategy, vs, r.scheme); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Check if the VirtualService already exists
|
||||
found := &v1alpha3.VirtualService{}
|
||||
err = r.Get(context.TODO(), types.NamespacedName{Name: vs.Name, Namespace: vs.Namespace}, found)
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
log.Info("Creating VirtualService", "namespace", vs.Namespace, "name", vs.Name)
|
||||
err = r.Create(context.TODO(), vs)
|
||||
return reconcile.Result{}, err
|
||||
} else if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Update the found object and write the result back if there are any changes
|
||||
if !reflect.DeepEqual(vs.Spec, found.Spec) {
|
||||
found.Spec = vs.Spec
|
||||
log.Info("Updating VirtualService", "namespace", vs.Namespace, "name", vs.Name)
|
||||
err = r.Update(context.TODO(), found)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 The KubeSphere 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 strategy
|
||||
|
||||
import (
|
||||
stdlog "log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"kubesphere.io/kubesphere/pkg/apis"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
t := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")},
|
||||
}
|
||||
apis.AddToScheme(scheme.Scheme)
|
||||
|
||||
var err error
|
||||
if cfg, err = t.Start(); err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
t.Stop()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
|
||||
// writes the request to requests after Reconcile is finished.
|
||||
func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
|
||||
requests := make(chan reconcile.Request)
|
||||
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
|
||||
result, err := inner.Reconcile(req)
|
||||
requests <- req
|
||||
return result, err
|
||||
})
|
||||
return fn, requests
|
||||
}
|
||||
|
||||
// StartTestManager adds recFn
|
||||
func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) {
|
||||
stop := make(chan struct{})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred())
|
||||
}()
|
||||
return stop, wg
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 The KubeSphere 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 strategy
|
||||
|
||||
import (
|
||||
"github.com/knative/pkg/apis/istio/common/v1alpha1"
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"golang.org/x/net/context"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var c client.Client
|
||||
|
||||
var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo", Namespace: "default"}}
|
||||
var depKey = types.NamespacedName{Name: "foo-virtualservice", Namespace: "default"}
|
||||
|
||||
const timeout = time.Second * 5
|
||||
|
||||
func TestReconcile(t *testing.T) {
|
||||
g := gomega.NewGomegaWithT(t)
|
||||
instance := &servicemeshv1alpha2.Strategy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: servicemeshv1alpha2.StrategySpec{
|
||||
Type: servicemeshv1alpha2.CanaryType,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"type": "Canary",
|
||||
},
|
||||
},
|
||||
Template: servicemeshv1alpha2.VirtualServiceTemplateSpec{
|
||||
Spec: v1alpha3.VirtualServiceSpec{
|
||||
Hosts: []string{"details"},
|
||||
Gateways: []string{"default"},
|
||||
Http: []v1alpha3.HTTPRoute{
|
||||
{
|
||||
Match: []v1alpha3.HTTPMatchRequest{
|
||||
{
|
||||
Method: &v1alpha1.StringMatch{
|
||||
Exact: "POST",
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: []v1alpha3.DestinationWeight{
|
||||
{
|
||||
Destination: v1alpha3.Destination{
|
||||
Host: "details",
|
||||
Subset: "v1",
|
||||
},
|
||||
Weight: 60,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Route: []v1alpha3.DestinationWeight{
|
||||
{
|
||||
Destination: v1alpha3.Destination{
|
||||
Host: "details",
|
||||
Subset: "v2",
|
||||
},
|
||||
Weight: 40,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a
|
||||
// channel when it is finished.
|
||||
mgr, err := manager.New(cfg, manager.Options{})
|
||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
c = mgr.GetClient()
|
||||
|
||||
recFn, requests := SetupTestReconcile(newReconciler(mgr))
|
||||
g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred())
|
||||
|
||||
stopMgr, mgrStopped := StartTestManager(mgr, g)
|
||||
|
||||
defer func() {
|
||||
close(stopMgr)
|
||||
mgrStopped.Wait()
|
||||
}()
|
||||
|
||||
// Create the Strategy object and expect the Reconcile and Deployment to be created
|
||||
err = c.Create(context.TODO(), instance)
|
||||
// The instance object may not be a valid object because it might be missing some required fields.
|
||||
// Please modify the instance object by adding required fields and then remove the following if statement.
|
||||
if apierrors.IsInvalid(err) {
|
||||
t.Logf("failed to create object, got an invalid object error: %v", err)
|
||||
return
|
||||
}
|
||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
defer c.Delete(context.TODO(), instance)
|
||||
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
|
||||
|
||||
vs := &v1alpha3.VirtualService{}
|
||||
g.Eventually(func() error { return c.Get(context.TODO(), depKey, vs) }, timeout).
|
||||
Should(gomega.Succeed())
|
||||
|
||||
if str, err := json.Marshal(vs); err == nil {
|
||||
t.Logf("Created virtual service %s\n", str)
|
||||
}
|
||||
|
||||
// Delete the Deployment and expect Reconcile to be called for Deployment deletion
|
||||
g.Expect(c.Delete(context.TODO(), vs)).NotTo(gomega.HaveOccurred())
|
||||
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
|
||||
//g.Eventually(func() error { return c.Get(context.TODO(), depKey, vs) }, timeout).Should(gomega.Succeed())
|
||||
|
||||
// Manually delete Deployment since GC isn't enabled in the test control plane
|
||||
g.Eventually(func() error { return c.Delete(context.TODO(), vs) }, timeout).
|
||||
Should(gomega.MatchError("virtualservices.networking.istio.io \"foo-virtualservice\" not found"))
|
||||
|
||||
}
|
||||
98
pkg/controller/virtualservice/util/util.go
Normal file
98
pkg/controller/virtualservice/util/util.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
AppLabel = "app"
|
||||
VersionLabel = "version"
|
||||
ApplicationNameLabel = "app.kubernetes.io/name"
|
||||
ApplicationVersionLabel = "app.kubernetes.io/version"
|
||||
ServiceMeshEnabledLabel = "servicemesh.kubesphere.io/enabled"
|
||||
)
|
||||
|
||||
// resource with these following labels considered as part of servicemesh
|
||||
var ApplicationLabels = [...]string{
|
||||
ApplicationNameLabel,
|
||||
ServiceMeshEnabledLabel,
|
||||
AppLabel,
|
||||
}
|
||||
|
||||
var TrimChars = [...]string{".", "_", "-"}
|
||||
|
||||
// normalize version names
|
||||
// strip [_.-]
|
||||
func NormalizeVersionName(version string) string {
|
||||
for _, char := range TrimChars {
|
||||
version = strings.ReplaceAll(version, char, "")
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
||||
func GetComponentName(meta *metav1.ObjectMeta) string {
|
||||
if len(meta.Labels[AppLabel]) > 0 {
|
||||
return meta.Labels[AppLabel]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetComponentVersion(meta *metav1.ObjectMeta) string {
|
||||
if len(meta.Labels[VersionLabel]) > 0 {
|
||||
return meta.Labels[VersionLabel]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func ExtractApplicationLabels(meta *metav1.ObjectMeta) map[string]string {
|
||||
|
||||
labels := make(map[string]string, len(ApplicationLabels))
|
||||
for _, label := range ApplicationLabels {
|
||||
if _, ok := meta.Labels[label]; !ok {
|
||||
return nil
|
||||
} else {
|
||||
labels[label] = meta.Labels[label]
|
||||
}
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
func IsApplicationComponent(lbs map[string]string) bool {
|
||||
|
||||
for _, label := range ApplicationLabels {
|
||||
if _, ok := lbs[label]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// if virtualservice not specified with port number, then fill with service first port
|
||||
func FillDestinationPort(vs *v1alpha3.VirtualService, service *v1.Service) {
|
||||
// fill http port
|
||||
for i := range vs.Spec.Http {
|
||||
for j := range vs.Spec.Http[i].Route {
|
||||
if vs.Spec.Http[i].Route[j].Destination.Port.Number == 0 {
|
||||
vs.Spec.Http[i].Route[j].Destination.Port.Number = uint32(service.Spec.Ports[0].Port)
|
||||
}
|
||||
}
|
||||
|
||||
if vs.Spec.Http[i].Mirror != nil && vs.Spec.Http[i].Mirror.Port.Number == 0 {
|
||||
vs.Spec.Http[i].Mirror.Port.Number = uint32(service.Spec.Ports[0].Port)
|
||||
}
|
||||
}
|
||||
|
||||
// fill tcp port
|
||||
for i := range vs.Spec.Tcp {
|
||||
for j := range vs.Spec.Tcp[i].Route {
|
||||
if vs.Spec.Tcp[i].Route[j].Destination.Port.Number == 0 {
|
||||
vs.Spec.Tcp[i].Route[j].Destination.Port.Number = uint32(service.Spec.Ports[0].Port)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
501
pkg/controller/virtualservice/virtualservice_controller.go
Normal file
501
pkg/controller/virtualservice/virtualservice_controller.go
Normal file
@@ -0,0 +1,501 @@
|
||||
package virtualservice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/util/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/controller/virtualservice/util"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
|
||||
istioclient "github.com/knative/pkg/client/clientset/versioned"
|
||||
istioinformers "github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3"
|
||||
istiolisters "github.com/knative/pkg/client/listers/istio/v1alpha3"
|
||||
coreinformers "k8s.io/client-go/informers/core/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
corelisters "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
servicemeshinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions/servicemesh/v1alpha2"
|
||||
servicemeshlisters "kubesphere.io/kubesphere/pkg/client/listers/servicemesh/v1alpha2"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxRetries is the number of times a service will be retried before it is dropped out of the queue.
|
||||
// With the current rate-limiter in use (5ms*2^(maxRetries-1)) the following numbers represent the
|
||||
// sequence of delays between successive queuings of a service.
|
||||
//
|
||||
// 5ms, 10ms, 20ms, 40ms, 80ms, 160ms, 320ms, 640ms, 1.3s, 2.6s, 5.1s, 10.2s, 20.4s, 41s, 82s
|
||||
maxRetries = 15
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("virtualservice-controller")
|
||||
|
||||
type VirtualServiceController struct {
|
||||
client clientset.Interface
|
||||
|
||||
virtualServiceClient istioclient.Interface
|
||||
|
||||
eventBroadcaster record.EventBroadcaster
|
||||
eventRecorder record.EventRecorder
|
||||
|
||||
serviceLister corelisters.ServiceLister
|
||||
serviceSynced cache.InformerSynced
|
||||
|
||||
virtualServiceLister istiolisters.VirtualServiceLister
|
||||
virtualServiceSynced cache.InformerSynced
|
||||
|
||||
destinationRuleLister istiolisters.DestinationRuleLister
|
||||
destinationRuleSynced cache.InformerSynced
|
||||
|
||||
strategyLister servicemeshlisters.StrategyLister
|
||||
strategySynced cache.InformerSynced
|
||||
|
||||
queue workqueue.RateLimitingInterface
|
||||
|
||||
workerLoopPeriod time.Duration
|
||||
}
|
||||
|
||||
func NewVirtualServiceController(serviceInformer coreinformers.ServiceInformer,
|
||||
virtualServiceInformer istioinformers.VirtualServiceInformer,
|
||||
destinationRuleInformer istioinformers.DestinationRuleInformer,
|
||||
strategyInformer servicemeshinformers.StrategyInformer,
|
||||
client clientset.Interface,
|
||||
virtualServiceClient istioclient.Interface) *VirtualServiceController {
|
||||
|
||||
broadcaster := record.NewBroadcaster()
|
||||
broadcaster.StartLogging(func(format string, args ...interface{}) {
|
||||
log.Info(fmt.Sprintf(format, args))
|
||||
})
|
||||
broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: client.CoreV1().Events("")})
|
||||
recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "virtualservice-controller"})
|
||||
|
||||
if client != nil && client.CoreV1().RESTClient().GetRateLimiter() != nil {
|
||||
metrics.RegisterMetricAndTrackRateLimiterUsage("virtualservice_controller", client.CoreV1().RESTClient().GetRateLimiter())
|
||||
}
|
||||
|
||||
v := &VirtualServiceController{
|
||||
client: client,
|
||||
virtualServiceClient: virtualServiceClient,
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "virtualservice"),
|
||||
workerLoopPeriod: time.Second,
|
||||
}
|
||||
|
||||
serviceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: v.enqueueService,
|
||||
DeleteFunc: v.enqueueService,
|
||||
UpdateFunc: func(old, cur interface{}) {
|
||||
// TODO(jeff): need a more robust mechanism, because user may change labels
|
||||
v.enqueueService(cur)
|
||||
},
|
||||
})
|
||||
|
||||
v.serviceLister = serviceInformer.Lister()
|
||||
v.serviceSynced = serviceInformer.Informer().HasSynced
|
||||
|
||||
v.strategyLister = strategyInformer.Lister()
|
||||
v.strategySynced = strategyInformer.Informer().HasSynced
|
||||
|
||||
strategyInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
DeleteFunc: v.addStrategy,
|
||||
AddFunc: v.addStrategy,
|
||||
UpdateFunc: func(old, cur interface{}) {
|
||||
v.addStrategy(cur)
|
||||
},
|
||||
})
|
||||
|
||||
v.destinationRuleLister = destinationRuleInformer.Lister()
|
||||
v.destinationRuleSynced = destinationRuleInformer.Informer().HasSynced
|
||||
|
||||
destinationRuleInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: v.addDestinationRule,
|
||||
UpdateFunc: func(old, cur interface{}) {
|
||||
v.addDestinationRule(cur)
|
||||
},
|
||||
})
|
||||
|
||||
v.virtualServiceLister = virtualServiceInformer.Lister()
|
||||
v.virtualServiceSynced = virtualServiceInformer.Informer().HasSynced
|
||||
|
||||
v.eventBroadcaster = broadcaster
|
||||
v.eventRecorder = recorder
|
||||
|
||||
return v
|
||||
|
||||
}
|
||||
|
||||
func (v *VirtualServiceController) Start(stopCh <-chan struct{}) error {
|
||||
v.Run(5, stopCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *VirtualServiceController) Run(workers int, stopCh <-chan struct{}) {
|
||||
defer utilruntime.HandleCrash()
|
||||
defer v.queue.ShutDown()
|
||||
|
||||
log.Info("starting virtualservice controller")
|
||||
defer log.Info("shutting down virtualservice controller")
|
||||
|
||||
if !controller.WaitForCacheSync("virtualservice-controller", stopCh, v.serviceSynced, v.virtualServiceSynced, v.destinationRuleSynced, v.strategySynced) {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < workers; i++ {
|
||||
go wait.Until(v.worker, v.workerLoopPeriod, stopCh)
|
||||
}
|
||||
|
||||
<-stopCh
|
||||
}
|
||||
|
||||
func (v *VirtualServiceController) enqueueService(obj interface{}) {
|
||||
key, err := controller.KeyFunc(obj)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("couldn't get key for object %+v: %v", obj, err))
|
||||
return
|
||||
}
|
||||
|
||||
v.queue.Add(key)
|
||||
}
|
||||
|
||||
func (v *VirtualServiceController) worker() {
|
||||
|
||||
for v.processNextWorkItem() {
|
||||
}
|
||||
}
|
||||
|
||||
func (v *VirtualServiceController) processNextWorkItem() bool {
|
||||
eKey, quit := v.queue.Get()
|
||||
if quit {
|
||||
return false
|
||||
}
|
||||
|
||||
defer v.queue.Done(eKey)
|
||||
|
||||
err := v.syncService(eKey.(string))
|
||||
v.handleErr(err, eKey)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// created virtualservice's name are same as the service name, same
|
||||
// as the destinationrule name
|
||||
// labels:
|
||||
// servicemesh.kubernetes.io/enabled: ""
|
||||
// app.kubernetes.io/name: bookinfo
|
||||
// app: reviews
|
||||
// are used to bind them together.
|
||||
// syncService are the main part of reconcile function body, it takes
|
||||
// service, destinationrule, strategy as input to create a virtualservice
|
||||
// for service.
|
||||
func (v *VirtualServiceController) syncService(key string) error {
|
||||
startTime := time.Now()
|
||||
namespace, name, err := cache.SplitMetaNamespaceKey(key)
|
||||
if err != nil {
|
||||
log.Error(err, "not a valid controller key", "key", key)
|
||||
return err
|
||||
}
|
||||
|
||||
// default component name to service name
|
||||
appName := name
|
||||
|
||||
defer func() {
|
||||
log.V(4).Info("Finished syncing service virtualservice.", "namespace", namespace, "name", name, "duration", time.Since(startTime))
|
||||
}()
|
||||
|
||||
service, err := v.serviceLister.Services(namespace).Get(name)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
// Delete the corresponding virtualservice, as the service has been deleted.
|
||||
err = v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Delete(name, nil)
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
log.Error(err, "delete orphan virtualservice failed", "namespace", namespace, "name", service.Name)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
log.Error(err, "get service failed", "namespace", namespace, "name", name)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(service.Labels) < len(util.ApplicationLabels) || !util.IsApplicationComponent(service.Labels) ||
|
||||
len(service.Spec.Ports) == 0 {
|
||||
// services don't have enough labels to create a virtualservice
|
||||
// or they don't have necessary labels
|
||||
// or they don't have any ports defined
|
||||
return nil
|
||||
}
|
||||
// get real component name, i.e label app value
|
||||
appName = util.GetComponentName(&service.ObjectMeta)
|
||||
|
||||
destinationRule, err := v.destinationRuleLister.DestinationRules(namespace).Get(name)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
// there is no destinationrule for this service
|
||||
// maybe corresponding workloads are not created yet
|
||||
log.Info("destination rules for service not found, retrying.", "namespace", namespace, "name", name)
|
||||
return fmt.Errorf("destination rule for service %s/%s not found", namespace, name)
|
||||
}
|
||||
log.Error(err, "Couldn't get destinationrule for service.", "service", types.NamespacedName{Name: service.Name, Namespace: service.Namespace}.String())
|
||||
return err
|
||||
}
|
||||
|
||||
subsets := destinationRule.Spec.Subsets
|
||||
if len(subsets) == 0 {
|
||||
// destination rule with no subsets, not possibly
|
||||
err = fmt.Errorf("found destinationrule with no subsets for service %s", name)
|
||||
log.Error(err, "found destinationrule with no subsets", "namespace", namespace, "name", appName)
|
||||
return err
|
||||
}
|
||||
|
||||
// fetch all strategies applied to service
|
||||
strategies, err := v.strategyLister.Strategies(namespace).List(labels.SelectorFromSet(map[string]string{util.AppLabel: appName}))
|
||||
if err != nil {
|
||||
log.Error(err, "list strategies for service failed", "namespace", namespace, "name", appName)
|
||||
return err
|
||||
} else if len(strategies) > 1 {
|
||||
// more than one strategies are not allowed, it will cause collision
|
||||
err = fmt.Errorf("more than one strategies applied to service %s/%s is forbbiden", namespace, appName)
|
||||
log.Error(err, "")
|
||||
return err
|
||||
}
|
||||
|
||||
// get current virtual service
|
||||
currentVirtualService, err := v.virtualServiceLister.VirtualServices(namespace).Get(appName)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
currentVirtualService = &v1alpha3.VirtualService{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: appName,
|
||||
Namespace: namespace,
|
||||
Labels: util.ExtractApplicationLabels(&service.ObjectMeta),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
log.Error(err, "cannot get virtualservice ", "namespace", namespace, "name", appName)
|
||||
return err
|
||||
}
|
||||
}
|
||||
vs := currentVirtualService.DeepCopy()
|
||||
|
||||
if len(strategies) > 0 {
|
||||
// apply strategy spec to virtualservice
|
||||
vs.Spec = v.generateVirtualServiceSpec(strategies[0], service).Spec
|
||||
} else {
|
||||
// create a whole new virtualservice
|
||||
|
||||
// TODO(jeff): use FQDN to replace service name
|
||||
vs.Spec.Hosts = []string{name}
|
||||
|
||||
// check if service has TCP protocol ports
|
||||
for _, port := range service.Spec.Ports {
|
||||
var route v1alpha3.DestinationWeight
|
||||
if port.Protocol == v1.ProtocolTCP {
|
||||
route = v1alpha3.DestinationWeight{
|
||||
Destination: v1alpha3.Destination{
|
||||
Host: name,
|
||||
Subset: subsets[0].Name,
|
||||
Port: v1alpha3.PortSelector{
|
||||
Number: uint32(port.Port),
|
||||
},
|
||||
},
|
||||
Weight: 100,
|
||||
}
|
||||
|
||||
// a http port, add to HTTPRoute
|
||||
if len(port.Name) > 0 && (port.Name == "http" || strings.HasPrefix(port.Name, "http-")) {
|
||||
vs.Spec.Http = []v1alpha3.HTTPRoute{{Route: []v1alpha3.DestinationWeight{route}}}
|
||||
break
|
||||
}
|
||||
|
||||
// everything else treated as TCPRoute
|
||||
vs.Spec.Tcp = []v1alpha3.TCPRoute{{Route: []v1alpha3.DestinationWeight{route}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createVirtualService := len(currentVirtualService.ResourceVersion) == 0
|
||||
|
||||
if !createVirtualService &&
|
||||
reflect.DeepEqual(vs.Spec, currentVirtualService.Spec) &&
|
||||
reflect.DeepEqual(service.Labels, currentVirtualService.Labels) {
|
||||
log.V(4).Info("virtual service are equal, skipping update ")
|
||||
return nil
|
||||
}
|
||||
|
||||
newVirtualService := currentVirtualService.DeepCopy()
|
||||
newVirtualService.Labels = service.Labels
|
||||
newVirtualService.Spec = vs.Spec
|
||||
if newVirtualService.Annotations == nil {
|
||||
newVirtualService.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
if len(newVirtualService.Spec.Http) == 0 && len(newVirtualService.Spec.Tcp) == 0 && len(newVirtualService.Spec.Tls) == 0 {
|
||||
err = fmt.Errorf("service %s/%s doesn't have a valid port spec", namespace, name)
|
||||
log.Error(err, "")
|
||||
return err
|
||||
}
|
||||
|
||||
if createVirtualService {
|
||||
_, err = v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Create(newVirtualService)
|
||||
} else {
|
||||
_, err = v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Update(newVirtualService)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
if createVirtualService {
|
||||
v.eventRecorder.Event(newVirtualService, v1.EventTypeWarning, "FailedToCreateVirtualService", fmt.Sprintf("Failed to create virtualservice for service %v/%v: %v", namespace, name, err))
|
||||
} else {
|
||||
v.eventRecorder.Event(newVirtualService, v1.EventTypeWarning, "FailedToUpdateVirtualService", fmt.Sprintf("Failed to update virtualservice for service %v/%v: %v", namespace, name, err))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// When a destinationrule is added, figure out which service it will be used
|
||||
// and enqueue it. obj must have *v1alpha3.DestinationRule type
|
||||
func (v *VirtualServiceController) addDestinationRule(obj interface{}) {
|
||||
dr := obj.(*v1alpha3.DestinationRule)
|
||||
service, err := v.serviceLister.Services(dr.Namespace).Get(dr.Name)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
log.V(3).Info("service not created yet", "namespace", dr.Namespace, "service", dr.Name)
|
||||
return
|
||||
}
|
||||
utilruntime.HandleError(fmt.Errorf("unable to get service with name %s/%s", dr.Namespace, dr.Name))
|
||||
return
|
||||
}
|
||||
|
||||
_, err = v.virtualServiceLister.VirtualServices(dr.Namespace).Get(dr.Name)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
key, err := controller.KeyFunc(service)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("get service %s/%s key failed", service.Namespace, service.Name))
|
||||
return
|
||||
}
|
||||
|
||||
v.queue.Add(key)
|
||||
}
|
||||
} else {
|
||||
// Already have a virtualservice created.
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// when a strategy created
|
||||
func (v *VirtualServiceController) addStrategy(obj interface{}) {
|
||||
strategy := obj.(*servicemeshv1alpha2.Strategy)
|
||||
|
||||
lbs := util.ExtractApplicationLabels(&strategy.ObjectMeta)
|
||||
if len(lbs) == 0 {
|
||||
err := fmt.Errorf("invalid strategy %s/%s labels %s, not have required labels", strategy.Namespace, strategy.Name, strategy.Labels)
|
||||
log.Error(err, "")
|
||||
utilruntime.HandleError(err)
|
||||
return
|
||||
}
|
||||
|
||||
allServices, err := v.serviceLister.Services(strategy.Namespace).List(labels.SelectorFromSet(lbs))
|
||||
if err != nil {
|
||||
log.Error(err, "list services failed")
|
||||
utilruntime.HandleError(err)
|
||||
return
|
||||
}
|
||||
|
||||
// avoid insert a key multiple times
|
||||
set := sets.String{}
|
||||
|
||||
for i := range allServices {
|
||||
service := allServices[i]
|
||||
if service.Spec.Selector == nil || len(service.Spec.Ports) == 0 {
|
||||
// services with nil selectors match nothing, not everything.
|
||||
continue
|
||||
}
|
||||
|
||||
key, err := controller.KeyFunc(service)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
return
|
||||
}
|
||||
set.Insert(key)
|
||||
}
|
||||
|
||||
for key := range set {
|
||||
v.queue.Add(key)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *VirtualServiceController) handleErr(err error, key interface{}) {
|
||||
if err != nil {
|
||||
v.queue.Forget(key)
|
||||
return
|
||||
}
|
||||
|
||||
if v.queue.NumRequeues(key) < maxRetries {
|
||||
log.V(2).Info("Error syncing virtualservice for service retrying.", "key", key, "error", err)
|
||||
v.queue.AddRateLimited(key)
|
||||
return
|
||||
}
|
||||
|
||||
log.V(4).Info("Dropping service out of the queue.", "key", key, "error", err)
|
||||
v.queue.Forget(key)
|
||||
utilruntime.HandleError(err)
|
||||
}
|
||||
|
||||
func (v *VirtualServiceController) generateVirtualServiceSpec(strategy *servicemeshv1alpha2.Strategy, service *v1.Service) *v1alpha3.VirtualService {
|
||||
|
||||
// Define VirtualService to be created
|
||||
vs := &v1alpha3.VirtualService{
|
||||
Spec: strategy.Spec.Template.Spec,
|
||||
}
|
||||
|
||||
// one version rules them all
|
||||
if len(strategy.Spec.GovernorVersion) > 0 {
|
||||
|
||||
governorDestinationWeight := v1alpha3.DestinationWeight{
|
||||
Destination: v1alpha3.Destination{
|
||||
Host: service.Name,
|
||||
Subset: strategy.Spec.GovernorVersion,
|
||||
},
|
||||
Weight: 100,
|
||||
}
|
||||
|
||||
if len(strategy.Spec.Template.Spec.Http) > 0 {
|
||||
governorRoute := v1alpha3.HTTPRoute{
|
||||
Route: []v1alpha3.DestinationWeight{governorDestinationWeight},
|
||||
}
|
||||
|
||||
vs.Spec.Http = []v1alpha3.HTTPRoute{governorRoute}
|
||||
} else if len(strategy.Spec.Template.Spec.Tcp) > 0 {
|
||||
governorRoute := v1alpha3.TCPRoute{
|
||||
Route: []v1alpha3.DestinationWeight{governorDestinationWeight},
|
||||
}
|
||||
vs.Spec.Tcp = []v1alpha3.TCPRoute{governorRoute}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
util.FillDestinationPort(vs, service)
|
||||
return vs
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package virtualservice
|
||||
@@ -18,24 +18,37 @@
|
||||
package informers
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
s2iInformers "github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
|
||||
|
||||
"k8s.io/client-go/informers"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
)
|
||||
|
||||
const defaultResync = 600 * time.Second
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
informerFactory informers.SharedInformerFactory
|
||||
k8sOnce sync.Once
|
||||
s2iOnce sync.Once
|
||||
informerFactory informers.SharedInformerFactory
|
||||
s2iInformerFactory s2iInformers.SharedInformerFactory
|
||||
)
|
||||
|
||||
func SharedInformerFactory() informers.SharedInformerFactory {
|
||||
once.Do(func() {
|
||||
k8sOnce.Do(func() {
|
||||
k8sClient := k8s.Client()
|
||||
informerFactory = informers.NewSharedInformerFactory(k8sClient, defaultResync)
|
||||
})
|
||||
return informerFactory
|
||||
}
|
||||
|
||||
func S2iSharedInformerFactory() s2iInformers.SharedInformerFactory {
|
||||
s2iOnce.Do(func() {
|
||||
k8sClient := k8s.S2iClient()
|
||||
s2iInformerFactory = s2iInformers.NewSharedInformerFactory(k8sClient, defaultResync)
|
||||
})
|
||||
return s2iInformerFactory
|
||||
}
|
||||
|
||||
30
pkg/models/log/constants.go
Normal file
30
pkg/models/log/constants.go
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 log
|
||||
|
||||
type LogQueryLevel int
|
||||
|
||||
const (
|
||||
QueryLevelCluster LogQueryLevel = iota
|
||||
QueryLevelWorkspace
|
||||
QueryLevelNamespace
|
||||
QueryLevelWorkload
|
||||
QueryLevelPod
|
||||
QueryLevelContainer
|
||||
)
|
||||
309
pkg/models/log/logcollector.go
Normal file
309
pkg/models/log/logcollector.go
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 log
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func intersection(s1, s2 []string) (inter []string) {
|
||||
hash := make(map[string]bool)
|
||||
for _, e := range s1 {
|
||||
hash[e] = true
|
||||
}
|
||||
for _, e := range s2 {
|
||||
// If elements present in the hashmap then append intersection list.
|
||||
if hash[e] {
|
||||
inter = append(inter, e)
|
||||
}
|
||||
}
|
||||
//Remove dups from slice.
|
||||
inter = removeDups(inter)
|
||||
return
|
||||
}
|
||||
|
||||
//Remove dups from slice.
|
||||
func removeDups(elements []string) (nodups []string) {
|
||||
encountered := make(map[string]bool)
|
||||
for _, element := range elements {
|
||||
if !encountered[element] {
|
||||
nodups = append(nodups, element)
|
||||
encountered[element] = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func in(value interface{}, container interface{}) int {
|
||||
if container == nil {
|
||||
return -1
|
||||
}
|
||||
containerValue := reflect.ValueOf(container)
|
||||
switch reflect.TypeOf(container).Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
for i := 0; i < containerValue.Len(); i++ {
|
||||
if containerValue.Index(i).Interface() == value {
|
||||
return i
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if containerValue.MapIndex(reflect.ValueOf(value)).IsValid() {
|
||||
return -1
|
||||
}
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func getWorkloadName(name string, kind string) string {
|
||||
if kind == "ReplicaSet" {
|
||||
lastIndex := strings.LastIndex(name, "-")
|
||||
if lastIndex >= 0 {
|
||||
return name[:lastIndex]
|
||||
}
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func matchLabel(label string, labelsMatch []string) bool {
|
||||
var result = false
|
||||
|
||||
for _, labelMatch := range labelsMatch {
|
||||
if strings.Compare(label, labelMatch) == 0 {
|
||||
result = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func queryLabel(label string, labelsQuery []string) bool {
|
||||
var result = false
|
||||
|
||||
for _, labelQuery := range labelsQuery {
|
||||
if strings.Contains(label, labelQuery) {
|
||||
result = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func QueryWorkspace(workspaceMatch string, workspaceQuery string) (bool, []string) {
|
||||
if workspaceMatch == "" && workspaceQuery == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
nsLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
nsList, err := nsLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.Error("failed to list namespace, error: ", err)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var namespaces []string
|
||||
|
||||
var hasMatch = false
|
||||
var workspacesMatch []string
|
||||
if workspaceMatch != "" {
|
||||
workspacesMatch = strings.Split(strings.Replace(workspaceMatch, ",", " ", -1), " ")
|
||||
hasMatch = true
|
||||
}
|
||||
|
||||
var hasQuery = false
|
||||
var workspacesQuery []string
|
||||
if workspaceQuery != "" {
|
||||
workspacesQuery = strings.Split(strings.ToLower(strings.Replace(workspaceQuery, ",", " ", -1)), " ")
|
||||
hasQuery = true
|
||||
}
|
||||
|
||||
for _, ns := range nsList {
|
||||
labels := ns.GetLabels()
|
||||
_, ok := labels[constants.WorkspaceLabelKey]
|
||||
if ok {
|
||||
var namespaceCanAppend = true
|
||||
if hasMatch {
|
||||
if !matchLabel(labels[constants.WorkspaceLabelKey], workspacesMatch) {
|
||||
namespaceCanAppend = false
|
||||
}
|
||||
}
|
||||
if hasQuery {
|
||||
if !queryLabel(strings.ToLower(labels[constants.WorkspaceLabelKey]), workspacesQuery) {
|
||||
namespaceCanAppend = false
|
||||
}
|
||||
}
|
||||
|
||||
if namespaceCanAppend {
|
||||
namespaces = append(namespaces, ns.GetName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, namespaces
|
||||
}
|
||||
|
||||
func MatchNamespace(namespaceMatch string, namespaceFilled bool, namespaces []string) (bool, []string) {
|
||||
if namespaceMatch == "" {
|
||||
return namespaceFilled, namespaces
|
||||
}
|
||||
|
||||
namespacesMatch := strings.Split(strings.Replace(namespaceMatch, ",", " ", -1), " ")
|
||||
|
||||
if namespaceFilled {
|
||||
return true, intersection(namespacesMatch, namespaces)
|
||||
}
|
||||
|
||||
return true, namespacesMatch
|
||||
}
|
||||
|
||||
func QueryWorkload(workloadMatch string, workloadQuery string, namespaces []string) (bool, []string) {
|
||||
if workloadMatch == "" && workloadQuery == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
podList, err := podLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.Error("failed to list pods, error: ", err)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var pods []string
|
||||
|
||||
var hasMatch = false
|
||||
var workloadsMatch []string
|
||||
if workloadMatch != "" {
|
||||
workloadsMatch = strings.Split(strings.Replace(workloadMatch, ",", " ", -1), " ")
|
||||
hasMatch = true
|
||||
}
|
||||
|
||||
var hasQuery = false
|
||||
var workloadsQuery []string
|
||||
if workloadQuery != "" {
|
||||
workloadsQuery = strings.Split(strings.ToLower(strings.Replace(workloadQuery, ",", " ", -1)), " ")
|
||||
hasQuery = true
|
||||
}
|
||||
|
||||
if namespaces == nil {
|
||||
for _, pod := range podList {
|
||||
/*if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
||||
glog.Infof("List Pod %v:%v:%v", pod.Name, pod.ObjectMeta.OwnerReferences[0].Name, pod.ObjectMeta.OwnerReferences[0].Kind)
|
||||
}*/
|
||||
if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
||||
var podCanAppend = true
|
||||
workloadName := getWorkloadName(pod.ObjectMeta.OwnerReferences[0].Name, pod.ObjectMeta.OwnerReferences[0].Kind)
|
||||
if hasMatch {
|
||||
if !matchLabel(workloadName, workloadsMatch) {
|
||||
podCanAppend = false
|
||||
}
|
||||
}
|
||||
if hasQuery {
|
||||
if !queryLabel(strings.ToLower(workloadName), workloadsQuery) {
|
||||
podCanAppend = false
|
||||
}
|
||||
}
|
||||
|
||||
if podCanAppend {
|
||||
pods = append(pods, pod.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, pod := range podList {
|
||||
/*if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
||||
glog.Infof("List Pod %v:%v:%v", pod.Name, pod.ObjectMeta.OwnerReferences[0].Name, pod.ObjectMeta.OwnerReferences[0].Kind)
|
||||
}*/
|
||||
if len(pod.ObjectMeta.OwnerReferences) > 0 && in(pod.Namespace, namespaces) >= 0 {
|
||||
var podCanAppend = true
|
||||
workloadName := getWorkloadName(pod.ObjectMeta.OwnerReferences[0].Name, pod.ObjectMeta.OwnerReferences[0].Kind)
|
||||
if hasMatch {
|
||||
if !matchLabel(workloadName, workloadsMatch) {
|
||||
podCanAppend = false
|
||||
}
|
||||
}
|
||||
if hasQuery {
|
||||
if !queryLabel(strings.ToLower(workloadName), workloadsQuery) {
|
||||
podCanAppend = false
|
||||
}
|
||||
}
|
||||
|
||||
if podCanAppend {
|
||||
pods = append(pods, pod.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, pods
|
||||
}
|
||||
|
||||
func MatchPod(podMatch string, podFilled bool, pods []string) (bool, []string) {
|
||||
if podMatch == "" {
|
||||
return podFilled, pods
|
||||
}
|
||||
|
||||
podsMatch := strings.Split(strings.Replace(podMatch, ",", " ", -1), " ")
|
||||
|
||||
if podFilled {
|
||||
return true, intersection(podsMatch, pods)
|
||||
}
|
||||
|
||||
return true, podsMatch
|
||||
}
|
||||
|
||||
func MatchContainer(containerMatch string) (bool, []string) {
|
||||
if containerMatch == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, strings.Split(strings.Replace(containerMatch, ",", " ", -1), " ")
|
||||
}
|
||||
|
||||
func GetWorkspaceOfNamesapce(namespace string) string {
|
||||
var workspace string
|
||||
workspace = ""
|
||||
|
||||
nsLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
nsList, err := nsLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.Error("failed to list namespace, error: ", err)
|
||||
return workspace
|
||||
}
|
||||
|
||||
for _, ns := range nsList {
|
||||
if ns.GetName() == namespace {
|
||||
labels := ns.GetLabels()
|
||||
_, ok := labels[constants.WorkspaceLabelKey]
|
||||
if ok {
|
||||
workspace = labels[constants.WorkspaceLabelKey]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return workspace
|
||||
}
|
||||
543
pkg/models/log/logcrd.go
Normal file
543
pkg/models/log/logcrd.go
Normal file
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
Copyright 2018 The KubeSphere 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 log
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/golang/glog"
|
||||
"github.com/google/uuid"
|
||||
"github.com/json-iterator/go"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
es "kubesphere.io/kubesphere/pkg/simple/client/elasticsearch"
|
||||
fb "kubesphere.io/kubesphere/pkg/simple/client/fluentbit"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
const (
|
||||
ConfigMapName = "fluent-bit-output-config"
|
||||
ConfigMapData = "outputs"
|
||||
LoggingNamespace = "kubesphere-logging-system"
|
||||
)
|
||||
|
||||
func createCRDClientSet() (*rest.RESTClient, *runtime.Scheme, error) {
|
||||
config, err := fb.GetClientConfig("")
|
||||
if err != nil {
|
||||
//panic(err.Error())
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Create a new clientset which include our CRD schema
|
||||
return fb.NewFluentbitCRDClient(config)
|
||||
}
|
||||
|
||||
func getParameterValue(parameters []fb.Parameter, name string) string {
|
||||
var value string
|
||||
|
||||
value = ""
|
||||
for _, parameter := range parameters {
|
||||
if parameter.Name == name {
|
||||
value = parameter.Value
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func getFilters(result *FluentbitFiltersResult, Filters []fb.Plugin) {
|
||||
for _, filter := range Filters {
|
||||
if strings.Compare(filter.Name, "fluentbit-filter-input-regex") == 0 {
|
||||
parameters := strings.Split(getParameterValue(filter.Parameters, "Regex"), " ")
|
||||
field := strings.TrimSuffix(strings.TrimPrefix(parameters[0], "kubernetes_"), "_name")
|
||||
expression := parameters[1]
|
||||
result.Filters = append(result.Filters, FluentbitFilter{"Regex", field, expression})
|
||||
}
|
||||
if strings.Compare(filter.Name, "fluentbit-filter-input-exclude") == 0 {
|
||||
parameters := strings.Split(getParameterValue(filter.Parameters, "Exclude"), " ")
|
||||
field := strings.TrimSuffix(strings.TrimPrefix(parameters[0], "kubernetes_"), "_name")
|
||||
expression := parameters[1]
|
||||
result.Filters = append(result.Filters, FluentbitFilter{"Exclude", field, expression})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func FluentbitFiltersQuery() *FluentbitFiltersResult {
|
||||
var result FluentbitFiltersResult
|
||||
|
||||
crdcs, scheme, err := createCRDClientSet()
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// Create a CRD client interface
|
||||
crdclient := fb.CrdClient(crdcs, scheme, LoggingNamespace)
|
||||
|
||||
item, err := crdclient.Get("fluent-bit")
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
getFilters(&result, item.Spec.Filter)
|
||||
|
||||
result.Status = http.StatusOK
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitFiltersUpdate(filters *[]FluentbitFilter) *FluentbitFiltersResult {
|
||||
var result FluentbitFiltersResult
|
||||
|
||||
//Generate filter plugin config
|
||||
var filter []fb.Plugin
|
||||
|
||||
var para_kubernetes []fb.Parameter
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Name", Value: "kubernetes"})
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Kube_URL", Value: "https://kubernetes.default.svc:443"})
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Kube_CA_File", Value: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"})
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Kube_Token_File", Value: "/var/run/secrets/kubernetes.io/serviceaccount/token"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-kubernetes", Parameters: para_kubernetes})
|
||||
|
||||
var para_lift []fb.Parameter
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Name", Value: "nest"})
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Operation", Value: "lift"})
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Nested_under", Value: "kubernetes"})
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Prefix_with", Value: "kubernetes_"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-lift", Parameters: para_lift})
|
||||
|
||||
var para_remove_stream []fb.Parameter
|
||||
para_remove_stream = append(para_remove_stream, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_stream = append(para_remove_stream, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_stream = append(para_remove_stream, fb.Parameter{Name: "Remove", Value: "stream"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-stream", Parameters: para_remove_stream})
|
||||
|
||||
var para_remove_labels []fb.Parameter
|
||||
para_remove_labels = append(para_remove_labels, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_labels = append(para_remove_labels, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_labels = append(para_remove_labels, fb.Parameter{Name: "Remove", Value: "kubernetes_labels"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-labels", Parameters: para_remove_labels})
|
||||
|
||||
var para_remove_annotations []fb.Parameter
|
||||
para_remove_annotations = append(para_remove_annotations, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_annotations = append(para_remove_annotations, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_annotations = append(para_remove_annotations, fb.Parameter{Name: "Remove", Value: "kubernetes_annotations"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-annotations", Parameters: para_remove_annotations})
|
||||
|
||||
var para_remove_pod_id []fb.Parameter
|
||||
para_remove_pod_id = append(para_remove_pod_id, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_pod_id = append(para_remove_pod_id, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_pod_id = append(para_remove_pod_id, fb.Parameter{Name: "Remove", Value: "kubernetes_pod_id"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-podid", Parameters: para_remove_pod_id})
|
||||
|
||||
var para_remove_docker_id []fb.Parameter
|
||||
para_remove_docker_id = append(para_remove_docker_id, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_docker_id = append(para_remove_docker_id, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_docker_id = append(para_remove_docker_id, fb.Parameter{Name: "Remove", Value: "kubernetes_docker_id"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-dockerid", Parameters: para_remove_docker_id})
|
||||
|
||||
if len(*filters) > 0 {
|
||||
for _, item := range *filters {
|
||||
if strings.Compare(item.Type, "Regex") == 0 {
|
||||
field := "kubernetes_" + strings.TrimSpace(item.Field) + "_name"
|
||||
expression := strings.TrimSpace(item.Expression)
|
||||
|
||||
var para_regex []fb.Parameter
|
||||
para_regex = append(para_regex, fb.Parameter{Name: "Name", Value: "grep"})
|
||||
para_regex = append(para_regex, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_regex = append(para_regex, fb.Parameter{Name: "Regex", Value: field + " " + expression})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-regex", Parameters: para_regex})
|
||||
}
|
||||
|
||||
if strings.Compare(item.Type, "Exclude") == 0 {
|
||||
field := "kubernetes_" + strings.TrimSpace(item.Field) + "_name"
|
||||
expression := strings.TrimSpace(item.Expression)
|
||||
|
||||
var para_exclude []fb.Parameter
|
||||
para_exclude = append(para_exclude, fb.Parameter{Name: "Name", Value: "grep"})
|
||||
para_exclude = append(para_exclude, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_exclude = append(para_exclude, fb.Parameter{Name: "Exclude", Value: field + " " + expression})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-exclude", Parameters: para_exclude})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var para_nest []fb.Parameter
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Name", Value: "nest"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Operation", Value: "nest"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Wildcard", Value: "kubernetes_*"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Nested_under", Value: "kubernetes"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Remove_prefix", Value: "kubernetes_"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-nest", Parameters: para_nest})
|
||||
|
||||
crdcs, scheme, err := createCRDClientSet()
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// Create a CRD client interface
|
||||
crdclient := fb.CrdClient(crdcs, scheme, LoggingNamespace)
|
||||
|
||||
var item *fb.FluentBit
|
||||
var err_read error
|
||||
|
||||
item, err_read = crdclient.Get("fluent-bit")
|
||||
if err_read != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
item.Spec.Filter = filter
|
||||
|
||||
itemnew, err := crdclient.Update("fluent-bit", item)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
getFilters(&result, itemnew.Spec.Filter)
|
||||
result.Status = http.StatusOK
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitOutputsQuery() *FluentbitOutputsResult {
|
||||
var result FluentbitOutputsResult
|
||||
|
||||
outputs, err := GetFluentbitOutputFromConfigMap()
|
||||
if err != nil {
|
||||
result.Status = http.StatusNotFound
|
||||
return &result
|
||||
}
|
||||
|
||||
result.Outputs = outputs
|
||||
result.Status = http.StatusOK
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitOutputInsert(output fb.OutputPlugin) *FluentbitOutputsResult {
|
||||
var result FluentbitOutputsResult
|
||||
|
||||
// 1. Update ConfigMap
|
||||
var outputs []fb.OutputPlugin
|
||||
outputs, err := GetFluentbitOutputFromConfigMap()
|
||||
if err != nil {
|
||||
// If the ConfigMap doesn't exist, a new one will be created later
|
||||
glog.Errorln(err)
|
||||
}
|
||||
|
||||
// When adding a new output for the first time, one should always set it disabled
|
||||
output.Enable = false
|
||||
output.Id = uuid.New().String()
|
||||
output.Updatetime = time.Now()
|
||||
|
||||
outputs = append(outputs, output)
|
||||
|
||||
err = updateFluentbitOutputConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 2. Keep CRD in inline with ConfigMap
|
||||
err = syncFluentbitCRDOutputWithConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 3. If it's an configs output added, reset configs client configs
|
||||
configs := ParseEsOutputParams(output.Parameters)
|
||||
if configs != nil {
|
||||
configs.WriteESConfigs()
|
||||
}
|
||||
|
||||
result.Status = http.StatusOK
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitOutputUpdate(output fb.OutputPlugin, id string) *FluentbitOutputsResult {
|
||||
var result FluentbitOutputsResult
|
||||
|
||||
// 1. Update ConfigMap
|
||||
var outputs []fb.OutputPlugin
|
||||
outputs, err := GetFluentbitOutputFromConfigMap()
|
||||
if err != nil {
|
||||
// If the ConfigMap doesn't exist, a new one will be created later
|
||||
glog.Errorln(err)
|
||||
}
|
||||
|
||||
index := 0
|
||||
for _, output := range outputs {
|
||||
if output.Id == id {
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
if index >= len(outputs) {
|
||||
result.Status = http.StatusNotFound
|
||||
return &result
|
||||
}
|
||||
|
||||
output.Updatetime = time.Now()
|
||||
outputs = append(append(outputs[:index], outputs[index+1:]...), output)
|
||||
|
||||
err = updateFluentbitOutputConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 2. Keep CRD in inline with ConfigMap
|
||||
err = syncFluentbitCRDOutputWithConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 3. If it's an configs output updated, reset configs client configs
|
||||
configs := ParseEsOutputParams(output.Parameters)
|
||||
if configs != nil {
|
||||
configs.WriteESConfigs()
|
||||
}
|
||||
|
||||
result.Status = http.StatusOK
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitOutputDelete(id string) *FluentbitOutputsResult {
|
||||
var result FluentbitOutputsResult
|
||||
|
||||
// 1. Update ConfigMap
|
||||
// If the ConfigMap doesn't exist, a new one will be created
|
||||
outputs, _ := GetFluentbitOutputFromConfigMap()
|
||||
|
||||
index := 0
|
||||
for _, output := range outputs {
|
||||
if output.Id == id {
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
if index >= len(outputs) {
|
||||
result.Status = http.StatusNotFound
|
||||
return &result
|
||||
}
|
||||
|
||||
outputs = append(outputs[:index], outputs[index+1:]...)
|
||||
|
||||
err := updateFluentbitOutputConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 2. Keep CRD in inline with DB
|
||||
err = syncFluentbitCRDOutputWithConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
result.Status = http.StatusOK
|
||||
return &result
|
||||
}
|
||||
|
||||
func GetFluentbitOutputFromConfigMap() ([]fb.OutputPlugin, error) {
|
||||
configMap, err := informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister().ConfigMaps(LoggingNamespace).Get(ConfigMapName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := configMap.Data[ConfigMapData]
|
||||
|
||||
var outputs []fb.OutputPlugin
|
||||
if err = jsonIter.UnmarshalFromString(data, &outputs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return outputs, nil
|
||||
}
|
||||
|
||||
func updateFluentbitOutputConfigMap(outputs []fb.OutputPlugin) error {
|
||||
|
||||
var data string
|
||||
data, err := jsonIter.MarshalToString(outputs)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the ConfigMap
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Creates the clientset
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
configMapClient := clientset.CoreV1().ConfigMaps(LoggingNamespace)
|
||||
|
||||
configMap, err := configMapClient.Get(ConfigMapName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
|
||||
// If the ConfigMap doesn't exist, create a new one
|
||||
newConfigMap := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ConfigMapName,
|
||||
},
|
||||
Data: map[string]string{ConfigMapData: data},
|
||||
}
|
||||
|
||||
_, err = configMapClient.Create(newConfigMap)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
||||
// update
|
||||
configMap.Data = map[string]string{ConfigMapData: data}
|
||||
_, err = configMapClient.Update(configMap)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func syncFluentbitCRDOutputWithConfigMap(outputs []fb.OutputPlugin) error {
|
||||
|
||||
var enabledOutputs []fb.Plugin
|
||||
for _, output := range outputs {
|
||||
if output.Enable {
|
||||
enabledOutputs = append(enabledOutputs, fb.Plugin{Type: output.Type, Name: output.Name, Parameters: output.Parameters})
|
||||
}
|
||||
}
|
||||
|
||||
// Empty output is not allowed, must specify a null-type output
|
||||
if len(enabledOutputs) == 0 {
|
||||
enabledOutputs = []fb.Plugin{
|
||||
{
|
||||
Type: "fluentbit_output",
|
||||
Name: "fluentbit-output-null",
|
||||
Parameters: []fb.Parameter{
|
||||
{
|
||||
Name: "Name",
|
||||
Value: "null",
|
||||
},
|
||||
{
|
||||
Name: "Match",
|
||||
Value: "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
crdcs, scheme, err := createCRDClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a CRD client interface
|
||||
crdclient := fb.CrdClient(crdcs, scheme, LoggingNamespace)
|
||||
|
||||
fluentbit, err := crdclient.Get("fluent-bit")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fluentbit.Spec.Output = enabledOutputs
|
||||
_, err = crdclient.Update("fluent-bit", fluentbit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse es host, port and index
|
||||
func ParseEsOutputParams(params []fb.Parameter) *es.ESConfigs {
|
||||
|
||||
var (
|
||||
isEsFound bool
|
||||
|
||||
host = "127.0.0.1"
|
||||
port = "9200"
|
||||
index = "logstash"
|
||||
logstashFormat string
|
||||
logstashPrefix string
|
||||
)
|
||||
|
||||
for _, param := range params {
|
||||
switch param.Name {
|
||||
case "Name":
|
||||
if param.Value == "es" {
|
||||
isEsFound = true
|
||||
}
|
||||
case "Host":
|
||||
host = param.Value
|
||||
case "Port":
|
||||
port = param.Value
|
||||
case "Index":
|
||||
index = param.Value
|
||||
case "Logstash_Format":
|
||||
logstashFormat = strings.ToLower(param.Value)
|
||||
case "Logstash_Prefix":
|
||||
logstashPrefix = param.Value
|
||||
}
|
||||
}
|
||||
|
||||
if !isEsFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If Logstash_Format is On/True, ignore Index
|
||||
if logstashFormat == "on" || logstashFormat == "true" {
|
||||
if logstashPrefix != "" {
|
||||
index = logstashPrefix
|
||||
} else {
|
||||
index = "logstash"
|
||||
}
|
||||
}
|
||||
|
||||
return &es.ESConfigs{Host: host, Port: port, Index: index}
|
||||
}
|
||||
53
pkg/models/log/types.go
Normal file
53
pkg/models/log/types.go
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 log
|
||||
|
||||
import (
|
||||
fb "kubesphere.io/kubesphere/pkg/simple/client/fluentbit"
|
||||
)
|
||||
|
||||
type FluentbitCRDResult struct {
|
||||
Status int `json:"status"`
|
||||
CRD fb.FluentBitSpec `json:"CRD,omitempty"`
|
||||
}
|
||||
|
||||
type FluentbitCRDDeleteResult struct {
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
type FluentbitSettingsResult struct {
|
||||
Status int `json:"status"`
|
||||
Enable string `json:"Enable,omitempty"`
|
||||
}
|
||||
|
||||
type FluentbitFilter struct {
|
||||
Type string `json:"type"`
|
||||
Field string `json:"field"`
|
||||
Expression string `json:"expression"`
|
||||
}
|
||||
|
||||
type FluentbitFiltersResult struct {
|
||||
Status int `json:"status"`
|
||||
Filters []FluentbitFilter `json:"filters,omitempty"`
|
||||
}
|
||||
|
||||
type FluentbitOutputsResult struct {
|
||||
Status int `json:"status"`
|
||||
Outputs []fb.OutputPlugin `json:"outputs,omitempty"`
|
||||
}
|
||||
@@ -1,42 +1,32 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere Authors.
|
||||
Copyright 2019 The KubeSphere 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
|
||||
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
|
||||
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.
|
||||
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 metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/components"
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
|
||||
"github.com/golang/glog"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
|
||||
@@ -44,12 +34,12 @@ import (
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
client "kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
nodeStatusDelLabel = []string{"endpoint", "instance", "job", "namespace", "pod", "service"}
|
||||
)
|
||||
var jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
const (
|
||||
ChannelMaxCapacityWorkspaceMetric = 800
|
||||
@@ -145,9 +135,9 @@ func getAllWorkspaces() map[string]int {
|
||||
paramValues := make(url.Values)
|
||||
paramValues.Set("query", WorkspaceNamespaceLabelRule)
|
||||
params := paramValues.Encode()
|
||||
res := prometheus.SendMonitoringRequest(prometheus.DefaultQueryType, params)
|
||||
res := client.SendMonitoringRequest(client.DefaultQueryType, params)
|
||||
|
||||
metric := ReformatJson(res, "")
|
||||
metric := ReformatJson(res, "", map[string]string{"workspace": "workspace"})
|
||||
|
||||
return getAllWorkspaceNames(metric)
|
||||
}
|
||||
@@ -240,17 +230,17 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
||||
}
|
||||
}
|
||||
|
||||
func AssembleSpecificWorkloadMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string, bool) {
|
||||
func AssembleSpecificWorkloadMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string, bool) {
|
||||
|
||||
nsName := monitoringRequest.NsName
|
||||
wkName := monitoringRequest.WorkloadName
|
||||
podsFilter := monitoringRequest.PodsFilter
|
||||
wlName := monitoringRequest.WorkloadName
|
||||
podsFilter := monitoringRequest.ResourcesFilter
|
||||
|
||||
rule := MakeSpecificWorkloadRule(monitoringRequest.WorkloadKind, wkName, nsName)
|
||||
rule := MakeSpecificWorkloadRule(monitoringRequest.WorkloadKind, wlName, nsName)
|
||||
paramValues := monitoringRequest.Params
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
|
||||
res := prometheus.SendMonitoringRequest(prometheus.DefaultQueryType, params)
|
||||
res := client.SendMonitoringRequest(client.DefaultQueryType, params)
|
||||
|
||||
podNamesFilter := getPodNameRegexInWorkload(res, podsFilter)
|
||||
|
||||
@@ -261,32 +251,26 @@ func AssembleSpecificWorkloadMetricRequestInfo(monitoringRequest *prometheus.Mon
|
||||
return queryType, params, rule == ""
|
||||
}
|
||||
|
||||
func AssembleAllWorkloadMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleAllWorkloadMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
|
||||
paramValues := monitoringRequest.Params
|
||||
|
||||
rule := MakeWorkloadPromQL(metricName, monitoringRequest.NsName, monitoringRequest.WlFilter)
|
||||
rule := MakeWorkloadPromQL(metricName, monitoringRequest.NsName, monitoringRequest.ResourcesFilter)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssemblePodMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string, bool) {
|
||||
func AssemblePodMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string, bool) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
|
||||
paramValues := monitoringRequest.Params
|
||||
|
||||
rule := MakePodPromQL(metricName, monitoringRequest.NsName, monitoringRequest.NodeId, monitoringRequest.PodName, monitoringRequest.PodsFilter)
|
||||
rule := MakePodPromQL(metricName, monitoringRequest.NsName, monitoringRequest.NodeId, monitoringRequest.PodName, monitoringRequest.ResourcesFilter)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
return queryType, params, rule == ""
|
||||
}
|
||||
|
||||
func GetMetric(queryType, params, metricName string) *FormatedMetric {
|
||||
res := prometheus.SendMonitoringRequest(queryType, params)
|
||||
formatedMetric := ReformatJson(res, metricName)
|
||||
return formatedMetric
|
||||
}
|
||||
|
||||
func GetNodeAddressInfo() *map[string][]v1.NodeAddress {
|
||||
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
nodes, err := nodeLister.List(labels.Everything())
|
||||
@@ -319,33 +303,34 @@ func AddNodeAddressMetric(nodeMetric *FormatedMetric, nodeAddress *map[string][]
|
||||
}
|
||||
}
|
||||
|
||||
func MonitorContainer(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) *FormatedMetric {
|
||||
func MonitorContainer(monitoringRequest *client.MonitoringRequestParams, metricName string) *FormatedMetric {
|
||||
queryType, params := AssembleContainerMetricRequestInfo(monitoringRequest, metricName)
|
||||
res := GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
res := ReformatJson(metricsStr, metricName, map[string]string{"container_name": ""})
|
||||
return res
|
||||
}
|
||||
|
||||
func AssembleContainerMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleContainerMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
|
||||
paramValues := monitoringRequest.Params
|
||||
rule := MakeContainerPromQL(monitoringRequest.NsName, monitoringRequest.NodeId, monitoringRequest.PodName, monitoringRequest.ContainerName, metricName, monitoringRequest.ContainersFilter)
|
||||
rule := MakeContainerPromQL(monitoringRequest.NsName, monitoringRequest.NodeId, monitoringRequest.PodName, monitoringRequest.ContainerName, metricName, monitoringRequest.ResourcesFilter)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssembleNamespaceMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleNamespaceMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
|
||||
paramValues := monitoringRequest.Params
|
||||
rule := MakeNamespacePromQL(monitoringRequest.NsName, monitoringRequest.NsFilter, metricName)
|
||||
rule := MakeNamespacePromQL(monitoringRequest.NsName, monitoringRequest.ResourcesFilter, metricName)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
|
||||
func AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
|
||||
|
||||
nsFilter := "^(" + strings.Join(namespaceList, "|") + ")$"
|
||||
|
||||
@@ -357,7 +342,7 @@ func AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest *prometheus.Mo
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssembleAllWorkspaceMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
|
||||
func AssembleAllWorkspaceMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
|
||||
var nsFilter = "^()$"
|
||||
|
||||
if namespaceList != nil {
|
||||
@@ -407,7 +392,7 @@ func filterNamespace(nsFilter string, namespaceList []string) []string {
|
||||
return newNSlist
|
||||
}
|
||||
|
||||
func MonitorAllWorkspaces(monitoringRequest *prometheus.MonitoringRequestParams) *FormatedLevelMetric {
|
||||
func MonitorAllWorkspaces(monitoringRequest *client.MonitoringRequestParams) *FormatedLevelMetric {
|
||||
metricsFilter := monitoringRequest.MetricsFilter
|
||||
if strings.Trim(metricsFilter, " ") == "" {
|
||||
metricsFilter = ".*"
|
||||
@@ -429,7 +414,7 @@ func MonitorAllWorkspaces(monitoringRequest *prometheus.MonitoringRequestParams)
|
||||
wsMap := getAllWorkspaces()
|
||||
|
||||
for ws := range wsMap {
|
||||
bol, err := regexp.MatchString(monitoringRequest.WsFilter, ws)
|
||||
bol, err := regexp.MatchString(monitoringRequest.ResourcesFilter, ws)
|
||||
if err == nil && bol {
|
||||
// a workspace
|
||||
wgAll.Add(1)
|
||||
@@ -470,7 +455,7 @@ func MonitorAllWorkspaces(monitoringRequest *prometheus.MonitoringRequestParams)
|
||||
}
|
||||
}
|
||||
|
||||
func collectWorkspaceMetric(monitoringRequest *prometheus.MonitoringRequestParams, ws string, filterMetricsName []string, wgAll *sync.WaitGroup, wsAllch chan *[]FormatedMetric) {
|
||||
func collectWorkspaceMetric(monitoringRequest *client.MonitoringRequestParams, ws string, filterMetricsName []string, wgAll *sync.WaitGroup, wsAllch chan *[]FormatedMetric) {
|
||||
defer wgAll.Done()
|
||||
var wg sync.WaitGroup
|
||||
var ch = make(chan *FormatedMetric, ChannelMaxCapacity)
|
||||
@@ -484,7 +469,8 @@ func collectWorkspaceMetric(monitoringRequest *prometheus.MonitoringRequestParam
|
||||
go func(metricName string) {
|
||||
|
||||
queryType, params := AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest, namespaceArray, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"namespace": ""})
|
||||
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
@@ -511,7 +497,7 @@ func collectWorkspaceMetric(monitoringRequest *prometheus.MonitoringRequestParam
|
||||
wsAllch <- &metricsArray
|
||||
}
|
||||
|
||||
func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, resourceType string) *FormatedLevelMetric {
|
||||
func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resourceType string) *FormatedLevelMetric {
|
||||
metricsFilter := monitoringRequest.MetricsFilter
|
||||
if metricsFilter == "" {
|
||||
metricsFilter = ".*"
|
||||
@@ -529,10 +515,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleClusterMetricRequestInfo(monitoringRequest, metricName)
|
||||
clusterMetrics := GetMetric(queryType, params, metricName)
|
||||
|
||||
ch <- clusterMetrics
|
||||
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"cluster": "local"})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -546,7 +530,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleNodeMetricRequestInfo(monitoringRequest, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"node": ""})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -560,7 +545,7 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
if err != nil {
|
||||
glog.Errorln(err.Error())
|
||||
}
|
||||
namespaceArray = filterNamespace(monitoringRequest.NsFilter, namespaceArray)
|
||||
namespaceArray = filterNamespace(monitoringRequest.ResourcesFilter, namespaceArray)
|
||||
|
||||
if monitoringRequest.Tp == "rank" {
|
||||
for _, metricName := range NamespaceMetricsNames {
|
||||
@@ -570,12 +555,13 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
|
||||
bol, err := regexp.MatchString(metricsFilter, metricName)
|
||||
ns := "^(" + strings.Join(namespaceArray, "|") + ")$"
|
||||
monitoringRequest.NsFilter = ns
|
||||
monitoringRequest.ResourcesFilter = ns
|
||||
if err == nil && bol {
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleNamespaceMetricRequestInfo(monitoringRequest, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workspace": "workspace"})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -593,7 +579,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest, namespaceArray, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workspace": "workspace"})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -610,9 +597,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleAllWorkspaceMetricRequestInfo(monitoringRequest, nil, metricName)
|
||||
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workspace": "workspaces"})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -627,7 +613,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleNamespaceMetricRequestInfo(monitoringRequest, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"namespace": ""})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -635,15 +622,15 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
}
|
||||
case MetricLevelWorkload:
|
||||
{
|
||||
if monitoringRequest.Tp == "rank" {
|
||||
if monitoringRequest.WorkloadName == "" {
|
||||
for _, metricName := range WorkloadMetricsNames {
|
||||
bol, err := regexp.MatchString(metricsFilter, metricName)
|
||||
if err == nil && bol {
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleAllWorkloadMetricRequestInfo(monitoringRequest, metricName)
|
||||
fmtMetrics := GetMetric(queryType, params, metricName)
|
||||
ch <- fmtMetrics
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workload": ""})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -657,7 +644,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
metricName = strings.TrimLeft(metricName, "workload_")
|
||||
queryType, params, nullRule := AssembleSpecificWorkloadMetricRequestInfo(monitoringRequest, metricName)
|
||||
if !nullRule {
|
||||
fmtMetrics := GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
fmtMetrics := ReformatJson(metricsStr, metricName, map[string]string{"pod_name": ""})
|
||||
unifyMetricHistoryTimeRange(fmtMetrics)
|
||||
ch <- fmtMetrics
|
||||
}
|
||||
@@ -676,7 +664,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
go func(metricName string) {
|
||||
queryType, params, nullRule := AssemblePodMetricRequestInfo(monitoringRequest, metricName)
|
||||
if !nullRule {
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"pod_name": ""})
|
||||
} else {
|
||||
ch <- nil
|
||||
}
|
||||
@@ -693,7 +682,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleContainerMetricRequestInfo(monitoringRequest, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"container_name": ""})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -868,125 +858,7 @@ func getSpecificMetricItem(timestamp int64, metricName string, resource string,
|
||||
return &nsMetrics
|
||||
}
|
||||
|
||||
// k8s component(controller, scheduler, etcd) status
|
||||
func MonitorComponentStatus(monitoringRequest *prometheus.MonitoringRequestParams) *[]interface{} {
|
||||
componentList, err := k8s.Client().CoreV1().ComponentStatuses().List(metaV1.ListOptions{})
|
||||
if err != nil {
|
||||
glog.Errorln(err.Error())
|
||||
}
|
||||
|
||||
var componentStatusList []*ComponentStatus
|
||||
for _, item := range componentList.Items {
|
||||
var status []OneComponentStatus
|
||||
for _, cond := range item.Conditions {
|
||||
status = append(status, OneComponentStatus{
|
||||
Type: string(cond.Type),
|
||||
Status: string(cond.Status),
|
||||
Message: cond.Message,
|
||||
Error: cond.Error,
|
||||
})
|
||||
}
|
||||
|
||||
componentStatusList = append(componentStatusList, &ComponentStatus{
|
||||
Name: item.Name,
|
||||
Namespace: item.Namespace,
|
||||
Labels: item.Labels,
|
||||
ComponentStatus: status,
|
||||
})
|
||||
}
|
||||
|
||||
// node status
|
||||
queryType := monitoringRequest.QueryType
|
||||
paramValues := monitoringRequest.Params
|
||||
paramValues.Set("query", NodeStatusRule)
|
||||
params := paramValues.Encode()
|
||||
res := prometheus.SendMonitoringRequest(queryType, params)
|
||||
|
||||
nodeStatusMetric := ReformatJson(res, "node_status", nodeStatusDelLabel...)
|
||||
nodeStatusMetric = ReformatNodeStatusField(nodeStatusMetric)
|
||||
|
||||
var normalNodes []string
|
||||
var abnormalNodes []string
|
||||
for _, result := range nodeStatusMetric.Data.Result {
|
||||
tmap, sure := result[ResultItemMetric].(map[string]interface{})
|
||||
|
||||
if sure {
|
||||
if tmap[MetricStatus].(string) == "false" {
|
||||
abnormalNodes = append(abnormalNodes, tmap[MetricLevelNode].(string))
|
||||
} else {
|
||||
normalNodes = append(normalNodes, tmap[MetricLevelNode].(string))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Components, err := components.GetAllComponentsStatus()
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err.Error())
|
||||
}
|
||||
|
||||
var namespaceComponentHealthyMap = make(map[string]int)
|
||||
var namespaceComponentTotalMap = make(map[string]int)
|
||||
|
||||
for _, ns := range constants.SystemNamespaces {
|
||||
nsStatus, exist := Components[ns]
|
||||
if exist {
|
||||
for _, nsStatusItem := range nsStatus.(map[string]interface{}) {
|
||||
component := nsStatusItem.(models.Component)
|
||||
namespaceComponentTotalMap[ns] += 1
|
||||
if component.HealthyBackends != 0 && component.HealthyBackends == component.TotalBackends {
|
||||
namespaceComponentHealthyMap[ns] += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timestamp := int64(time.Now().Unix())
|
||||
|
||||
onlineMetricItems := makeMetricItems(timestamp, namespaceComponentHealthyMap, MetricLevelNamespace)
|
||||
metricItems := makeMetricItems(timestamp, namespaceComponentTotalMap, MetricLevelNamespace)
|
||||
|
||||
var assembleList []interface{}
|
||||
assembleList = append(assembleList, nodeStatusMetric)
|
||||
|
||||
for _, statusItem := range componentStatusList {
|
||||
assembleList = append(assembleList, statusItem)
|
||||
}
|
||||
|
||||
assembleList = append(assembleList, FormatedMetric{
|
||||
Data: FormatedMetricData{
|
||||
Result: *onlineMetricItems,
|
||||
ResultType: ResultTypeVector,
|
||||
},
|
||||
MetricName: MetricNameComponentOnLine,
|
||||
Status: MetricStatusSuccess,
|
||||
})
|
||||
|
||||
assembleList = append(assembleList, FormatedMetric{
|
||||
Data: FormatedMetricData{
|
||||
Result: *metricItems,
|
||||
ResultType: ResultTypeVector,
|
||||
},
|
||||
MetricName: MetricNameComponentLine,
|
||||
Status: MetricStatusSuccess,
|
||||
})
|
||||
|
||||
return &assembleList
|
||||
}
|
||||
|
||||
func makeMetricItems(timestamp int64, statusMap map[string]int, resourceType string) *[]map[string]interface{} {
|
||||
var metricItems []map[string]interface{}
|
||||
|
||||
for ns, count := range statusMap {
|
||||
metricItems = append(metricItems, map[string]interface{}{
|
||||
ResultItemMetric: map[string]string{resourceType: ns},
|
||||
ResultItemValue: []interface{}{timestamp, fmt.Sprintf("%d", count)},
|
||||
})
|
||||
}
|
||||
return &metricItems
|
||||
}
|
||||
|
||||
func AssembleClusterMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleClusterMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
paramValues := monitoringRequest.Params
|
||||
rule := MakeClusterRule(metricName)
|
||||
@@ -995,10 +867,10 @@ func AssembleClusterMetricRequestInfo(monitoringRequest *prometheus.MonitoringRe
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssembleNodeMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleNodeMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
paramValues := monitoringRequest.Params
|
||||
rule := MakeNodeRule(monitoringRequest.NodeId, monitoringRequest.NodesFilter, metricName)
|
||||
rule := MakeNodeRule(monitoringRequest.NodeId, monitoringRequest.ResourcesFilter, metricName)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
|
||||
return queryType, params
|
||||
|
||||
@@ -318,14 +318,14 @@ var RulePromQLTmplMap = MetricMap{
|
||||
"cluster_disk_read_throughput": "sum(node:data_volume_throughput_bytes_read:sum)",
|
||||
"cluster_disk_write_throughput": "sum(node:data_volume_throughput_bytes_written:sum)",
|
||||
|
||||
"cluster_disk_size_usage": `sum(max((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_utilisation": `1 - sum(max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node)) / sum(max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_capacity": `sum(max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_available": `sum(max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_usage": `sum(max((node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_utilisation": `1 - sum(max(node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node)) / sum(max(node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_capacity": `sum(max(node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_available": `sum(max(node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
|
||||
"cluster_disk_inode_total": `sum(node:disk_inodes_total:)`,
|
||||
"cluster_disk_inode_usage": `sum(node:disk_inodes_total:) - sum(node:disk_inodes_free:)`,
|
||||
"cluster_disk_inode_utilisation": `1 - sum(node:disk_inodes_free:) / sum(node:disk_inodes_total:)`,
|
||||
"cluster_disk_inode_total": `sum(node:node_inodes_total:)`,
|
||||
"cluster_disk_inode_usage": `sum(node:node_inodes_total:) - sum(node:node_inodes_free:)`,
|
||||
"cluster_disk_inode_utilisation": `1 - sum(node:node_inodes_free:) / sum(node:node_inodes_total:)`,
|
||||
|
||||
"cluster_namespace_count": `count(kube_namespace_annotations)`,
|
||||
|
||||
@@ -396,14 +396,14 @@ var RulePromQLTmplMap = MetricMap{
|
||||
"node_disk_read_throughput": "node:data_volume_throughput_bytes_read:sum",
|
||||
"node_disk_write_throughput": "node:data_volume_throughput_bytes_written:sum",
|
||||
|
||||
"node_disk_size_capacity": `max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_available": `max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_usage": `max((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_utilisation": `max(((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) / node_filesystem_size{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_capacity": `max(node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_available": `max(node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_usage": `max((node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_utilisation": `max(((node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"}) / node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
|
||||
"node_disk_inode_total": `node:disk_inodes_total:$1`,
|
||||
"node_disk_inode_usage": `node:disk_inodes_total:$1 - node:disk_inodes_free:$1`,
|
||||
"node_disk_inode_utilisation": `(1 - (node:disk_inodes_free:$1 / node:disk_inodes_total:$1))`,
|
||||
"node_disk_inode_total": `node:node_inodes_total:$1`,
|
||||
"node_disk_inode_usage": `node:node_inodes_total:$1 - node:node_inodes_free:$1`,
|
||||
"node_disk_inode_utilisation": `(1 - (node:node_inodes_free:$1 / node:node_inodes_total:$1))`,
|
||||
|
||||
"node_pod_count": `sum by (node) ((kube_pod_status_scheduled{condition="true"} > 0) * on (namespace, pod) group_left(node) kube_pod_info$1 unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
|
||||
"node_pod_quota": `sum(kube_node_status_capacity_pods$1) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
prom "kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
)
|
||||
|
||||
func GetNamespacesWithMetrics(namespaces []*v1.Namespace) []*v1.Namespace {
|
||||
@@ -34,11 +34,11 @@ func GetNamespacesWithMetrics(namespaces []*v1.Namespace) []*v1.Namespace {
|
||||
nsFilter := "^(" + strings.Join(nsNameList, "|") + ")$"
|
||||
var timeRelateParams = make(url.Values)
|
||||
|
||||
params := prometheus.MonitoringRequestParams{
|
||||
NsFilter: nsFilter,
|
||||
Params: timeRelateParams,
|
||||
QueryType: prometheus.DefaultQueryType,
|
||||
MetricsFilter: "namespace_cpu_usage|namespace_memory_usage_wo_cache|namespace_pod_count",
|
||||
params := prom.MonitoringRequestParams{
|
||||
ResourcesFilter: nsFilter,
|
||||
Params: timeRelateParams,
|
||||
QueryType: prom.DefaultQueryType,
|
||||
MetricsFilter: "namespace_cpu_usage|namespace_memory_usage_wo_cache|namespace_pod_count",
|
||||
}
|
||||
|
||||
rawMetrics := MonitorAllMetrics(¶ms, MetricLevelNamespace)
|
||||
|
||||
@@ -50,7 +50,7 @@ func (wrapper FormatedMetricDataWrapper) Swap(i, j int) {
|
||||
}
|
||||
|
||||
// sorted metric by ascending or descending order
|
||||
func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelMetric, resourceType string) (*FormatedLevelMetric, int) {
|
||||
func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelMetric) (*FormatedLevelMetric, int) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
glog.Errorln(err)
|
||||
@@ -83,8 +83,8 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
v1, _ := strconv.ParseFloat(value1[len(value1)-1].(string), 64)
|
||||
v2, _ := strconv.ParseFloat(value2[len(value2)-1].(string), 64)
|
||||
if v1 == v2 {
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
return resourceName1.(string) < resourceName2.(string)
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
v2, _ := strconv.ParseFloat(value2[len(value2)-1].(string), 64)
|
||||
|
||||
if v1 == v2 {
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
return resourceName1.(string) > resourceName2.(string)
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
for _, r := range metricItem.Data.Result {
|
||||
// for some reasons, 'metric' may not contain `resourceType` field
|
||||
// example: {"metric":{},"value":[1541142931.731,"3"]}
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
key := k.(string)
|
||||
if exist {
|
||||
if _, exist := indexMap[key]; !exist {
|
||||
@@ -125,7 +125,7 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
|
||||
// iterator all metric to find max metricItems length
|
||||
for _, r := range metricItem.Data.Result {
|
||||
k, ok := r[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
k, ok := r[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
if ok {
|
||||
currentResourceMap[k.(string)] = 1
|
||||
}
|
||||
@@ -154,7 +154,7 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
sortedMetric := make([]map[string]interface{}, len(indexMap))
|
||||
for j := 0; j < len(re.Data.Result); j++ {
|
||||
r := re.Data.Result[j]
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
if exist {
|
||||
index, exist := indexMap[k.(string)]
|
||||
if exist {
|
||||
@@ -176,7 +176,7 @@ func Page(pageNum string, limitNum string, fmtLevelMetric *FormatedLevelMetric,
|
||||
}
|
||||
// matrix type can not be sorted
|
||||
for _, metricItem := range fmtLevelMetric.Results {
|
||||
// if metric reterieved field, resultType is ""
|
||||
// if metric reterieved field, resultType: ""
|
||||
if metricItem.Data.ResultType == ResultTypeMatrix {
|
||||
return fmtLevelMetric
|
||||
}
|
||||
@@ -251,7 +251,7 @@ func Page(pageNum string, limitNum string, fmtLevelMetric *FormatedLevelMetric,
|
||||
}
|
||||
|
||||
// maybe this function is time consuming
|
||||
func ReformatJson(metric string, metricsName string, needDelParams ...string) *FormatedMetric {
|
||||
func ReformatJson(metric string, metricsName string, needAddParams map[string]string, needDelParams ...string) *FormatedMetric {
|
||||
var formatMetric FormatedMetric
|
||||
|
||||
err := jsonIter.Unmarshal([]byte(metric), &formatMetric)
|
||||
@@ -277,6 +277,17 @@ func ReformatJson(metric string, metricsName string, needDelParams ...string) *F
|
||||
delete(metricMap, p)
|
||||
}
|
||||
}
|
||||
|
||||
if needAddParams != nil && len(needAddParams) > 0 {
|
||||
for n := range needAddParams {
|
||||
if v, ok := metricMap[n]; ok {
|
||||
delete(metricMap, n)
|
||||
metricMap["resource_name"] = v
|
||||
} else {
|
||||
metricMap["resource_name"] = needAddParams[n]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,14 @@ func init() {
|
||||
namespacedResources[StatefulSets] = &statefulSetSearcher{}
|
||||
namespacedResources[Pods] = &podSearcher{}
|
||||
namespacedResources[Roles] = &roleSearcher{}
|
||||
namespacedResources[S2iBuilders] = &s2iBuilderSearcher{}
|
||||
namespacedResources[S2iRuns] = &s2iRunSearcher{}
|
||||
|
||||
clusterResources[Nodes] = &nodeSearcher{}
|
||||
clusterResources[Namespaces] = &namespaceSearcher{}
|
||||
clusterResources[ClusterRoles] = &clusterRoleSearcher{}
|
||||
clusterResources[StorageClasses] = &storageClassesSearcher{}
|
||||
clusterResources[S2iBuilderTemplates] = &s2iBuilderTemplateSearcher{}
|
||||
}
|
||||
|
||||
var namespacedResources = make(map[string]namespacedSearcherInterface)
|
||||
@@ -82,6 +85,9 @@ const (
|
||||
Namespaces = "namespaces"
|
||||
StorageClasses = "storageclasses"
|
||||
ClusterRoles = "clusterroles"
|
||||
S2iBuilderTemplates = "s2ibuildertemplates"
|
||||
S2iBuilders = "s2ibuilders"
|
||||
S2iRuns = "s2iruns"
|
||||
)
|
||||
|
||||
type namespacedSearcherInterface interface {
|
||||
|
||||
125
pkg/models/resources/s2ibuilder.go
Normal file
125
pkg/models/resources/s2ibuilder.go
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 resources
|
||||
|
||||
import (
|
||||
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type s2iBuilderSearcher struct {
|
||||
}
|
||||
|
||||
// exactly Match
|
||||
func (*s2iBuilderSearcher) match(match map[string]string, item *v1alpha1.S2iBuilder) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Fuzzy searchInNamespace
|
||||
func (*s2iBuilderSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iBuilder) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*s2iBuilderSearcher) compare(a, b *v1alpha1.S2iBuilder, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *s2iBuilderSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
s2iBuilders, err := informers.S2iSharedInformerFactory().Devops().V1alpha1().S2iBuilders().Lister().S2iBuilders(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1alpha1.S2iBuilder, 0)
|
||||
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = s2iBuilders
|
||||
} else {
|
||||
for _, item := range s2iBuilders {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
121
pkg/models/resources/s2ibuildertemplate.go
Normal file
121
pkg/models/resources/s2ibuildertemplate.go
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 resources
|
||||
|
||||
import (
|
||||
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type s2iBuilderTemplateSearcher struct {
|
||||
}
|
||||
|
||||
// exactly Match
|
||||
func (*s2iBuilderTemplateSearcher) match(match map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Fuzzy searchInNamespace
|
||||
func (*s2iBuilderTemplateSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*s2iBuilderTemplateSearcher) compare(a, b *v1alpha1.S2iBuilderTemplate, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *s2iBuilderTemplateSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
builderTemplates, err := informers.S2iSharedInformerFactory().Devops().V1alpha1().S2iBuilderTemplates().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1alpha1.S2iBuilderTemplate, 0)
|
||||
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = builderTemplates
|
||||
} else {
|
||||
for _, item := range builderTemplates {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
132
pkg/models/resources/s2irun.go
Normal file
132
pkg/models/resources/s2irun.go
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 resources
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
|
||||
)
|
||||
|
||||
type s2iRunSearcher struct {
|
||||
}
|
||||
|
||||
// exactly Match
|
||||
func (*s2iRunSearcher) match(match map[string]string, item *v1alpha1.S2iRun) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
case status:
|
||||
if string(item.Status.RunState) != v{
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Fuzzy searchInNamespace
|
||||
func (*s2iRunSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iRun) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*s2iRunSearcher) compare(a, b *v1alpha1.S2iRun, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *s2iRunSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
s2iRuns, err := informers.S2iSharedInformerFactory().Devops().V1alpha1().S2iRuns().Lister().S2iRuns(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1alpha1.S2iRun, 0)
|
||||
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = s2iRuns
|
||||
} else {
|
||||
for _, item := range s2iRuns {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
69
pkg/models/servicemesh/application.go
Normal file
69
pkg/models/servicemesh/application.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package servicemesh
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
AppLabel = "app"
|
||||
VersionLabel = "version"
|
||||
ApplicationNameLabel = "app.kubernetes.io/name"
|
||||
ApplicationVersionLabel = "app.kubernetes.io/version"
|
||||
)
|
||||
|
||||
var ApplicationLabels = [...]string{
|
||||
ApplicationNameLabel,
|
||||
ApplicationVersionLabel,
|
||||
AppLabel,
|
||||
}
|
||||
|
||||
var TrimChars = [...]string{".", "_", "-"}
|
||||
|
||||
// normalize version names
|
||||
// strip [_.-]
|
||||
func NormalizeVersionName(version string) string {
|
||||
for _, char := range TrimChars {
|
||||
version = strings.ReplaceAll(version, char, "")
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
||||
func GetComponentName(meta *metav1.ObjectMeta) string {
|
||||
if len(meta.Labels[AppLabel]) > 0 {
|
||||
return meta.Labels[AppLabel]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetComponentVersion(meta *metav1.ObjectMeta) string {
|
||||
if len(meta.Labels[VersionLabel]) > 0 {
|
||||
return meta.Labels[VersionLabel]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func ExtractApplicationLabels(meta *metav1.ObjectMeta) map[string]string {
|
||||
|
||||
labels := make(map[string]string, 0)
|
||||
for _, label := range ApplicationLabels {
|
||||
if len(meta.Labels[label]) == 0 {
|
||||
return nil
|
||||
} else {
|
||||
labels[label] = meta.Labels[label]
|
||||
}
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
func IsApplicationComponent(meta *metav1.ObjectMeta) bool {
|
||||
|
||||
for _, label := range ApplicationLabels {
|
||||
if len(meta.Labels[label]) == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
639
pkg/simple/client/elasticsearch/esclient.go
Normal file
639
pkg/simple/client/elasticsearch/esclient.go
Normal file
@@ -0,0 +1,639 @@
|
||||
/*
|
||||
Copyright 2018 The KubeSphere 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 esclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
var jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
var (
|
||||
mu sync.RWMutex
|
||||
esConfigs *ESConfigs
|
||||
)
|
||||
|
||||
type ESConfigs struct {
|
||||
Host string
|
||||
Port string
|
||||
Index string
|
||||
}
|
||||
|
||||
func readESConfigs() *ESConfigs {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
|
||||
return esConfigs
|
||||
}
|
||||
|
||||
func (configs *ESConfigs) WriteESConfigs() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
esConfigs = configs
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
From int64 `json:"from"`
|
||||
Size int64 `json:"size"`
|
||||
Sorts []Sort `json:"sort,omitempty"`
|
||||
MainQuery MainQuery `json:"query"`
|
||||
Aggs interface{} `json:"aggs,omitempty"`
|
||||
MainHighLight MainHighLight `json:"highlight,omitempty"`
|
||||
}
|
||||
|
||||
type Sort struct {
|
||||
Order Order `json:"time"`
|
||||
}
|
||||
|
||||
type Order struct {
|
||||
Order string `json:"order"`
|
||||
}
|
||||
|
||||
type MainQuery struct {
|
||||
MainBoolQuery MainBoolQuery `json:"bool"`
|
||||
}
|
||||
|
||||
type MainBoolQuery struct {
|
||||
MainFilter MainFilter `json:"filter"`
|
||||
}
|
||||
|
||||
type MainFilter struct {
|
||||
FilterBoolQuery FilterBoolQuery `json:"bool"`
|
||||
}
|
||||
|
||||
type FilterBoolQuery struct {
|
||||
Musts []interface{} `json:"must"`
|
||||
}
|
||||
|
||||
type RangeQuery struct {
|
||||
RangeSpec RangeSpec `json:"range"`
|
||||
}
|
||||
|
||||
type RangeSpec struct {
|
||||
TimeRange TimeRange `json:"time"`
|
||||
}
|
||||
|
||||
type TimeRange struct {
|
||||
Gte string `json:"gte,omitempty"`
|
||||
Lte string `json:"lte,omitempty"`
|
||||
}
|
||||
|
||||
type BoolShouldMatchPhrase struct {
|
||||
ShouldMatchPhrase ShouldMatchPhrase `json:"bool"`
|
||||
}
|
||||
|
||||
type ShouldMatchPhrase struct {
|
||||
Shoulds []interface{} `json:"should"`
|
||||
MinimumShouldMatch int64 `json:"minimum_should_match"`
|
||||
}
|
||||
|
||||
type MatchPhrase struct {
|
||||
MatchPhrase interface{} `json:"match_phrase"`
|
||||
}
|
||||
|
||||
type Match struct {
|
||||
Match interface{} `json:"match"`
|
||||
}
|
||||
|
||||
type QueryWord struct {
|
||||
Word string `json:"query"`
|
||||
}
|
||||
|
||||
type MainHighLight struct {
|
||||
Fields []interface{} `json:"fields,omitempty"`
|
||||
}
|
||||
|
||||
type LogHighLightField struct {
|
||||
FieldContent EmptyField `json:"log"`
|
||||
}
|
||||
|
||||
type NamespaceHighLightField struct {
|
||||
FieldContent EmptyField `json:"kubernetes.namespace_name.keyword"`
|
||||
}
|
||||
|
||||
type PodHighLightField struct {
|
||||
FieldContent EmptyField `json:"kubernetes.pod_name.keyword"`
|
||||
}
|
||||
|
||||
type ContainerHighLightField struct {
|
||||
FieldContent EmptyField `json:"kubernetes.container_name.keyword"`
|
||||
}
|
||||
|
||||
type EmptyField struct {
|
||||
}
|
||||
|
||||
type StatisticsAggs struct {
|
||||
NamespaceAgg NamespaceAgg `json:"Namespace"`
|
||||
}
|
||||
|
||||
type NamespaceAgg struct {
|
||||
Terms StatisticsAggTerm `json:"terms"`
|
||||
ContainerAggs ContainerAggs `json:"aggs"`
|
||||
}
|
||||
|
||||
type ContainerAggs struct {
|
||||
ContainerAgg ContainerAgg `json:"Container"`
|
||||
}
|
||||
|
||||
type ContainerAgg struct {
|
||||
Terms StatisticsAggTerm `json:"terms"`
|
||||
}
|
||||
|
||||
type StatisticsAggTerm struct {
|
||||
Field string `json:"field"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
type HistogramAggs struct {
|
||||
HistogramAgg HistogramAgg `json:"histogram"`
|
||||
}
|
||||
|
||||
type HistogramAgg struct {
|
||||
DateHistogram DateHistogram `json:"date_histogram"`
|
||||
}
|
||||
|
||||
type DateHistogram struct {
|
||||
Field string `json:"field"`
|
||||
Interval string `json:"interval"`
|
||||
}
|
||||
|
||||
func createQueryRequest(param QueryParameters) (int, []byte, error) {
|
||||
var request Request
|
||||
var mainBoolQuery MainBoolQuery
|
||||
|
||||
if param.NamespaceFilled {
|
||||
var shouldMatchPhrase ShouldMatchPhrase
|
||||
if len(param.Namespaces) == 0 {
|
||||
matchPhrase := MatchPhrase{map[string]interface{}{"kubernetes.namespace_name.key_word": QueryWord{""}}}
|
||||
shouldMatchPhrase.Shoulds = append(shouldMatchPhrase.Shoulds, matchPhrase)
|
||||
} else {
|
||||
for _, namespace := range param.Namespaces {
|
||||
matchPhrase := MatchPhrase{map[string]interface{}{"kubernetes.namespace_name.keyword": QueryWord{namespace}}}
|
||||
shouldMatchPhrase.Shoulds = append(shouldMatchPhrase.Shoulds, matchPhrase)
|
||||
}
|
||||
}
|
||||
shouldMatchPhrase.MinimumShouldMatch = 1
|
||||
mainBoolQuery.MainFilter.FilterBoolQuery.Musts = append(mainBoolQuery.MainFilter.FilterBoolQuery.Musts, BoolShouldMatchPhrase{shouldMatchPhrase})
|
||||
}
|
||||
if param.PodFilled {
|
||||
var shouldMatchPhrase ShouldMatchPhrase
|
||||
if len(param.Pods) == 0 {
|
||||
matchPhrase := MatchPhrase{map[string]interface{}{"kubernetes.pod_name.key_word": QueryWord{""}}}
|
||||
shouldMatchPhrase.Shoulds = append(shouldMatchPhrase.Shoulds, matchPhrase)
|
||||
} else {
|
||||
for _, pod := range param.Pods {
|
||||
matchPhrase := MatchPhrase{map[string]interface{}{"kubernetes.pod_name.keyword": QueryWord{pod}}}
|
||||
shouldMatchPhrase.Shoulds = append(shouldMatchPhrase.Shoulds, matchPhrase)
|
||||
}
|
||||
}
|
||||
shouldMatchPhrase.MinimumShouldMatch = 1
|
||||
mainBoolQuery.MainFilter.FilterBoolQuery.Musts = append(mainBoolQuery.MainFilter.FilterBoolQuery.Musts, BoolShouldMatchPhrase{shouldMatchPhrase})
|
||||
}
|
||||
if param.ContainerFilled {
|
||||
var shouldMatchPhrase ShouldMatchPhrase
|
||||
if len(param.Containers) == 0 {
|
||||
matchPhrase := MatchPhrase{map[string]interface{}{"kubernetes.container_name.key_word": QueryWord{""}}}
|
||||
shouldMatchPhrase.Shoulds = append(shouldMatchPhrase.Shoulds, matchPhrase)
|
||||
} else {
|
||||
for _, container := range param.Containers {
|
||||
matchPhrase := MatchPhrase{map[string]interface{}{"kubernetes.container_name.keyword": QueryWord{container}}}
|
||||
shouldMatchPhrase.Shoulds = append(shouldMatchPhrase.Shoulds, matchPhrase)
|
||||
}
|
||||
}
|
||||
shouldMatchPhrase.MinimumShouldMatch = 1
|
||||
mainBoolQuery.MainFilter.FilterBoolQuery.Musts = append(mainBoolQuery.MainFilter.FilterBoolQuery.Musts, BoolShouldMatchPhrase{shouldMatchPhrase})
|
||||
}
|
||||
|
||||
if param.NamespaceQuery != "" {
|
||||
match := Match{map[string]interface{}{"kubernetes.namespace_name": QueryWord{param.NamespaceQuery}}}
|
||||
mainBoolQuery.MainFilter.FilterBoolQuery.Musts = append(mainBoolQuery.MainFilter.FilterBoolQuery.Musts, match)
|
||||
}
|
||||
if param.PodQuery != "" {
|
||||
match := Match{map[string]interface{}{"kubernetes.pod_name": QueryWord{param.PodQuery}}}
|
||||
mainBoolQuery.MainFilter.FilterBoolQuery.Musts = append(mainBoolQuery.MainFilter.FilterBoolQuery.Musts, match)
|
||||
}
|
||||
if param.ContainerQuery != "" {
|
||||
match := Match{map[string]interface{}{"kubernetes.container_name": QueryWord{param.ContainerQuery}}}
|
||||
mainBoolQuery.MainFilter.FilterBoolQuery.Musts = append(mainBoolQuery.MainFilter.FilterBoolQuery.Musts, match)
|
||||
}
|
||||
|
||||
if param.LogQuery != "" {
|
||||
match := Match{map[string]interface{}{"log": QueryWord{param.LogQuery}}}
|
||||
mainBoolQuery.MainFilter.FilterBoolQuery.Musts = append(mainBoolQuery.MainFilter.FilterBoolQuery.Musts, match)
|
||||
}
|
||||
|
||||
rangeQuery := RangeQuery{RangeSpec{TimeRange{param.StartTime, param.EndTime}}}
|
||||
mainBoolQuery.MainFilter.FilterBoolQuery.Musts = append(mainBoolQuery.MainFilter.FilterBoolQuery.Musts, rangeQuery)
|
||||
|
||||
var operation int
|
||||
|
||||
if param.Operation == "statistics" {
|
||||
operation = OperationStatistics
|
||||
containerAggs := ContainerAggs{ContainerAgg{StatisticsAggTerm{"kubernetes.container_name.keyword", 2147483647}}}
|
||||
namespaceAgg := NamespaceAgg{StatisticsAggTerm{"kubernetes.namespace_name.keyword", 2147483647}, containerAggs}
|
||||
request.Aggs = StatisticsAggs{namespaceAgg}
|
||||
request.Size = 0
|
||||
} else if param.Operation == "histogram" {
|
||||
operation = OperationHistogram
|
||||
var interval string
|
||||
if param.Interval != "" {
|
||||
interval = param.Interval
|
||||
} else {
|
||||
interval = "15m"
|
||||
}
|
||||
param.Interval = interval
|
||||
request.Aggs = HistogramAggs{HistogramAgg{DateHistogram{"time", interval}}}
|
||||
request.Size = 0
|
||||
} else {
|
||||
operation = OperationQuery
|
||||
request.From = param.From
|
||||
request.Size = param.Size
|
||||
var order string
|
||||
if strings.Compare(strings.ToLower(param.Sort), "asc") == 0 {
|
||||
order = "asc"
|
||||
} else {
|
||||
order = "desc"
|
||||
}
|
||||
request.Sorts = append(request.Sorts, Sort{Order{order}})
|
||||
|
||||
var mainHighLight MainHighLight
|
||||
mainHighLight.Fields = append(mainHighLight.Fields, LogHighLightField{})
|
||||
mainHighLight.Fields = append(mainHighLight.Fields, NamespaceHighLightField{})
|
||||
mainHighLight.Fields = append(mainHighLight.Fields, PodHighLightField{})
|
||||
mainHighLight.Fields = append(mainHighLight.Fields, ContainerHighLightField{})
|
||||
request.MainHighLight = mainHighLight
|
||||
}
|
||||
|
||||
request.MainQuery = MainQuery{mainBoolQuery}
|
||||
|
||||
queryRequest, err := json.Marshal(request)
|
||||
|
||||
return operation, queryRequest, err
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Status int `json:"status"`
|
||||
Workspace string `json:"workspace,omitempty"`
|
||||
Shards Shards `json:"_shards"`
|
||||
Hits Hits `json:"hits"`
|
||||
Aggregations json.RawMessage `json:"aggregations"`
|
||||
}
|
||||
|
||||
type Shards struct {
|
||||
Total int64 `json:"total"`
|
||||
Successful int64 `json:"successful"`
|
||||
Skipped int64 `json:"skipped"`
|
||||
Failed int64 `json:"failed"`
|
||||
}
|
||||
|
||||
type Hits struct {
|
||||
Total int64 `json:"total"`
|
||||
Hits []Hit `json:"hits"`
|
||||
}
|
||||
|
||||
type Hit struct {
|
||||
Source Source `json:"_source"`
|
||||
HighLight HighLight `json:"highlight"`
|
||||
}
|
||||
|
||||
type Source struct {
|
||||
Log string `json:"log"`
|
||||
Time string `json:"time"`
|
||||
Kubernetes Kubernetes `json:"kubernetes"`
|
||||
}
|
||||
|
||||
type Kubernetes struct {
|
||||
Namespace string `json:"namespace_name"`
|
||||
Pod string `json:"pod_name"`
|
||||
Container string `json:"container_name"`
|
||||
Host string `json:"host"`
|
||||
}
|
||||
|
||||
type HighLight struct {
|
||||
LogHighLights []string `json:"log,omitempty"`
|
||||
NamespaceHighLights []string `json:"kubernetes.namespace_name.keyword,omitempty"`
|
||||
PodHighLights []string `json:"kubernetes.pod_name.keyword,omitempty"`
|
||||
ContainerHighLights []string `json:"kubernetes.container_name.keyword,omitempty"`
|
||||
}
|
||||
|
||||
type LogRecord struct {
|
||||
Time int64 `json:"time,omitempty"`
|
||||
Log string `json:"log,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
Pod string `json:"pod,omitempty"`
|
||||
Container string `json:"container,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
HighLight HighLight `json:"highlight,omitempty"`
|
||||
}
|
||||
|
||||
type ReadResult struct {
|
||||
Total int64 `json:"total"`
|
||||
From int64 `json:"from"`
|
||||
Size int64 `json:"size"`
|
||||
Records []LogRecord `json:"records,omitempty"`
|
||||
}
|
||||
|
||||
type NamespaceAggregations struct {
|
||||
NamespaceAggregation NamespaceAggregation `json:"Namespace"`
|
||||
}
|
||||
|
||||
type NamespaceAggregation struct {
|
||||
Namespaces []NamespaceStatistics `json:"buckets"`
|
||||
}
|
||||
|
||||
type NamespaceStatistics struct {
|
||||
Namespace string `json:"Key"`
|
||||
Count int64 `json:"doc_count"`
|
||||
ContainerAggregation ContainerAggregation `json:"Container"`
|
||||
}
|
||||
|
||||
type ContainerAggregation struct {
|
||||
Containers []ContainerStatistics `json:"buckets"`
|
||||
}
|
||||
|
||||
type ContainerStatistics struct {
|
||||
Container string `json:"Key"`
|
||||
Count int64 `json:"doc_count"`
|
||||
}
|
||||
|
||||
type NamespaceResult struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Count int64 `json:"count"`
|
||||
Containers []ContainerResult `json:"containers"`
|
||||
}
|
||||
|
||||
type ContainerResult struct {
|
||||
Container string `json:"container"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
type StatisticsResult struct {
|
||||
Total int64 `json:"total"`
|
||||
Namespaces []NamespaceResult `json:"namespaces"`
|
||||
}
|
||||
|
||||
type HistogramAggregations struct {
|
||||
HistogramAggregation HistogramAggregation `json:"histogram"`
|
||||
}
|
||||
|
||||
type HistogramAggregation struct {
|
||||
Histograms []HistogramStatistics `json:"buckets"`
|
||||
}
|
||||
|
||||
type HistogramStatistics struct {
|
||||
Time int64 `json:"key"`
|
||||
Count int64 `json:"doc_count"`
|
||||
}
|
||||
|
||||
type HistogramRecord struct {
|
||||
Time int64 `json:"time"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
type HistogramResult struct {
|
||||
Total int64 `json:"total"`
|
||||
StartTime int64 `json:"start_time"`
|
||||
EndTime int64 `json:"end_time"`
|
||||
Interval string `json:"interval"`
|
||||
Histograms []HistogramRecord `json:"histograms"`
|
||||
}
|
||||
|
||||
type QueryResult struct {
|
||||
Status int `json:"status,omitempty"`
|
||||
Workspace string `json:"workspace,omitempty"`
|
||||
Read *ReadResult `json:"query,omitempty"`
|
||||
Statistics *StatisticsResult `json:"statistics,omitempty"`
|
||||
Histogram *HistogramResult `json:"histogram,omitempty"`
|
||||
Request string `json:"request,omitempty"`
|
||||
Response string `json:"response,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
OperationQuery int = iota
|
||||
OperationStatistics
|
||||
OperationHistogram
|
||||
)
|
||||
|
||||
func calcTimestamp(input string) int64 {
|
||||
var t time.Time
|
||||
var err error
|
||||
var ret int64
|
||||
|
||||
ret = 0
|
||||
|
||||
t, err = time.Parse(time.RFC3339, input)
|
||||
if err != nil {
|
||||
var i int64
|
||||
i, err = strconv.ParseInt(input, 10, 64)
|
||||
if err == nil {
|
||||
ret = time.Unix(i/1000, (i%1000)*1000000).UnixNano() / 1000000
|
||||
}
|
||||
} else {
|
||||
ret = t.UnixNano() / 1000000
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func parseQueryResult(operation int, param QueryParameters, body []byte, query []byte) *QueryResult {
|
||||
var queryResult QueryResult
|
||||
//queryResult.Request = string(query)
|
||||
//queryResult.Response = string(body)
|
||||
|
||||
var response Response
|
||||
err := jsonIter.Unmarshal(body, &response)
|
||||
if err != nil {
|
||||
//fmt.Println("Parse response error ", err.Error())
|
||||
queryResult.Status = http.StatusNotFound
|
||||
return &queryResult
|
||||
}
|
||||
|
||||
if response.Status != 0 {
|
||||
//Elastic error, eg, es_rejected_execute_exception
|
||||
queryResult.Status = response.Status
|
||||
return &queryResult
|
||||
}
|
||||
|
||||
if response.Shards.Successful != response.Shards.Total {
|
||||
//Elastic some shards error
|
||||
queryResult.Status = http.StatusInternalServerError
|
||||
return &queryResult
|
||||
}
|
||||
|
||||
switch operation {
|
||||
case OperationQuery:
|
||||
var readResult ReadResult
|
||||
readResult.Total = response.Hits.Total
|
||||
readResult.From = param.From
|
||||
readResult.Size = param.Size
|
||||
for _, hit := range response.Hits.Hits {
|
||||
var logRecord LogRecord
|
||||
logRecord.Time = calcTimestamp(hit.Source.Time)
|
||||
logRecord.Log = hit.Source.Log
|
||||
logRecord.Namespace = hit.Source.Kubernetes.Namespace
|
||||
logRecord.Pod = hit.Source.Kubernetes.Pod
|
||||
logRecord.Container = hit.Source.Kubernetes.Container
|
||||
logRecord.Host = hit.Source.Kubernetes.Host
|
||||
logRecord.HighLight = hit.HighLight
|
||||
readResult.Records = append(readResult.Records, logRecord)
|
||||
}
|
||||
queryResult.Read = &readResult
|
||||
|
||||
case OperationStatistics:
|
||||
var statisticsResult StatisticsResult
|
||||
statisticsResult.Total = response.Hits.Total
|
||||
|
||||
var namespaceAggregations NamespaceAggregations
|
||||
jsonIter.Unmarshal(response.Aggregations, &namespaceAggregations)
|
||||
|
||||
for _, namespace := range namespaceAggregations.NamespaceAggregation.Namespaces {
|
||||
var namespaceResult NamespaceResult
|
||||
namespaceResult.Namespace = namespace.Namespace
|
||||
namespaceResult.Count = namespace.Count
|
||||
|
||||
for _, container := range namespace.ContainerAggregation.Containers {
|
||||
var containerResult ContainerResult
|
||||
containerResult.Container = container.Container
|
||||
containerResult.Count = container.Count
|
||||
namespaceResult.Containers = append(namespaceResult.Containers, containerResult)
|
||||
}
|
||||
|
||||
statisticsResult.Namespaces = append(statisticsResult.Namespaces, namespaceResult)
|
||||
}
|
||||
|
||||
queryResult.Statistics = &statisticsResult
|
||||
|
||||
case OperationHistogram:
|
||||
var histogramResult HistogramResult
|
||||
histogramResult.Total = response.Hits.Total
|
||||
histogramResult.StartTime = calcTimestamp(param.StartTime)
|
||||
histogramResult.EndTime = calcTimestamp(param.EndTime)
|
||||
histogramResult.Interval = param.Interval
|
||||
|
||||
var histogramAggregations HistogramAggregations
|
||||
jsonIter.Unmarshal(response.Aggregations, &histogramAggregations)
|
||||
for _, histogram := range histogramAggregations.HistogramAggregation.Histograms {
|
||||
var histogramRecord HistogramRecord
|
||||
histogramRecord.Time = histogram.Time
|
||||
histogramRecord.Count = histogram.Count
|
||||
|
||||
histogramResult.Histograms = append(histogramResult.Histograms, histogramRecord)
|
||||
}
|
||||
|
||||
queryResult.Histogram = &histogramResult
|
||||
}
|
||||
|
||||
queryResult.Status = http.StatusOK
|
||||
queryResult.Workspace = param.Workspace
|
||||
|
||||
return &queryResult
|
||||
}
|
||||
|
||||
type QueryParameters struct {
|
||||
NamespaceFilled bool
|
||||
Namespaces []string
|
||||
PodFilled bool
|
||||
Pods []string
|
||||
ContainerFilled bool
|
||||
Containers []string
|
||||
|
||||
NamespaceQuery string
|
||||
PodQuery string
|
||||
ContainerQuery string
|
||||
|
||||
Workspace string
|
||||
|
||||
Operation string
|
||||
LogQuery string
|
||||
Interval string
|
||||
StartTime string
|
||||
EndTime string
|
||||
Sort string
|
||||
From int64
|
||||
Size int64
|
||||
}
|
||||
|
||||
func stubResult() *QueryResult {
|
||||
var queryResult QueryResult
|
||||
|
||||
queryResult.Status = http.StatusOK
|
||||
|
||||
return &queryResult
|
||||
}
|
||||
|
||||
func Query(param QueryParameters) *QueryResult {
|
||||
var queryResult *QueryResult
|
||||
|
||||
//queryResult = stubResult()
|
||||
//return queryResult
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
operation, query, err := createQueryRequest(param)
|
||||
if err != nil {
|
||||
//fmt.Println("Create query error ", err.Error())
|
||||
queryResult = new(QueryResult)
|
||||
queryResult.Status = http.StatusNotFound
|
||||
return queryResult
|
||||
}
|
||||
|
||||
es := readESConfigs()
|
||||
if es == nil {
|
||||
queryResult = new(QueryResult)
|
||||
queryResult.Status = http.StatusNotFound
|
||||
return queryResult
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s:%s/%s*/_search", es.Host, es.Port, es.Index)
|
||||
request, err := http.NewRequest("GET", url, bytes.NewBuffer(query))
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
queryResult = new(QueryResult)
|
||||
queryResult.Status = http.StatusNotFound
|
||||
return queryResult
|
||||
}
|
||||
request.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
queryResult = new(QueryResult)
|
||||
queryResult.Status = http.StatusNotFound
|
||||
return queryResult
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
queryResult = new(QueryResult)
|
||||
queryResult.Status = http.StatusNotFound
|
||||
return queryResult
|
||||
}
|
||||
|
||||
queryResult = parseQueryResult(operation, param, body, query)
|
||||
|
||||
return queryResult
|
||||
}
|
||||
289
pkg/simple/client/fluentbit/fluentbitcrdclient.go
Normal file
289
pkg/simple/client/fluentbit/fluentbitcrdclient.go
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
Copyright 2018 The KubeSphere 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 fluentbitclient
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
CRDPlural string = "fluentbits"
|
||||
CRDGroup string = "logging.kubesphere.io"
|
||||
CRDVersion string = "v1alpha1"
|
||||
FullCRDName string = CRDPlural + "." + CRDGroup
|
||||
)
|
||||
|
||||
// FluentBitList auto generated by the sdk
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type FluentBitList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
Items []FluentBit `json:"items"`
|
||||
}
|
||||
|
||||
// FluentBit auto generated by the sdk
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type FluentBit struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
Spec FluentBitSpec `json:"spec"`
|
||||
Status FluentBitStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// FluentBitSpec holds the spec for the operator
|
||||
type FluentBitSpec struct {
|
||||
Service []Plugin `json:"service"`
|
||||
Input []Plugin `json:"input"`
|
||||
Filter []Plugin `json:"filter"`
|
||||
Output []Plugin `json:"output"`
|
||||
Settings []Plugin `json:"settings"`
|
||||
}
|
||||
|
||||
// FluentBitStatus holds the status info for the operator
|
||||
type FluentBitStatus struct {
|
||||
// Fill me
|
||||
}
|
||||
|
||||
// Plugin struct for fluent-bit plugins
|
||||
type Plugin struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Parameters []Parameter `json:"parameters"`
|
||||
}
|
||||
|
||||
// Fluent-bit output plugins
|
||||
type OutputPlugin struct {
|
||||
Plugin
|
||||
Id string `json:"id"`
|
||||
Enable bool `json:"enable"`
|
||||
Updatetime time.Time `json:"updatetime,omitempty"`
|
||||
}
|
||||
|
||||
// Parameter generic parameter type to handle values from different sources
|
||||
type Parameter struct {
|
||||
Name string `json:"name"`
|
||||
ValueFrom *ValueFrom `json:"valueFrom,omitempty"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// ValueFrom generic type to determine value origin
|
||||
type ValueFrom struct {
|
||||
SecretKeyRef KubernetesSecret `json:"secretKeyRef"`
|
||||
}
|
||||
|
||||
// KubernetesSecret is a ValueFrom type
|
||||
type KubernetesSecret struct {
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *FluentBit) DeepCopyInto(out *FluentBit) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
out.Spec = in.Spec
|
||||
out.Status = in.Status
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FluentBit.
|
||||
func (in *FluentBit) DeepCopy() *FluentBit {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FluentBit)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *FluentBit) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *FluentBitList) DeepCopyInto(out *FluentBitList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]FluentBit, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FluentBitList.
|
||||
func (in *FluentBitList) DeepCopy() *FluentBitList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FluentBitList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *FluentBitList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *FluentBitSpec) DeepCopyInto(out *FluentBitSpec) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FluentBitSpec.
|
||||
func (in *FluentBitSpec) DeepCopy() *FluentBitSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FluentBitSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *FluentBitStatus) DeepCopyInto(out *FluentBitStatus) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FluentBitStatus.
|
||||
func (in *FluentBitStatus) DeepCopy() *FluentBitStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FluentBitStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// Create a Rest client with the new CRD Schema
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: CRDGroup, Version: CRDVersion}
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&FluentBit{},
|
||||
&FluentBitList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewFluentbitCRDClient(cfg *rest.Config) (*rest.RESTClient, *runtime.Scheme, error) {
|
||||
scheme := runtime.NewScheme()
|
||||
SchemeBuilder := runtime.NewSchemeBuilder(addKnownTypes)
|
||||
if err := SchemeBuilder.AddToScheme(scheme); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
config := *cfg
|
||||
config.GroupVersion = &SchemeGroupVersion
|
||||
config.APIPath = "/apis"
|
||||
config.ContentType = runtime.ContentTypeJSON
|
||||
config.NegotiatedSerializer = serializer.DirectCodecFactory{
|
||||
CodecFactory: serializer.NewCodecFactory(scheme)}
|
||||
|
||||
client, err := rest.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return client, scheme, nil
|
||||
}
|
||||
|
||||
// This file implement all the (CRUD) client methods we need to access our CRD object
|
||||
|
||||
func CrdClient(cl *rest.RESTClient, scheme *runtime.Scheme, namespace string) *crdclient {
|
||||
return &crdclient{cl: cl, ns: namespace, plural: CRDPlural,
|
||||
codec: runtime.NewParameterCodec(scheme)}
|
||||
}
|
||||
|
||||
type crdclient struct {
|
||||
cl *rest.RESTClient
|
||||
ns string
|
||||
plural string
|
||||
codec runtime.ParameterCodec
|
||||
}
|
||||
|
||||
func (f *crdclient) Create(obj *FluentBit) (*FluentBit, error) {
|
||||
var result FluentBit
|
||||
err := f.cl.Post().
|
||||
Namespace(f.ns).Resource(f.plural).
|
||||
Body(obj).Do().Into(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (f *crdclient) Update(name string, obj *FluentBit) (*FluentBit, error) {
|
||||
var result FluentBit
|
||||
err := f.cl.Put().
|
||||
Namespace(f.ns).Resource(f.plural).
|
||||
Name(name).Body(obj).Do().Into(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (f *crdclient) Delete(name string, options *metav1.DeleteOptions) error {
|
||||
return f.cl.Delete().
|
||||
Namespace(f.ns).Resource(f.plural).
|
||||
Name(name).Body(options).Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
func (f *crdclient) Get(name string) (*FluentBit, error) {
|
||||
var result FluentBit
|
||||
err := f.cl.Get().
|
||||
Namespace(f.ns).Resource(f.plural).
|
||||
Name(name).Do().Into(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (f *crdclient) List(opts metav1.ListOptions) (*FluentBitList, error) {
|
||||
var result FluentBitList
|
||||
err := f.cl.Get().
|
||||
Namespace(f.ns).Resource(f.plural).
|
||||
VersionedParams(&opts, f.codec).
|
||||
Do().Into(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
// Create a new List watch for our TPR
|
||||
func (f *crdclient) NewListWatch() *cache.ListWatch {
|
||||
return cache.NewListWatchFromClient(f.cl, f.plural, f.ns, fields.Everything())
|
||||
}
|
||||
|
||||
// return rest config, if path not specified assume in cluster config
|
||||
func GetClientConfig(kubeconfig string) (*rest.Config, error) {
|
||||
if kubeconfig != "" {
|
||||
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||
}
|
||||
return rest.InClusterConfig()
|
||||
}
|
||||
@@ -20,17 +20,13 @@ package k8s
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -38,10 +34,12 @@ var (
|
||||
k8sClient *kubernetes.Clientset
|
||||
k8sClientOnce sync.Once
|
||||
KubeConfig *rest.Config
|
||||
masterURL string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&kubeConfigFile, "kubeconfig", fmt.Sprintf("%s/.kube/config", os.Getenv("HOME")), "path to kubeconfig file")
|
||||
flag.StringVar(&kubeConfigFile, "kubeconfig", "", "path to kubeconfig file")
|
||||
flag.StringVar(&masterURL, "master-url", "", "kube-apiserver url, only needed when out of cluster")
|
||||
}
|
||||
|
||||
func Client() *kubernetes.Clientset {
|
||||
@@ -64,18 +62,8 @@ func Client() *kubernetes.Clientset {
|
||||
|
||||
func Config() (kubeConfig *rest.Config, err error) {
|
||||
|
||||
if kubeConfigFile == "" {
|
||||
if env := os.Getenv("KUBECONFIG"); env != "" {
|
||||
kubeConfigFile = env
|
||||
} else {
|
||||
if home, err := homedir.Dir(); err == nil {
|
||||
kubeConfigFile = fmt.Sprintf("%s/.kube/config", home)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = os.Stat(kubeConfigFile); err == nil {
|
||||
kubeConfig, err = clientcmd.BuildConfigFromFlags("", kubeConfigFile)
|
||||
kubeConfig, err = clientcmd.BuildConfigFromFlags(masterURL, kubeConfigFile)
|
||||
} else {
|
||||
kubeConfig, err = rest.InClusterConfig()
|
||||
}
|
||||
|
||||
31
pkg/simple/client/k8s/s2iclient.go
Normal file
31
pkg/simple/client/k8s/s2iclient.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package k8s
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
s2i "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
var (
|
||||
s2iClient *s2i.Clientset
|
||||
s2iClientOnce sync.Once
|
||||
)
|
||||
|
||||
func S2iClient() *s2i.Clientset {
|
||||
|
||||
s2iClientOnce.Do(func() {
|
||||
|
||||
config, err := Config()
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
s2iClient = s2i.NewForConfigOrDie(config)
|
||||
|
||||
KubeConfig = config
|
||||
})
|
||||
|
||||
return s2iClient
|
||||
}
|
||||
@@ -31,49 +31,48 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultQueryStep = "10m"
|
||||
DefaultQueryTimeout = "10s"
|
||||
RangeQueryType = "query_range?"
|
||||
DefaultQueryType = "query?"
|
||||
DefaultScheme = "http"
|
||||
DefaultPrometheusPort = "9090"
|
||||
PrometheusApiPath = "/api/v1/"
|
||||
DefaultQueryStep = "10m"
|
||||
DefaultQueryTimeout = "10s"
|
||||
RangeQueryType = "query_range?"
|
||||
DefaultQueryType = "query?"
|
||||
PrometheusAPIServerEnv = "PROMETHEUS_API_SERVER"
|
||||
)
|
||||
|
||||
var (
|
||||
PrometheusAPIEndpoint string
|
||||
)
|
||||
var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc"
|
||||
var PrometheusAPIEndpoint string
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&PrometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "prometheus api endpoint")
|
||||
flag.StringVar(&PrometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1", "")
|
||||
}
|
||||
|
||||
type MonitoringRequestParams struct {
|
||||
Params url.Values
|
||||
QueryType string
|
||||
SortMetricName string
|
||||
SortType string
|
||||
PageNum string
|
||||
LimitNum string
|
||||
Tp string
|
||||
MetricsFilter string
|
||||
NodesFilter string
|
||||
WsFilter string
|
||||
NsFilter string
|
||||
PodsFilter string
|
||||
ContainersFilter string
|
||||
MetricsName string
|
||||
WorkloadName string
|
||||
WlFilter string
|
||||
NodeId string
|
||||
WsName string
|
||||
NsName string
|
||||
PodName string
|
||||
ContainerName string
|
||||
WorkloadKind string
|
||||
Params url.Values
|
||||
QueryType string
|
||||
SortMetricName string
|
||||
SortType string
|
||||
PageNum string
|
||||
LimitNum string
|
||||
Tp string
|
||||
MetricsFilter string
|
||||
ResourcesFilter string
|
||||
MetricsName string
|
||||
WorkloadName string
|
||||
NodeId string
|
||||
WsName string
|
||||
NsName string
|
||||
PodName string
|
||||
ContainerName string
|
||||
WorkloadKind string
|
||||
}
|
||||
|
||||
var client = &http.Client{}
|
||||
|
||||
func SendMonitoringRequest(queryType string, params string) string {
|
||||
epurl := PrometheusAPIEndpoint + queryType + params
|
||||
|
||||
response, err := http.DefaultClient.Get(epurl)
|
||||
response, err := client.Get(epurl)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
@@ -103,15 +102,10 @@ func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestPa
|
||||
tp := strings.Trim(request.QueryParameter("type"), " ")
|
||||
|
||||
metricsFilter := strings.Trim(request.QueryParameter("metrics_filter"), " ")
|
||||
nodesFilter := strings.Trim(request.QueryParameter("nodes_filter"), " ")
|
||||
wsFilter := strings.Trim(request.QueryParameter("workspaces_filter"), " ")
|
||||
nsFilter := strings.Trim(request.QueryParameter("namespaces_filter"), " ")
|
||||
wlFilter := strings.Trim(request.QueryParameter("workloads_filter"), " ")
|
||||
podsFilter := strings.Trim(request.QueryParameter("pods_filter"), " ")
|
||||
containersFilter := strings.Trim(request.QueryParameter("containers_filter"), " ")
|
||||
resourcesFilter := strings.Trim(request.QueryParameter("resources_filter"), " ")
|
||||
|
||||
metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ")
|
||||
workloadName := strings.Trim(request.QueryParameter("workload_name"), " ")
|
||||
workloadName := strings.Trim(request.PathParameter("workload"), " ")
|
||||
|
||||
nodeId := strings.Trim(request.PathParameter("node"), " ")
|
||||
wsName := strings.Trim(request.PathParameter("workspace"), " ")
|
||||
@@ -121,26 +115,21 @@ func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestPa
|
||||
workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ")
|
||||
|
||||
var requestParams = MonitoringRequestParams{
|
||||
SortMetricName: sortMetricName,
|
||||
SortType: sortType,
|
||||
PageNum: pageNum,
|
||||
LimitNum: limitNum,
|
||||
Tp: tp,
|
||||
MetricsFilter: metricsFilter,
|
||||
NodesFilter: nodesFilter,
|
||||
WsFilter: wsFilter,
|
||||
NsFilter: nsFilter,
|
||||
PodsFilter: podsFilter,
|
||||
ContainersFilter: containersFilter,
|
||||
MetricsName: metricsName,
|
||||
WorkloadName: workloadName,
|
||||
WlFilter: wlFilter,
|
||||
NodeId: nodeId,
|
||||
WsName: wsName,
|
||||
NsName: nsName,
|
||||
PodName: podName,
|
||||
ContainerName: containerName,
|
||||
WorkloadKind: workloadKind,
|
||||
SortMetricName: sortMetricName,
|
||||
SortType: sortType,
|
||||
PageNum: pageNum,
|
||||
LimitNum: limitNum,
|
||||
Tp: tp,
|
||||
MetricsFilter: metricsFilter,
|
||||
ResourcesFilter: resourcesFilter,
|
||||
MetricsName: metricsName,
|
||||
WorkloadName: workloadName,
|
||||
NodeId: nodeId,
|
||||
WsName: wsName,
|
||||
NsName: nsName,
|
||||
PodName: podName,
|
||||
ContainerName: containerName,
|
||||
WorkloadKind: workloadKind,
|
||||
}
|
||||
|
||||
if timeout == "" {
|
||||
|
||||
@@ -19,9 +19,10 @@ package namespace
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -36,6 +37,8 @@ import (
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("namespace-controller")
|
||||
|
||||
const threadiness = 2
|
||||
|
||||
var (
|
||||
@@ -54,18 +57,18 @@ type NamespaceController struct {
|
||||
}
|
||||
|
||||
func NewNamespaceController(
|
||||
kubeclientset kubernetes.Interface,
|
||||
clientset kubernetes.Interface,
|
||||
namespaceInformer coreinformers.NamespaceInformer,
|
||||
roleInformer rbacinformers.RoleInformer) *NamespaceController {
|
||||
|
||||
controller := &NamespaceController{
|
||||
clientset: kubeclientset,
|
||||
clientset: clientset,
|
||||
namespaceInformer: namespaceInformer,
|
||||
roleInformer: roleInformer,
|
||||
workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "namespaces"),
|
||||
}
|
||||
|
||||
glog.Info("setting up event handlers")
|
||||
log.V(3).Info("setting up event handlers")
|
||||
|
||||
namespaceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: controller.handleObject,
|
||||
@@ -85,30 +88,27 @@ func NewNamespaceController(
|
||||
return controller
|
||||
}
|
||||
|
||||
func (c *NamespaceController) Start(stopCh <-chan struct{}) {
|
||||
go func() {
|
||||
defer utilruntime.HandleCrash()
|
||||
defer c.workqueue.ShutDown()
|
||||
func (c *NamespaceController) Start(stopCh <-chan struct{}) error {
|
||||
defer utilruntime.HandleCrash()
|
||||
defer c.workqueue.ShutDown()
|
||||
|
||||
// Start the informer factories to begin populating the informer caches
|
||||
glog.Info("starting namespace controller")
|
||||
log.V(3).Info("starting namespace controller")
|
||||
defer glog.Info("shutting down namespace controller")
|
||||
|
||||
// Wait for the caches to be synced before starting workers
|
||||
glog.Info("waiting for informer caches to sync")
|
||||
if ok := cache.WaitForCacheSync(stopCh, c.namespaceInformer.Informer().HasSynced, c.roleInformer.Informer().HasSynced); !ok {
|
||||
glog.Fatalf("controller exit with error: failed to wait for caches to sync")
|
||||
}
|
||||
// Wait for the caches to be synced before starting workers
|
||||
log.Info("waiting for informer caches to sync")
|
||||
if ok := cache.WaitForCacheSync(stopCh, c.namespaceInformer.Informer().HasSynced, c.roleInformer.Informer().HasSynced); !ok {
|
||||
glog.Fatalf("controller exit with error: failed to wait for caches to sync")
|
||||
}
|
||||
|
||||
glog.Info("starting workers")
|
||||
log.V(3).Info("starting workers")
|
||||
for i := 0; i < threadiness; i++ {
|
||||
go wait.Until(c.runWorker, time.Second, stopCh)
|
||||
}
|
||||
|
||||
for i := 0; i < threadiness; i++ {
|
||||
go wait.Until(c.runWorker, time.Second, stopCh)
|
||||
}
|
||||
<-stopCh
|
||||
|
||||
glog.Info("started workers")
|
||||
<-stopCh
|
||||
glog.Info("shutting down workers")
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *NamespaceController) runWorker() {
|
||||
@@ -140,7 +140,7 @@ func (c *NamespaceController) processNextWorkItem() bool {
|
||||
}
|
||||
|
||||
c.workqueue.Forget(obj)
|
||||
glog.Infof("successfully namespace synced '%s'", namespace)
|
||||
log.V(4).Info("successfully namespace synced ", "namespace", namespace)
|
||||
return nil
|
||||
}(obj)
|
||||
|
||||
|
||||
25
vendor/github.com/evanphx/json-patch/LICENSE
generated
vendored
Normal file
25
vendor/github.com/evanphx/json-patch/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2014, Evan Phoenix
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the Evan Phoenix nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
383
vendor/github.com/evanphx/json-patch/merge.go
generated
vendored
Normal file
383
vendor/github.com/evanphx/json-patch/merge.go
generated
vendored
Normal file
@@ -0,0 +1,383 @@
|
||||
package jsonpatch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode {
|
||||
curDoc, err := cur.intoDoc()
|
||||
|
||||
if err != nil {
|
||||
pruneNulls(patch)
|
||||
return patch
|
||||
}
|
||||
|
||||
patchDoc, err := patch.intoDoc()
|
||||
|
||||
if err != nil {
|
||||
return patch
|
||||
}
|
||||
|
||||
mergeDocs(curDoc, patchDoc, mergeMerge)
|
||||
|
||||
return cur
|
||||
}
|
||||
|
||||
func mergeDocs(doc, patch *partialDoc, mergeMerge bool) {
|
||||
for k, v := range *patch {
|
||||
if v == nil {
|
||||
if mergeMerge {
|
||||
(*doc)[k] = nil
|
||||
} else {
|
||||
delete(*doc, k)
|
||||
}
|
||||
} else {
|
||||
cur, ok := (*doc)[k]
|
||||
|
||||
if !ok || cur == nil {
|
||||
pruneNulls(v)
|
||||
(*doc)[k] = v
|
||||
} else {
|
||||
(*doc)[k] = merge(cur, v, mergeMerge)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pruneNulls(n *lazyNode) {
|
||||
sub, err := n.intoDoc()
|
||||
|
||||
if err == nil {
|
||||
pruneDocNulls(sub)
|
||||
} else {
|
||||
ary, err := n.intoAry()
|
||||
|
||||
if err == nil {
|
||||
pruneAryNulls(ary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pruneDocNulls(doc *partialDoc) *partialDoc {
|
||||
for k, v := range *doc {
|
||||
if v == nil {
|
||||
delete(*doc, k)
|
||||
} else {
|
||||
pruneNulls(v)
|
||||
}
|
||||
}
|
||||
|
||||
return doc
|
||||
}
|
||||
|
||||
func pruneAryNulls(ary *partialArray) *partialArray {
|
||||
newAry := []*lazyNode{}
|
||||
|
||||
for _, v := range *ary {
|
||||
if v != nil {
|
||||
pruneNulls(v)
|
||||
newAry = append(newAry, v)
|
||||
}
|
||||
}
|
||||
|
||||
*ary = newAry
|
||||
|
||||
return ary
|
||||
}
|
||||
|
||||
var errBadJSONDoc = fmt.Errorf("Invalid JSON Document")
|
||||
var errBadJSONPatch = fmt.Errorf("Invalid JSON Patch")
|
||||
var errBadMergeTypes = fmt.Errorf("Mismatched JSON Documents")
|
||||
|
||||
// MergeMergePatches merges two merge patches together, such that
|
||||
// applying this resulting merged merge patch to a document yields the same
|
||||
// as merging each merge patch to the document in succession.
|
||||
func MergeMergePatches(patch1Data, patch2Data []byte) ([]byte, error) {
|
||||
return doMergePatch(patch1Data, patch2Data, true)
|
||||
}
|
||||
|
||||
// MergePatch merges the patchData into the docData.
|
||||
func MergePatch(docData, patchData []byte) ([]byte, error) {
|
||||
return doMergePatch(docData, patchData, false)
|
||||
}
|
||||
|
||||
func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) {
|
||||
doc := &partialDoc{}
|
||||
|
||||
docErr := json.Unmarshal(docData, doc)
|
||||
|
||||
patch := &partialDoc{}
|
||||
|
||||
patchErr := json.Unmarshal(patchData, patch)
|
||||
|
||||
if _, ok := docErr.(*json.SyntaxError); ok {
|
||||
return nil, errBadJSONDoc
|
||||
}
|
||||
|
||||
if _, ok := patchErr.(*json.SyntaxError); ok {
|
||||
return nil, errBadJSONPatch
|
||||
}
|
||||
|
||||
if docErr == nil && *doc == nil {
|
||||
return nil, errBadJSONDoc
|
||||
}
|
||||
|
||||
if patchErr == nil && *patch == nil {
|
||||
return nil, errBadJSONPatch
|
||||
}
|
||||
|
||||
if docErr != nil || patchErr != nil {
|
||||
// Not an error, just not a doc, so we turn straight into the patch
|
||||
if patchErr == nil {
|
||||
if mergeMerge {
|
||||
doc = patch
|
||||
} else {
|
||||
doc = pruneDocNulls(patch)
|
||||
}
|
||||
} else {
|
||||
patchAry := &partialArray{}
|
||||
patchErr = json.Unmarshal(patchData, patchAry)
|
||||
|
||||
if patchErr != nil {
|
||||
return nil, errBadJSONPatch
|
||||
}
|
||||
|
||||
pruneAryNulls(patchAry)
|
||||
|
||||
out, patchErr := json.Marshal(patchAry)
|
||||
|
||||
if patchErr != nil {
|
||||
return nil, errBadJSONPatch
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
} else {
|
||||
mergeDocs(doc, patch, mergeMerge)
|
||||
}
|
||||
|
||||
return json.Marshal(doc)
|
||||
}
|
||||
|
||||
// resemblesJSONArray indicates whether the byte-slice "appears" to be
|
||||
// a JSON array or not.
|
||||
// False-positives are possible, as this function does not check the internal
|
||||
// structure of the array. It only checks that the outer syntax is present and
|
||||
// correct.
|
||||
func resemblesJSONArray(input []byte) bool {
|
||||
input = bytes.TrimSpace(input)
|
||||
|
||||
hasPrefix := bytes.HasPrefix(input, []byte("["))
|
||||
hasSuffix := bytes.HasSuffix(input, []byte("]"))
|
||||
|
||||
return hasPrefix && hasSuffix
|
||||
}
|
||||
|
||||
// CreateMergePatch will return a merge patch document capable of converting
|
||||
// the original document(s) to the modified document(s).
|
||||
// The parameters can be bytes of either two JSON Documents, or two arrays of
|
||||
// JSON documents.
|
||||
// The merge patch returned follows the specification defined at http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch-07
|
||||
func CreateMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
|
||||
originalResemblesArray := resemblesJSONArray(originalJSON)
|
||||
modifiedResemblesArray := resemblesJSONArray(modifiedJSON)
|
||||
|
||||
// Do both byte-slices seem like JSON arrays?
|
||||
if originalResemblesArray && modifiedResemblesArray {
|
||||
return createArrayMergePatch(originalJSON, modifiedJSON)
|
||||
}
|
||||
|
||||
// Are both byte-slices are not arrays? Then they are likely JSON objects...
|
||||
if !originalResemblesArray && !modifiedResemblesArray {
|
||||
return createObjectMergePatch(originalJSON, modifiedJSON)
|
||||
}
|
||||
|
||||
// None of the above? Then return an error because of mismatched types.
|
||||
return nil, errBadMergeTypes
|
||||
}
|
||||
|
||||
// createObjectMergePatch will return a merge-patch document capable of
|
||||
// converting the original document to the modified document.
|
||||
func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
|
||||
originalDoc := map[string]interface{}{}
|
||||
modifiedDoc := map[string]interface{}{}
|
||||
|
||||
err := json.Unmarshal(originalJSON, &originalDoc)
|
||||
if err != nil {
|
||||
return nil, errBadJSONDoc
|
||||
}
|
||||
|
||||
err = json.Unmarshal(modifiedJSON, &modifiedDoc)
|
||||
if err != nil {
|
||||
return nil, errBadJSONDoc
|
||||
}
|
||||
|
||||
dest, err := getDiff(originalDoc, modifiedDoc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(dest)
|
||||
}
|
||||
|
||||
// createArrayMergePatch will return an array of merge-patch documents capable
|
||||
// of converting the original document to the modified document for each
|
||||
// pair of JSON documents provided in the arrays.
|
||||
// Arrays of mismatched sizes will result in an error.
|
||||
func createArrayMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
|
||||
originalDocs := []json.RawMessage{}
|
||||
modifiedDocs := []json.RawMessage{}
|
||||
|
||||
err := json.Unmarshal(originalJSON, &originalDocs)
|
||||
if err != nil {
|
||||
return nil, errBadJSONDoc
|
||||
}
|
||||
|
||||
err = json.Unmarshal(modifiedJSON, &modifiedDocs)
|
||||
if err != nil {
|
||||
return nil, errBadJSONDoc
|
||||
}
|
||||
|
||||
total := len(originalDocs)
|
||||
if len(modifiedDocs) != total {
|
||||
return nil, errBadJSONDoc
|
||||
}
|
||||
|
||||
result := []json.RawMessage{}
|
||||
for i := 0; i < len(originalDocs); i++ {
|
||||
original := originalDocs[i]
|
||||
modified := modifiedDocs[i]
|
||||
|
||||
patch, err := createObjectMergePatch(original, modified)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, json.RawMessage(patch))
|
||||
}
|
||||
|
||||
return json.Marshal(result)
|
||||
}
|
||||
|
||||
// Returns true if the array matches (must be json types).
|
||||
// As is idiomatic for go, an empty array is not the same as a nil array.
|
||||
func matchesArray(a, b []interface{}) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
if (a == nil && b != nil) || (a != nil && b == nil) {
|
||||
return false
|
||||
}
|
||||
for i := range a {
|
||||
if !matchesValue(a[i], b[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Returns true if the values matches (must be json types)
|
||||
// The types of the values must match, otherwise it will always return false
|
||||
// If two map[string]interface{} are given, all elements must match.
|
||||
func matchesValue(av, bv interface{}) bool {
|
||||
if reflect.TypeOf(av) != reflect.TypeOf(bv) {
|
||||
return false
|
||||
}
|
||||
switch at := av.(type) {
|
||||
case string:
|
||||
bt := bv.(string)
|
||||
if bt == at {
|
||||
return true
|
||||
}
|
||||
case float64:
|
||||
bt := bv.(float64)
|
||||
if bt == at {
|
||||
return true
|
||||
}
|
||||
case bool:
|
||||
bt := bv.(bool)
|
||||
if bt == at {
|
||||
return true
|
||||
}
|
||||
case nil:
|
||||
// Both nil, fine.
|
||||
return true
|
||||
case map[string]interface{}:
|
||||
bt := bv.(map[string]interface{})
|
||||
for key := range at {
|
||||
if !matchesValue(at[key], bt[key]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for key := range bt {
|
||||
if !matchesValue(at[key], bt[key]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case []interface{}:
|
||||
bt := bv.([]interface{})
|
||||
return matchesArray(at, bt)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getDiff returns the (recursive) difference between a and b as a map[string]interface{}.
|
||||
func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) {
|
||||
into := map[string]interface{}{}
|
||||
for key, bv := range b {
|
||||
av, ok := a[key]
|
||||
// value was added
|
||||
if !ok {
|
||||
into[key] = bv
|
||||
continue
|
||||
}
|
||||
// If types have changed, replace completely
|
||||
if reflect.TypeOf(av) != reflect.TypeOf(bv) {
|
||||
into[key] = bv
|
||||
continue
|
||||
}
|
||||
// Types are the same, compare values
|
||||
switch at := av.(type) {
|
||||
case map[string]interface{}:
|
||||
bt := bv.(map[string]interface{})
|
||||
dst := make(map[string]interface{}, len(bt))
|
||||
dst, err := getDiff(at, bt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(dst) > 0 {
|
||||
into[key] = dst
|
||||
}
|
||||
case string, float64, bool:
|
||||
if !matchesValue(av, bv) {
|
||||
into[key] = bv
|
||||
}
|
||||
case []interface{}:
|
||||
bt := bv.([]interface{})
|
||||
if !matchesArray(at, bt) {
|
||||
into[key] = bv
|
||||
}
|
||||
case nil:
|
||||
switch bv.(type) {
|
||||
case nil:
|
||||
// Both nil, fine.
|
||||
default:
|
||||
into[key] = bv
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown type:%T in key %s", av, key))
|
||||
}
|
||||
}
|
||||
// Now add all deleted values as nil
|
||||
for key := range a {
|
||||
_, found := b[key]
|
||||
if !found {
|
||||
into[key] = nil
|
||||
}
|
||||
}
|
||||
return into, nil
|
||||
}
|
||||
682
vendor/github.com/evanphx/json-patch/patch.go
generated
vendored
Normal file
682
vendor/github.com/evanphx/json-patch/patch.go
generated
vendored
Normal file
@@ -0,0 +1,682 @@
|
||||
package jsonpatch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
eRaw = iota
|
||||
eDoc
|
||||
eAry
|
||||
)
|
||||
|
||||
var SupportNegativeIndices bool = true
|
||||
|
||||
type lazyNode struct {
|
||||
raw *json.RawMessage
|
||||
doc partialDoc
|
||||
ary partialArray
|
||||
which int
|
||||
}
|
||||
|
||||
type operation map[string]*json.RawMessage
|
||||
|
||||
// Patch is an ordered collection of operations.
|
||||
type Patch []operation
|
||||
|
||||
type partialDoc map[string]*lazyNode
|
||||
type partialArray []*lazyNode
|
||||
|
||||
type container interface {
|
||||
get(key string) (*lazyNode, error)
|
||||
set(key string, val *lazyNode) error
|
||||
add(key string, val *lazyNode) error
|
||||
remove(key string) error
|
||||
}
|
||||
|
||||
func newLazyNode(raw *json.RawMessage) *lazyNode {
|
||||
return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
|
||||
}
|
||||
|
||||
func (n *lazyNode) MarshalJSON() ([]byte, error) {
|
||||
switch n.which {
|
||||
case eRaw:
|
||||
return json.Marshal(n.raw)
|
||||
case eDoc:
|
||||
return json.Marshal(n.doc)
|
||||
case eAry:
|
||||
return json.Marshal(n.ary)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown type")
|
||||
}
|
||||
}
|
||||
|
||||
func (n *lazyNode) UnmarshalJSON(data []byte) error {
|
||||
dest := make(json.RawMessage, len(data))
|
||||
copy(dest, data)
|
||||
n.raw = &dest
|
||||
n.which = eRaw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *lazyNode) intoDoc() (*partialDoc, error) {
|
||||
if n.which == eDoc {
|
||||
return &n.doc, nil
|
||||
}
|
||||
|
||||
if n.raw == nil {
|
||||
return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial document")
|
||||
}
|
||||
|
||||
err := json.Unmarshal(*n.raw, &n.doc)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n.which = eDoc
|
||||
return &n.doc, nil
|
||||
}
|
||||
|
||||
func (n *lazyNode) intoAry() (*partialArray, error) {
|
||||
if n.which == eAry {
|
||||
return &n.ary, nil
|
||||
}
|
||||
|
||||
if n.raw == nil {
|
||||
return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial array")
|
||||
}
|
||||
|
||||
err := json.Unmarshal(*n.raw, &n.ary)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n.which = eAry
|
||||
return &n.ary, nil
|
||||
}
|
||||
|
||||
func (n *lazyNode) compact() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
if n.raw == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := json.Compact(buf, *n.raw)
|
||||
|
||||
if err != nil {
|
||||
return *n.raw
|
||||
}
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (n *lazyNode) tryDoc() bool {
|
||||
if n.raw == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
err := json.Unmarshal(*n.raw, &n.doc)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
n.which = eDoc
|
||||
return true
|
||||
}
|
||||
|
||||
func (n *lazyNode) tryAry() bool {
|
||||
if n.raw == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
err := json.Unmarshal(*n.raw, &n.ary)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
n.which = eAry
|
||||
return true
|
||||
}
|
||||
|
||||
func (n *lazyNode) equal(o *lazyNode) bool {
|
||||
if n.which == eRaw {
|
||||
if !n.tryDoc() && !n.tryAry() {
|
||||
if o.which != eRaw {
|
||||
return false
|
||||
}
|
||||
|
||||
return bytes.Equal(n.compact(), o.compact())
|
||||
}
|
||||
}
|
||||
|
||||
if n.which == eDoc {
|
||||
if o.which == eRaw {
|
||||
if !o.tryDoc() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if o.which != eDoc {
|
||||
return false
|
||||
}
|
||||
|
||||
for k, v := range n.doc {
|
||||
ov, ok := o.doc[k]
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if v == nil && ov == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !v.equal(ov) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if o.which != eAry && !o.tryAry() {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(n.ary) != len(o.ary) {
|
||||
return false
|
||||
}
|
||||
|
||||
for idx, val := range n.ary {
|
||||
if !val.equal(o.ary[idx]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (o operation) kind() string {
|
||||
if obj, ok := o["op"]; ok && obj != nil {
|
||||
var op string
|
||||
|
||||
err := json.Unmarshal(*obj, &op)
|
||||
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func (o operation) path() string {
|
||||
if obj, ok := o["path"]; ok && obj != nil {
|
||||
var op string
|
||||
|
||||
err := json.Unmarshal(*obj, &op)
|
||||
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func (o operation) from() string {
|
||||
if obj, ok := o["from"]; ok && obj != nil {
|
||||
var op string
|
||||
|
||||
err := json.Unmarshal(*obj, &op)
|
||||
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func (o operation) value() *lazyNode {
|
||||
if obj, ok := o["value"]; ok {
|
||||
return newLazyNode(obj)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isArray(buf []byte) bool {
|
||||
Loop:
|
||||
for _, c := range buf {
|
||||
switch c {
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\t':
|
||||
continue
|
||||
case '[':
|
||||
return true
|
||||
default:
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func findObject(pd *container, path string) (container, string) {
|
||||
doc := *pd
|
||||
|
||||
split := strings.Split(path, "/")
|
||||
|
||||
if len(split) < 2 {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
parts := split[1 : len(split)-1]
|
||||
|
||||
key := split[len(split)-1]
|
||||
|
||||
var err error
|
||||
|
||||
for _, part := range parts {
|
||||
|
||||
next, ok := doc.get(decodePatchKey(part))
|
||||
|
||||
if next == nil || ok != nil {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
if isArray(*next.raw) {
|
||||
doc, err = next.intoAry()
|
||||
|
||||
if err != nil {
|
||||
return nil, ""
|
||||
}
|
||||
} else {
|
||||
doc, err = next.intoDoc()
|
||||
|
||||
if err != nil {
|
||||
return nil, ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return doc, decodePatchKey(key)
|
||||
}
|
||||
|
||||
func (d *partialDoc) set(key string, val *lazyNode) error {
|
||||
(*d)[key] = val
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *partialDoc) add(key string, val *lazyNode) error {
|
||||
(*d)[key] = val
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *partialDoc) get(key string) (*lazyNode, error) {
|
||||
return (*d)[key], nil
|
||||
}
|
||||
|
||||
func (d *partialDoc) remove(key string) error {
|
||||
_, ok := (*d)[key]
|
||||
if !ok {
|
||||
return fmt.Errorf("Unable to remove nonexistent key: %s", key)
|
||||
}
|
||||
|
||||
delete(*d, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *partialArray) set(key string, val *lazyNode) error {
|
||||
if key == "-" {
|
||||
*d = append(*d, val)
|
||||
return nil
|
||||
}
|
||||
|
||||
idx, err := strconv.Atoi(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sz := len(*d)
|
||||
if idx+1 > sz {
|
||||
sz = idx + 1
|
||||
}
|
||||
|
||||
ary := make([]*lazyNode, sz)
|
||||
|
||||
cur := *d
|
||||
|
||||
copy(ary, cur)
|
||||
|
||||
if idx >= len(ary) {
|
||||
return fmt.Errorf("Unable to access invalid index: %d", idx)
|
||||
}
|
||||
|
||||
ary[idx] = val
|
||||
|
||||
*d = ary
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *partialArray) add(key string, val *lazyNode) error {
|
||||
if key == "-" {
|
||||
*d = append(*d, val)
|
||||
return nil
|
||||
}
|
||||
|
||||
idx, err := strconv.Atoi(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ary := make([]*lazyNode, len(*d)+1)
|
||||
|
||||
cur := *d
|
||||
|
||||
if idx >= len(ary) {
|
||||
return fmt.Errorf("Unable to access invalid index: %d", idx)
|
||||
}
|
||||
|
||||
if SupportNegativeIndices {
|
||||
if idx < -len(ary) {
|
||||
return fmt.Errorf("Unable to access invalid index: %d", idx)
|
||||
}
|
||||
|
||||
if idx < 0 {
|
||||
idx += len(ary)
|
||||
}
|
||||
}
|
||||
|
||||
copy(ary[0:idx], cur[0:idx])
|
||||
ary[idx] = val
|
||||
copy(ary[idx+1:], cur[idx:])
|
||||
|
||||
*d = ary
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *partialArray) get(key string) (*lazyNode, error) {
|
||||
idx, err := strconv.Atoi(key)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if idx >= len(*d) {
|
||||
return nil, fmt.Errorf("Unable to access invalid index: %d", idx)
|
||||
}
|
||||
|
||||
return (*d)[idx], nil
|
||||
}
|
||||
|
||||
func (d *partialArray) remove(key string) error {
|
||||
idx, err := strconv.Atoi(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cur := *d
|
||||
|
||||
if idx >= len(cur) {
|
||||
return fmt.Errorf("Unable to access invalid index: %d", idx)
|
||||
}
|
||||
|
||||
if SupportNegativeIndices {
|
||||
if idx < -len(cur) {
|
||||
return fmt.Errorf("Unable to access invalid index: %d", idx)
|
||||
}
|
||||
|
||||
if idx < 0 {
|
||||
idx += len(cur)
|
||||
}
|
||||
}
|
||||
|
||||
ary := make([]*lazyNode, len(cur)-1)
|
||||
|
||||
copy(ary[0:idx], cur[0:idx])
|
||||
copy(ary[idx:], cur[idx+1:])
|
||||
|
||||
*d = ary
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (p Patch) add(doc *container, op operation) error {
|
||||
path := op.path()
|
||||
|
||||
con, key := findObject(doc, path)
|
||||
|
||||
if con == nil {
|
||||
return fmt.Errorf("jsonpatch add operation does not apply: doc is missing path: \"%s\"", path)
|
||||
}
|
||||
|
||||
return con.add(key, op.value())
|
||||
}
|
||||
|
||||
func (p Patch) remove(doc *container, op operation) error {
|
||||
path := op.path()
|
||||
|
||||
con, key := findObject(doc, path)
|
||||
|
||||
if con == nil {
|
||||
return fmt.Errorf("jsonpatch remove operation does not apply: doc is missing path: \"%s\"", path)
|
||||
}
|
||||
|
||||
return con.remove(key)
|
||||
}
|
||||
|
||||
func (p Patch) replace(doc *container, op operation) error {
|
||||
path := op.path()
|
||||
|
||||
con, key := findObject(doc, path)
|
||||
|
||||
if con == nil {
|
||||
return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing path: %s", path)
|
||||
}
|
||||
|
||||
_, ok := con.get(key)
|
||||
if ok != nil {
|
||||
return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing key: %s", path)
|
||||
}
|
||||
|
||||
return con.set(key, op.value())
|
||||
}
|
||||
|
||||
func (p Patch) move(doc *container, op operation) error {
|
||||
from := op.from()
|
||||
|
||||
con, key := findObject(doc, from)
|
||||
|
||||
if con == nil {
|
||||
return fmt.Errorf("jsonpatch move operation does not apply: doc is missing from path: %s", from)
|
||||
}
|
||||
|
||||
val, err := con.get(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = con.remove(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path := op.path()
|
||||
|
||||
con, key = findObject(doc, path)
|
||||
|
||||
if con == nil {
|
||||
return fmt.Errorf("jsonpatch move operation does not apply: doc is missing destination path: %s", path)
|
||||
}
|
||||
|
||||
return con.set(key, val)
|
||||
}
|
||||
|
||||
func (p Patch) test(doc *container, op operation) error {
|
||||
path := op.path()
|
||||
|
||||
con, key := findObject(doc, path)
|
||||
|
||||
if con == nil {
|
||||
return fmt.Errorf("jsonpatch test operation does not apply: is missing path: %s", path)
|
||||
}
|
||||
|
||||
val, err := con.get(key)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if val == nil {
|
||||
if op.value().raw == nil {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Testing value %s failed", path)
|
||||
} else if op.value() == nil {
|
||||
return fmt.Errorf("Testing value %s failed", path)
|
||||
}
|
||||
|
||||
if val.equal(op.value()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Testing value %s failed", path)
|
||||
}
|
||||
|
||||
func (p Patch) copy(doc *container, op operation) error {
|
||||
from := op.from()
|
||||
|
||||
con, key := findObject(doc, from)
|
||||
|
||||
if con == nil {
|
||||
return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing from path: %s", from)
|
||||
}
|
||||
|
||||
val, err := con.get(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path := op.path()
|
||||
|
||||
con, key = findObject(doc, path)
|
||||
|
||||
if con == nil {
|
||||
return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing destination path: %s", path)
|
||||
}
|
||||
|
||||
return con.set(key, val)
|
||||
}
|
||||
|
||||
// Equal indicates if 2 JSON documents have the same structural equality.
|
||||
func Equal(a, b []byte) bool {
|
||||
ra := make(json.RawMessage, len(a))
|
||||
copy(ra, a)
|
||||
la := newLazyNode(&ra)
|
||||
|
||||
rb := make(json.RawMessage, len(b))
|
||||
copy(rb, b)
|
||||
lb := newLazyNode(&rb)
|
||||
|
||||
return la.equal(lb)
|
||||
}
|
||||
|
||||
// DecodePatch decodes the passed JSON document as an RFC 6902 patch.
|
||||
func DecodePatch(buf []byte) (Patch, error) {
|
||||
var p Patch
|
||||
|
||||
err := json.Unmarshal(buf, &p)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Apply mutates a JSON document according to the patch, and returns the new
|
||||
// document.
|
||||
func (p Patch) Apply(doc []byte) ([]byte, error) {
|
||||
return p.ApplyIndent(doc, "")
|
||||
}
|
||||
|
||||
// ApplyIndent mutates a JSON document according to the patch, and returns the new
|
||||
// document indented.
|
||||
func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
|
||||
var pd container
|
||||
if doc[0] == '[' {
|
||||
pd = &partialArray{}
|
||||
} else {
|
||||
pd = &partialDoc{}
|
||||
}
|
||||
|
||||
err := json.Unmarshal(doc, pd)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = nil
|
||||
|
||||
for _, op := range p {
|
||||
switch op.kind() {
|
||||
case "add":
|
||||
err = p.add(&pd, op)
|
||||
case "remove":
|
||||
err = p.remove(&pd, op)
|
||||
case "replace":
|
||||
err = p.replace(&pd, op)
|
||||
case "move":
|
||||
err = p.move(&pd, op)
|
||||
case "test":
|
||||
err = p.test(&pd, op)
|
||||
case "copy":
|
||||
err = p.copy(&pd, op)
|
||||
default:
|
||||
err = fmt.Errorf("Unexpected kind: %s", op.kind())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if indent != "" {
|
||||
return json.MarshalIndent(pd, "", indent)
|
||||
}
|
||||
|
||||
return json.Marshal(pd)
|
||||
}
|
||||
|
||||
// From http://tools.ietf.org/html/rfc6901#section-4 :
|
||||
//
|
||||
// Evaluation of each reference token begins by decoding any escaped
|
||||
// character sequence. This is performed by first transforming any
|
||||
// occurrence of the sequence '~1' to '/', and then transforming any
|
||||
// occurrence of the sequence '~0' to '~'.
|
||||
|
||||
var (
|
||||
rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
|
||||
)
|
||||
|
||||
func decodePatchKey(k string) string {
|
||||
return rfc6901Decoder.Replace(k)
|
||||
}
|
||||
29
vendor/github.com/kiali/kiali/graph/options/options.go
generated
vendored
29
vendor/github.com/kiali/kiali/graph/options/options.go
generated
vendored
@@ -3,14 +3,12 @@ package options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/kiali/kiali/business"
|
||||
"github.com/kiali/kiali/graph"
|
||||
"github.com/kiali/kiali/graph/appender"
|
||||
@@ -64,17 +62,26 @@ type Options struct {
|
||||
VendorOptions
|
||||
}
|
||||
|
||||
func NewOptions(r *http.Request) Options {
|
||||
func getParameters(key string, request *restful.Request) string {
|
||||
value, ok := request.PathParameters()[key]
|
||||
|
||||
if !ok {
|
||||
return request.QueryParameter(key)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func NewOptions(request *restful.Request) Options {
|
||||
// path variables (0 or more will be set)
|
||||
vars := mux.Vars(r)
|
||||
app := vars["app"]
|
||||
namespace := vars["namespace"]
|
||||
service := vars["service"]
|
||||
version := vars["version"]
|
||||
workload := vars["workload"]
|
||||
app := getParameters("app", request)
|
||||
namespace := getParameters("namespace", request)
|
||||
service := getParameters("service", request)
|
||||
version := getParameters("version", request)
|
||||
workload := getParameters("workload", request)
|
||||
|
||||
// query params
|
||||
params := r.URL.Query()
|
||||
params := request.Request.URL.Query()
|
||||
var duration time.Duration
|
||||
var includeIstio bool
|
||||
var injectServiceNodes bool
|
||||
|
||||
20
vendor/github.com/kiali/kiali/handlers/apps.go
generated
vendored
20
vendor/github.com/kiali/kiali/handlers/apps.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
@@ -61,31 +62,30 @@ func AppDetails(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// AppMetrics is the API handler to fetch metrics to be displayed, related to an app-label grouping
|
||||
func AppMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
getAppMetrics(w, r, defaultPromClientSupplier, defaultK8SClientSupplier)
|
||||
func AppMetrics(request *restful.Request, response *restful.Response) {
|
||||
getAppMetrics(request, response, defaultPromClientSupplier, defaultK8SClientSupplier)
|
||||
}
|
||||
|
||||
// getAppMetrics (mock-friendly version)
|
||||
func getAppMetrics(w http.ResponseWriter, r *http.Request, promSupplier promClientSupplier, k8sSupplier k8sClientSupplier) {
|
||||
vars := mux.Vars(r)
|
||||
namespace := vars["namespace"]
|
||||
app := vars["app"]
|
||||
func getAppMetrics(request *restful.Request, response *restful.Response, promSupplier promClientSupplier, k8sSupplier k8sClientSupplier) {
|
||||
namespace := request.PathParameters()["namespace"]
|
||||
app := request.PathParameters()["app"]
|
||||
|
||||
prom, _, namespaceInfo := initClientsForMetrics(w, promSupplier, k8sSupplier, namespace)
|
||||
prom, _, namespaceInfo := initClientsForMetrics(response.ResponseWriter, promSupplier, k8sSupplier, namespace)
|
||||
if prom == nil {
|
||||
// any returned value nil means error & response already written
|
||||
return
|
||||
}
|
||||
|
||||
params := prometheus.IstioMetricsQuery{Namespace: namespace, App: app}
|
||||
err := extractIstioMetricsQueryParams(r, ¶ms, namespaceInfo)
|
||||
err := extractIstioMetricsQueryParams(request.Request, ¶ms, namespaceInfo)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusBadRequest, err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
metrics := prom.GetMetrics(¶ms)
|
||||
RespondWithJSON(w, http.StatusOK, metrics)
|
||||
RespondWithJSON(response.ResponseWriter, http.StatusOK, metrics)
|
||||
}
|
||||
|
||||
// CustomDashboard is the API handler to fetch runtime metrics to be displayed, related to a single app
|
||||
|
||||
36
vendor/github.com/kiali/kiali/handlers/graph.go
generated
vendored
36
vendor/github.com/kiali/kiali/handlers/graph.go
generated
vendored
@@ -34,6 +34,7 @@ package handlers
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
@@ -51,26 +52,35 @@ import (
|
||||
"github.com/kiali/kiali/prometheus/internalmetrics"
|
||||
)
|
||||
|
||||
// GraphNamespaces is a REST http.HandlerFunc handling graph generation for 1 or more namespaces
|
||||
func GraphNamespaces(w http.ResponseWriter, r *http.Request) {
|
||||
defer handlePanic(w)
|
||||
func GetNamespaceGraph(request * restful.Request, response *restful.Response) {
|
||||
defer handlePanic(response.ResponseWriter)
|
||||
|
||||
client, err := prometheus.NewClient()
|
||||
graph.CheckError(err)
|
||||
|
||||
graphNamespaces(w, r, client)
|
||||
graphNamespaces(request, response, client)
|
||||
}
|
||||
|
||||
// GraphNamespaces is a REST http.HandlerFunc handling graph generation for 1 or more namespaces
|
||||
func GraphNamespaces(request *restful.Request, response *restful.Response) {
|
||||
defer handlePanic(response.ResponseWriter)
|
||||
|
||||
client, err := prometheus.NewClient()
|
||||
graph.CheckError(err)
|
||||
|
||||
graphNamespaces(request, response, client)
|
||||
}
|
||||
|
||||
// graphNamespaces provides a testing hook that can supply a mock client
|
||||
func graphNamespaces(w http.ResponseWriter, r *http.Request, client *prometheus.Client) {
|
||||
o := options.NewOptions(r)
|
||||
func graphNamespaces(reqeust *restful.Request, response *restful.Response, client *prometheus.Client) {
|
||||
o := options.NewOptions(reqeust)
|
||||
|
||||
// time how long it takes to generate this graph
|
||||
promtimer := internalmetrics.GetGraphGenerationTimePrometheusTimer(o.GetGraphKind(), o.GraphType, o.InjectServiceNodes)
|
||||
defer promtimer.ObserveDuration()
|
||||
|
||||
trafficMap := buildNamespacesTrafficMap(o, client)
|
||||
generateGraph(trafficMap, w, o)
|
||||
generateGraph(trafficMap, response.ResponseWriter, o)
|
||||
|
||||
// update metrics
|
||||
internalmetrics.SetGraphNodes(o.GetGraphKind(), o.GraphType, o.InjectServiceNodes, len(trafficMap))
|
||||
@@ -613,18 +623,18 @@ func addNode(trafficMap graph.TrafficMap, namespace, workload, app, version, ser
|
||||
|
||||
// GraphNode is a REST http.HandlerFunc handling node-detail graph
|
||||
// config generation.
|
||||
func GraphNode(w http.ResponseWriter, r *http.Request) {
|
||||
defer handlePanic(w)
|
||||
func GraphNode(request *restful.Request, response *restful.Response) {
|
||||
defer handlePanic(response.ResponseWriter)
|
||||
|
||||
client, err := prometheus.NewClient()
|
||||
graph.CheckError(err)
|
||||
|
||||
graphNode(w, r, client)
|
||||
graphNode(request, response, client)
|
||||
}
|
||||
|
||||
// graphNode provides a testing hook that can supply a mock client
|
||||
func graphNode(w http.ResponseWriter, r *http.Request, client *prometheus.Client) {
|
||||
o := options.NewOptions(r)
|
||||
func graphNode(request *restful.Request, response *restful.Response, client *prometheus.Client) {
|
||||
o := options.NewOptions(request)
|
||||
switch o.Vendor {
|
||||
case "cytoscape":
|
||||
default:
|
||||
@@ -664,7 +674,7 @@ func graphNode(w http.ResponseWriter, r *http.Request, client *prometheus.Client
|
||||
// the current decision is to not reduce the node graph to provide more detail. This may be
|
||||
// confusing to users, we'll see...
|
||||
|
||||
generateGraph(trafficMap, w, o)
|
||||
generateGraph(trafficMap, response.ResponseWriter, o)
|
||||
|
||||
// update metrics
|
||||
internalmetrics.SetGraphNodes(o.GetGraphKind(), o.GraphType, o.InjectServiceNodes, len(trafficMap))
|
||||
|
||||
108
vendor/github.com/kiali/kiali/handlers/health.go
generated
vendored
108
vendor/github.com/kiali/kiali/handlers/health.go
generated
vendored
@@ -1,10 +1,10 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"github.com/kiali/kiali/business"
|
||||
@@ -15,25 +15,25 @@ import (
|
||||
const defaultHealthRateInterval = "10m"
|
||||
|
||||
// NamespaceHealth is the API handler to get app-based health of every services in the given namespace
|
||||
func NamespaceHealth(w http.ResponseWriter, r *http.Request) {
|
||||
func NamespaceHealth(request *restful.Request, response *restful.Response) {
|
||||
// Get business layer
|
||||
business, err := business.Get()
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Services initialization error: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Services initialization error: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
p := namespaceHealthParams{}
|
||||
if ok, err := p.extract(r); !ok {
|
||||
if ok, err := p.extract(request); !ok {
|
||||
// Bad request
|
||||
RespondWithError(w, http.StatusBadRequest, err)
|
||||
RespondWithError(response.ResponseWriter, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Adjust rate interval
|
||||
rateInterval, err := adjustRateInterval(business, p.Namespace, p.RateInterval, p.QueryTime)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -41,86 +41,86 @@ func NamespaceHealth(w http.ResponseWriter, r *http.Request) {
|
||||
case "app":
|
||||
health, err := business.Health.GetNamespaceAppHealth(p.Namespace, rateInterval, p.QueryTime)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Error while fetching app health: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Error while fetching app health: "+err.Error())
|
||||
return
|
||||
}
|
||||
RespondWithJSON(w, http.StatusOK, health)
|
||||
RespondWithJSON(response.ResponseWriter, http.StatusOK, health)
|
||||
case "service":
|
||||
health, err := business.Health.GetNamespaceServiceHealth(p.Namespace, rateInterval, p.QueryTime)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Error while fetching service health: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Error while fetching service health: "+err.Error())
|
||||
return
|
||||
}
|
||||
RespondWithJSON(w, http.StatusOK, health)
|
||||
RespondWithJSON(response.ResponseWriter, http.StatusOK, health)
|
||||
case "workload":
|
||||
health, err := business.Health.GetNamespaceWorkloadHealth(p.Namespace, rateInterval, p.QueryTime)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Error while fetching workload health: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Error while fetching workload health: "+err.Error())
|
||||
return
|
||||
}
|
||||
RespondWithJSON(w, http.StatusOK, health)
|
||||
RespondWithJSON(response.ResponseWriter, http.StatusOK, health)
|
||||
}
|
||||
}
|
||||
|
||||
// AppHealth is the API handler to get health of a single app
|
||||
func AppHealth(w http.ResponseWriter, r *http.Request) {
|
||||
func AppHealth(request *restful.Request, response *restful.Response) {
|
||||
business, err := business.Get()
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Services initialization error: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Services initialization error: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
p := appHealthParams{}
|
||||
p.extract(r)
|
||||
p.extract(request)
|
||||
rateInterval, err := adjustRateInterval(business, p.Namespace, p.RateInterval, p.QueryTime)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
health, err := business.Health.GetAppHealth(p.Namespace, p.App, rateInterval, p.QueryTime)
|
||||
handleHealthResponse(w, health, err)
|
||||
handleHealthResponse(response.ResponseWriter, health, err)
|
||||
}
|
||||
|
||||
// WorkloadHealth is the API handler to get health of a single workload
|
||||
func WorkloadHealth(w http.ResponseWriter, r *http.Request) {
|
||||
func WorkloadHealth(request *restful.Request, response *restful.Response) {
|
||||
business, err := business.Get()
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Services initialization error: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Services initialization error: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
p := workloadHealthParams{}
|
||||
p.extract(r)
|
||||
p.extract(request)
|
||||
rateInterval, err := adjustRateInterval(business, p.Namespace, p.RateInterval, p.QueryTime)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error())
|
||||
return
|
||||
}
|
||||
p.RateInterval = rateInterval
|
||||
|
||||
health, err := business.Health.GetWorkloadHealth(p.Namespace, p.Workload, rateInterval, p.QueryTime)
|
||||
handleHealthResponse(w, health, err)
|
||||
handleHealthResponse(response.ResponseWriter, health, err)
|
||||
}
|
||||
|
||||
// ServiceHealth is the API handler to get health of a single service
|
||||
func ServiceHealth(w http.ResponseWriter, r *http.Request) {
|
||||
func ServiceHealth(request *restful.Request, response *restful.Response) {
|
||||
business, err := business.Get()
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Services initialization error: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Services initialization error: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
p := serviceHealthParams{}
|
||||
p.extract(r)
|
||||
p.extract(request)
|
||||
rateInterval, err := adjustRateInterval(business, p.Namespace, p.RateInterval, p.QueryTime)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
health, err := business.Health.GetServiceHealth(p.Namespace, p.Service, rateInterval, p.QueryTime)
|
||||
handleHealthResponse(w, health, err)
|
||||
handleHealthResponse(response.ResponseWriter, health, err)
|
||||
}
|
||||
|
||||
func handleHealthResponse(w http.ResponseWriter, health interface{}, err error) {
|
||||
@@ -152,14 +152,15 @@ type baseHealthParams struct {
|
||||
QueryTime time.Time
|
||||
}
|
||||
|
||||
func (p *baseHealthParams) baseExtract(r *http.Request, vars map[string]string) {
|
||||
func (p *baseHealthParams) baseExtract(request *restful.Request) {
|
||||
p.RateInterval = defaultHealthRateInterval
|
||||
p.QueryTime = util.Clock.Now()
|
||||
queryParams := r.URL.Query()
|
||||
if rateIntervals, ok := queryParams["rateInterval"]; ok && len(rateIntervals) > 0 {
|
||||
p.RateInterval = rateIntervals[0]
|
||||
p.QueryTime = time.Now()
|
||||
|
||||
if len(request.QueryParameter("rateInterval")) > 0 {
|
||||
p.RateInterval = request.QueryParameter("rateInterval")
|
||||
}
|
||||
p.Namespace = vars["namespace"]
|
||||
|
||||
p.Namespace = request.PathParameter("namespace")
|
||||
}
|
||||
|
||||
// namespaceHealthParams holds the path and query parameters for NamespaceHealth
|
||||
@@ -175,19 +176,17 @@ type namespaceHealthParams struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func (p *namespaceHealthParams) extract(r *http.Request) (bool, string) {
|
||||
vars := mux.Vars(r)
|
||||
p.baseExtract(r, vars)
|
||||
func (p *namespaceHealthParams) extract(request *restful.Request) (bool, string) {
|
||||
p.baseExtract(request)
|
||||
p.Type = "app"
|
||||
queryParams := r.URL.Query()
|
||||
if healthTypes, ok := queryParams["type"]; ok && len(healthTypes) > 0 {
|
||||
if healthTypes[0] != "app" && healthTypes[0] != "service" && healthTypes[0] != "workload" {
|
||||
// Bad request
|
||||
return false, "Bad request, query parameter 'type' must be one of ['app','service','workload']"
|
||||
}
|
||||
p.Type = healthTypes[0]
|
||||
tp := request.QueryParameter("type")
|
||||
switch tp {
|
||||
case "app", "service", "workload":
|
||||
p.Type = tp
|
||||
return true, ""
|
||||
}
|
||||
return true, ""
|
||||
|
||||
return false, "Bad request, query parameter 'type' must be one of ['app','service','workload']"
|
||||
}
|
||||
|
||||
// appHealthParams holds the path and query parameters for AppHealth
|
||||
@@ -201,10 +200,9 @@ type appHealthParams struct {
|
||||
App string `json:"app"`
|
||||
}
|
||||
|
||||
func (p *appHealthParams) extract(r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
p.baseExtract(r, vars)
|
||||
p.App = vars["app"]
|
||||
func (p *appHealthParams) extract(request *restful.Request) {
|
||||
p.baseExtract(request)
|
||||
p.App = request.PathParameter("app")
|
||||
}
|
||||
|
||||
// serviceHealthParams holds the path and query parameters for ServiceHealth
|
||||
@@ -218,10 +216,9 @@ type serviceHealthParams struct {
|
||||
Service string `json:"service"`
|
||||
}
|
||||
|
||||
func (p *serviceHealthParams) extract(r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
p.baseExtract(r, vars)
|
||||
p.Service = vars["service"]
|
||||
func (p *serviceHealthParams) extract(request *restful.Request) {
|
||||
p.baseExtract(request)
|
||||
p.Service = request.PathParameter("service")
|
||||
}
|
||||
|
||||
// workloadHealthParams holds the path and query parameters for WorkloadHealth
|
||||
@@ -235,10 +232,9 @@ type workloadHealthParams struct {
|
||||
Workload string `json:"workload"`
|
||||
}
|
||||
|
||||
func (p *workloadHealthParams) extract(r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
p.baseExtract(r, vars)
|
||||
p.Workload = vars["workload"]
|
||||
func (p *workloadHealthParams) extract(request *restful.Request) {
|
||||
p.baseExtract(request)
|
||||
p.Workload = request.PathParameter("workload")
|
||||
}
|
||||
|
||||
func adjustRateInterval(business *business.Layer, namespace, rateInterval string, queryTime time.Time) (string, error) {
|
||||
|
||||
20
vendor/github.com/kiali/kiali/handlers/namespaces.go
generated
vendored
20
vendor/github.com/kiali/kiali/handlers/namespaces.go
generated
vendored
@@ -1,10 +1,9 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/kiali/kiali/business"
|
||||
"github.com/kiali/kiali/log"
|
||||
"github.com/kiali/kiali/prometheus"
|
||||
@@ -31,28 +30,27 @@ func NamespaceList(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// NamespaceMetrics is the API handler to fetch metrics to be displayed, related to all
|
||||
// services in the namespace
|
||||
func NamespaceMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
getNamespaceMetrics(w, r, defaultPromClientSupplier, defaultK8SClientSupplier)
|
||||
func NamespaceMetrics(request *restful.Request, response *restful.Response) {
|
||||
getNamespaceMetrics(request, response, defaultPromClientSupplier, defaultK8SClientSupplier)
|
||||
}
|
||||
|
||||
// getServiceMetrics (mock-friendly version)
|
||||
func getNamespaceMetrics(w http.ResponseWriter, r *http.Request, promSupplier promClientSupplier, k8sSupplier k8sClientSupplier) {
|
||||
vars := mux.Vars(r)
|
||||
namespace := vars["namespace"]
|
||||
func getNamespaceMetrics(request *restful.Request, response *restful.Response, promSupplier promClientSupplier, k8sSupplier k8sClientSupplier) {
|
||||
namespace := request.PathParameters()["namespace"]
|
||||
|
||||
prom, _, namespaceInfo := initClientsForMetrics(w, promSupplier, k8sSupplier, namespace)
|
||||
prom, _, namespaceInfo := initClientsForMetrics(response.ResponseWriter, promSupplier, k8sSupplier, namespace)
|
||||
if prom == nil {
|
||||
// any returned value nil means error & response already written
|
||||
return
|
||||
}
|
||||
|
||||
params := prometheus.IstioMetricsQuery{Namespace: namespace}
|
||||
err := extractIstioMetricsQueryParams(r, ¶ms, namespaceInfo)
|
||||
err := extractIstioMetricsQueryParams(request.Request, ¶ms, namespaceInfo)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusBadRequest, err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
metrics := prom.GetMetrics(¶ms)
|
||||
RespondWithJSON(w, http.StatusOK, metrics)
|
||||
RespondWithJSON(response.ResponseWriter, http.StatusOK, metrics)
|
||||
}
|
||||
|
||||
20
vendor/github.com/kiali/kiali/handlers/services.go
generated
vendored
20
vendor/github.com/kiali/kiali/handlers/services.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
@@ -36,31 +37,30 @@ func ServiceList(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// ServiceMetrics is the API handler to fetch metrics to be displayed, related to a single service
|
||||
func ServiceMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
getServiceMetrics(w, r, defaultPromClientSupplier, defaultK8SClientSupplier)
|
||||
func ServiceMetrics(request *restful.Request, response *restful.Response) {
|
||||
getServiceMetrics(request, response, defaultPromClientSupplier, defaultK8SClientSupplier)
|
||||
}
|
||||
|
||||
// getServiceMetrics (mock-friendly version)
|
||||
func getServiceMetrics(w http.ResponseWriter, r *http.Request, promSupplier promClientSupplier, k8sSupplier k8sClientSupplier) {
|
||||
vars := mux.Vars(r)
|
||||
namespace := vars["namespace"]
|
||||
service := vars["service"]
|
||||
func getServiceMetrics(request *restful.Request, response *restful.Response, promSupplier promClientSupplier, k8sSupplier k8sClientSupplier) {
|
||||
namespace := request.PathParameters()["namespace"]
|
||||
service := request.PathParameters()["service"]
|
||||
|
||||
prom, _, namespaceInfo := initClientsForMetrics(w, promSupplier, k8sSupplier, namespace)
|
||||
prom, _, namespaceInfo := initClientsForMetrics(response.ResponseWriter, promSupplier, k8sSupplier, namespace)
|
||||
if prom == nil {
|
||||
// any returned value nil means error & response already written
|
||||
return
|
||||
}
|
||||
|
||||
params := prometheus.IstioMetricsQuery{Namespace: namespace, Service: service}
|
||||
err := extractIstioMetricsQueryParams(r, ¶ms, namespaceInfo)
|
||||
err := extractIstioMetricsQueryParams(request.Request, ¶ms, namespaceInfo)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusBadRequest, err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
metrics := prom.GetMetrics(¶ms)
|
||||
RespondWithJSON(w, http.StatusOK, metrics)
|
||||
RespondWithJSON(response.ResponseWriter, http.StatusOK, metrics)
|
||||
}
|
||||
|
||||
// ServiceDetails is the API handler to fetch full details of an specific service
|
||||
|
||||
20
vendor/github.com/kiali/kiali/handlers/workloads.go
generated
vendored
20
vendor/github.com/kiali/kiali/handlers/workloads.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
@@ -60,31 +61,30 @@ func WorkloadDetails(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// WorkloadMetrics is the API handler to fetch metrics to be displayed, related to a single workload
|
||||
func WorkloadMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
getWorkloadMetrics(w, r, defaultPromClientSupplier, defaultK8SClientSupplier)
|
||||
func WorkloadMetrics(request *restful.Request, response *restful.Response) {
|
||||
getWorkloadMetrics(request, response, defaultPromClientSupplier, defaultK8SClientSupplier)
|
||||
}
|
||||
|
||||
// getWorkloadMetrics (mock-friendly version)
|
||||
func getWorkloadMetrics(w http.ResponseWriter, r *http.Request, promSupplier promClientSupplier, k8sSupplier k8sClientSupplier) {
|
||||
vars := mux.Vars(r)
|
||||
namespace := vars["namespace"]
|
||||
workload := vars["workload"]
|
||||
func getWorkloadMetrics(request *restful.Request, response *restful.Response, promSupplier promClientSupplier, k8sSupplier k8sClientSupplier) {
|
||||
namespace := request.PathParameter("namespace")
|
||||
workload := request.PathParameter("workload")
|
||||
|
||||
prom, _, namespaceInfo := initClientsForMetrics(w, promSupplier, k8sSupplier, namespace)
|
||||
prom, _, namespaceInfo := initClientsForMetrics(response.ResponseWriter, promSupplier, k8sSupplier, namespace)
|
||||
if prom == nil {
|
||||
// any returned value nil means error & response already written
|
||||
return
|
||||
}
|
||||
|
||||
params := prometheus.IstioMetricsQuery{Namespace: namespace, Workload: workload}
|
||||
err := extractIstioMetricsQueryParams(r, ¶ms, namespaceInfo)
|
||||
err := extractIstioMetricsQueryParams(request.Request, ¶ms, namespaceInfo)
|
||||
if err != nil {
|
||||
RespondWithError(w, http.StatusBadRequest, err.Error())
|
||||
RespondWithError(response.ResponseWriter, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
metrics := prom.GetMetrics(¶ms)
|
||||
RespondWithJSON(w, http.StatusOK, metrics)
|
||||
RespondWithJSON(response, http.StatusOK, metrics)
|
||||
}
|
||||
|
||||
// WorkloadDashboard is the API handler to fetch Istio dashboard, related to a single workload
|
||||
|
||||
9
vendor/github.com/kiali/kiali/models/destination_rule.go
generated
vendored
9
vendor/github.com/kiali/kiali/models/destination_rule.go
generated
vendored
@@ -79,16 +79,17 @@ func (dRule *DestinationRule) HasCircuitBreaker(namespace string, serviceName st
|
||||
return false
|
||||
}
|
||||
|
||||
// change circuit breaker to true only connectionPool and outlierDetection
|
||||
// are both set
|
||||
func isCircuitBreakerTrafficPolicy(trafficPolicy interface{}) bool {
|
||||
if trafficPolicy == nil {
|
||||
return false
|
||||
}
|
||||
if dTrafficPolicy, ok := trafficPolicy.(map[string]interface{}); ok {
|
||||
if _, ok := dTrafficPolicy["connectionPool"]; ok {
|
||||
return true
|
||||
}
|
||||
if _, ok := dTrafficPolicy["outlierDetection"]; ok {
|
||||
return true
|
||||
if _, ok := dTrafficPolicy["outlierDetection"]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
1
vendor/github.com/knative/pkg
generated
vendored
1
vendor/github.com/knative/pkg
generated
vendored
Submodule vendor/github.com/knative/pkg deleted from f8007289b2
201
vendor/github.com/knative/pkg/LICENSE
generated
vendored
Normal file
201
vendor/github.com/knative/pkg/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
21
vendor/github.com/knative/pkg/apis/istio/authentication/register.go
generated
vendored
Normal file
21
vendor/github.com/knative/pkg/apis/istio/authentication/register.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright 2018 The Knative 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 authentication
|
||||
|
||||
const (
|
||||
GroupName = "authentication.istio.io"
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user