提交 aa4d07c8 编写于 作者: J Jeff 提交者: zryfish

add controllers

change kiali mux to go-restful

add knative
上级 4c7c8377
[submodule "vendor/github.com/knative/pkg"]
path = vendor/github.com/knative/pkg
url = https://github.com/knative/pkg.git
......@@ -15,12 +15,11 @@ 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 && bash hack/docker_build.sh
deploy:
skip_cleanup: true
......
此差异已折叠。
......@@ -14,7 +14,6 @@ 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"
......@@ -32,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"
......@@ -109,3 +112,7 @@ required = [
[[constraint]]
name = "github.com/gorilla/mux"
version = "1.7.0"
[[constraint]]
branch = "master"
name = "github.com/knative/pkg"
......@@ -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/...
......
......@@ -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
......
package app
import (
"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/informers"
"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.SharedInformerFactory()
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(),
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
}
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,93 +20,59 @@ 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
var metricsAddr, kubeConfigPath, masterURL 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")
log := logf.Log.WithName("controller-manager")
// Get a config to talk to the apiserver
log.Info("setting up client for manager")
cfg, err := k8s.Config()
kubeConfig, err := clientcmd.BuildConfigFromFlags(masterURL, kubeConfigPath)
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{})
mgr, err := manager.New(kubeConfig, manager.Options{})
if err != nil {
log.Error(err, "unable to set up overall controller manager")
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")
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")
if err := app.AddControllers(mgr, kubeConfig, stopCh); err != nil {
log.Error(err, "unable to register 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)
}
}
......@@ -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
......
......@@ -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 .
\ No newline at end of file
docker build -f build/ks-iam/Dockerfile -t kubespheredev/ks-iam:latest .
docker build -f build/controller-manager/Dockerfile -t kubespheredev/controller-manager:latest .
\ No newline at end of file
......@@ -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/controller-manager:latest
......@@ -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() {
......
......@@ -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"`
......
......@@ -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,10 @@ 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)
}
/*
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
}
/*
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
/*
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}
}
/*
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
/*
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))
}
/*
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
/*
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))
}
/*
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
/*
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
/*
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) 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
}
/*
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
}
/*
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 StrategyExpansion interface{}
/*
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
StrategiesGetter
}
// ServicemeshV1alpha2Client is used to interact with features provided by the servicemesh.kubesphere.io group.
type ServicemeshV1alpha2Client struct {
restClient rest.Interface
}
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
}
/*
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
}
/*
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)
}
/*
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("strategies"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Servicemesh().V1alpha2().Strategies().Informer()}, nil
}
return nil, fmt.Errorf("no informer found for %v", resource)
}
/*
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)
/*
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)
}
/*
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 {
// 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}
}
// Strategies returns a StrategyInformer.
func (v *version) Strategies() StrategyInformer {
return &strategyInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
/*
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())
}
/*
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
// StrategyListerExpansion allows custom methods to be added to
// StrategyLister.
type StrategyListerExpansion interface{}
// StrategyNamespaceListerExpansion allows custom methods to be added to
// StrategyNamespaceLister.
type StrategyNamespaceListerExpansion interface{}
/*
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
}
......@@ -18,6 +18,7 @@ package controller
import (
"kubesphere.io/kubesphere/pkg/controller/strategy"
"sigs.k8s.io/application/pkg/controller/application"
)
func init() {
......@@ -25,6 +26,6 @@ func init() {
AddToManagerFuncs = append(AddToManagerFuncs, strategy.Add)
// Add application to manager functions
//AddToManagerFuncs = append(AddToManagerFuncs, application.Add)
AddToManagerFuncs = append(AddToManagerFuncs, application.Add)
}
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"
"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"
)
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
destinationRuleLister istiolisters.DestinationRuleLister
destinationRuleSynced cache.InformerSynced
queue workqueue.RateLimitingInterface
workerLoopPeriod time.Duration
}
func NewDestinationRuleController(deploymentInformer informersv1.DeploymentInformer,
destinationRuleInformer istioinformers.DestinationRuleInformer,
serviceInformer coreinformers.ServiceInformer,
client clientset.Interface,
destinationRuleClient istioclientset.Interface) *DestinationRuleController {
broadcaster := record.NewBroadcaster()
broadcaster.StartLogging(log.Info)
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,
})
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.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) {
return
}
for i := 0; i < workers; i++ {
go wait.Until(v.worker, v.workerLoopPeriod, stopCh)
}
go func() {
defer utilruntime.HandleCrash()
}()
<-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
}
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 err != nil && !errors.IsNotFound(err) {
return err
}
return nil
}
if len(service.Labels) < len(util.ApplicationLabels) || !util.IsApplicationComponent(&service.ObjectMeta) ||
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
}
deployments, err := v.deploymentLister.Deployments(namespace).List(labels.Set(service.Spec.Selector).AsSelectorPreValidated())
if err != nil {
return err
}
subsets := []v1alpha3.Subset{}
for _, deployment := range deployments {
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(name),
Labels: map[string]string{
util.VersionLabel: name,
},
}
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,
},
}
}
log.Error(err, "Couldn't get destinationrule for service", "key", key)
return err
}
createDestinationRule := len(currentDestinationRule.Spec.Subsets) == 0
if !createDestinationRule && reflect.DeepEqual(currentDestinationRule.Spec.Subsets, subsets) &&
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.Subsets = subsets
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.Eventf(newDestinationRule, v1.EventTypeWarning, "FailedToCreateDestinationRule", "Failed to create destinationrule for service %v/%v: %v", service.Namespace, service.Name, err)
} else {
v.eventRecorder.Eventf(newDestinationRule, v1.EventTypeWarning, "FailedToUpdateDestinationRule", "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)
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 {
// 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) 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(0).Info("Dropping service out of the queue", "key", key, "error", err)
v.queue.Forget(key)
utilruntime.HandleError(err)
}
package strategy
import (
"fmt"
"github.com/knative/pkg/apis/istio/v1alpha3"
"k8s.io/api/core/v1"
"kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
)
const (
AppLabel = "app"
)
func getAppNameByStrategy(strategy *v1alpha2.Strategy) string {
if len(strategy.Labels) > 0 && len(strategy.Labels[AppLabel]) > 0 {
return strategy.Labels[AppLabel]
}
return ""
}
func fillDestinationPort(vs *v1alpha3.VirtualService, service *v1.Service) error {
if len(service.Spec.Ports) == 0 {
return fmt.Errorf("service %s/%s spec doesn't canotain any ports", service.Namespace, service.Name)
}
// fill http port
for i := range vs.Spec.Http {
for j := range vs.Spec.Http[i].Route {
vs.Spec.Http[i].Route[j].Destination.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 {
vs.Spec.Tcp[i].Route[j].Destination.Port.Number = uint32(service.Spec.Ports[0].Port)
}
}
return nil
}
......@@ -18,17 +18,17 @@ package strategy
import (
"context"
"fmt"
"github.com/knative/pkg/apis/istio/v1alpha3"
"reflect"
"k8s.io/api/core/v1"
"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"
"reflect"
"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"
......@@ -36,7 +36,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"
)
var log = logf.Log.WithName("controller")
var log = logf.Log.WithName("strategy-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.
......@@ -62,10 +62,6 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
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
......@@ -97,47 +93,50 @@ type ReconcileStrategy struct {
// +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,
}
return r.reconcileStrategy(strategy)
}
if err := controllerutil.SetControllerReference(strategy, vs, r.scheme); err != nil {
return reconcile.Result{}, err
func (r *ReconcileStrategy) reconcileStrategy(strategy *servicemeshv1alpha2.Strategy) (reconcile.Result, error) {
appName := getAppNameByStrategy(strategy)
service := &v1.Service{}
err := r.Get(context.TODO(), types.NamespacedName{Namespace: strategy.Namespace, Name: appName}, service)
if err != nil {
log.Error(err, "couldn't find service %s/%s,", strategy.Namespace, appName)
return reconcile.Result{}, errors.NewBadRequest(fmt.Sprintf("service %s not found", appName))
}
vs, err := r.generateVirtualService(strategy, service)
// 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) {
if !reflect.DeepEqual(vs.Spec, found.Spec) || len(vs.OwnerReferences) == 0 {
found.Spec = vs.Spec
found.OwnerReferences = vs.OwnerReferences
log.Info("Updating VirtualService", "namespace", vs.Namespace, "name", vs.Name)
err = r.Update(context.TODO(), found)
if err != nil {
......@@ -146,3 +145,48 @@ func (r *ReconcileStrategy) Reconcile(request reconcile.Request) (reconcile.Resu
}
return reconcile.Result{}, nil
}
func (r *ReconcileStrategy) generateVirtualService(strategy *servicemeshv1alpha2.Strategy, service *v1.Service) (*v1alpha3.VirtualService, error) {
// Define VirtualService to be created
vs := &v1alpha3.VirtualService{
ObjectMeta: metav1.ObjectMeta{
Name: getAppNameByStrategy(strategy),
Namespace: strategy.Namespace,
Labels: strategy.Spec.Selector.MatchLabels,
},
Spec: strategy.Spec.Template.Spec,
}
// one version rules them all
if len(strategy.Spec.GovernorVersion) > 0 {
governorDestinationWeight := v1alpha3.DestinationWeight{
Destination: v1alpha3.Destination{
Host: getAppNameByStrategy(strategy),
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}
}
}
if err := fillDestinationPort(vs, service); err != nil {
return nil, err
}
return vs, nil
}
......@@ -19,6 +19,7 @@ package strategy
import (
"github.com/knative/pkg/apis/istio/common/v1alpha1"
"github.com/knative/pkg/apis/istio/v1alpha3"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/json"
"testing"
"time"
......@@ -37,23 +38,47 @@ import (
var c client.Client
var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo", Namespace: "default"}}
var depKey = types.NamespacedName{Name: "foo-virtualservice", Namespace: "default"}
var depKey = types.NamespacedName{Name: "details", Namespace: "default"}
const timeout = time.Second * 5
var labels = map[string]string{
"app.kubernetes.io/name": "details",
"app.kubernetes.io/version": "v1",
"app": "details",
"servicemesh.kubesphere.io/enabled": "",
}
var svc = v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "details",
Namespace: "default",
Labels: labels,
},
Spec: v1.ServiceSpec{
Ports: []v1.ServicePort{
{
Name: "http",
Port: 8080,
Protocol: v1.ProtocolTCP,
},
},
Selector: labels,
},
}
func TestReconcile(t *testing.T) {
g := gomega.NewGomegaWithT(t)
instance := &servicemeshv1alpha2.Strategy{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "default",
Labels: labels,
},
Spec: servicemeshv1alpha2.StrategySpec{
Type: servicemeshv1alpha2.CanaryType,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"type": "Canary",
},
MatchLabels: labels,
},
Template: servicemeshv1alpha2.VirtualServiceTemplateSpec{
Spec: v1alpha3.VirtualServiceSpec{
......@@ -111,6 +136,14 @@ func TestReconcile(t *testing.T) {
mgrStopped.Wait()
}()
err = c.Create(context.TODO(), &svc)
if apierrors.IsInvalid(err) {
t.Logf("failed to create service, %v", err)
return
}
g.Expect(err).NotTo(gomega.HaveOccurred())
//defer c.Delete(context.TODO(), &svc)
// 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.
......@@ -119,6 +152,7 @@ func TestReconcile(t *testing.T) {
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)))
......@@ -133,11 +167,11 @@ func TestReconcile(t *testing.T) {
// 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(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"))
Should(gomega.MatchError("virtualservices.networking.istio.io \"details\" not found"))
}
package util
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"
ServiceMeshEnabledLabel = "servicemesh.kubesphere.io/enabled"
)
// resource with these following labels considered as part of servicemesh
var ApplicationLabels = [...]string{
ApplicationNameLabel,
ApplicationVersionLabel,
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, 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
}
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/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"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"
"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"
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(log.Info)
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{}) {
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.deleteStrategy,
})
v.destinationRuleLister = destinationRuleInformer.Lister()
v.destinationRuleSynced = destinationRuleInformer.Informer().HasSynced
destinationRuleInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: v.addDestinationRule,
})
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)
}
go func() {
defer utilruntime.HandleCrash()
}()
<-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
}
func (v *VirtualServiceController) syncService(key string) error {
startTime := time.Now()
defer func() {
log.V(4).Info("Finished syncing service virtualservice. ", "service", 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 virtualservice, as the service has been deleted.
err = v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Delete(service.Name, nil)
if err != nil && !errors.IsNotFound(err) {
return err
}
return nil
}
if len(service.Labels) < len(util.ApplicationLabels) || !util.IsApplicationComponent(&service.ObjectMeta) ||
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
}
vs, err := v.virtualServiceLister.VirtualServices(namespace).Get(name)
if err == nil {
// there already is virtual service there, no need to create another one
return nil
}
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
return nil
}
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("find destinationrule with no subsets for service %s", name)
log.Error(err, "Find destinationrule with no subsets for service", "service", service.String())
return err
} else {
vs = &v1alpha3.VirtualService{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: util.ExtractApplicationLabels(&service.ObjectMeta),
},
Spec: v1alpha3.VirtualServiceSpec{
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}}}
}
}
if len(vs.Spec.Http) > 0 || len(vs.Spec.Tcp) > 0 {
_, err := v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Create(vs)
if err != nil {
v.eventRecorder.Eventf(vs, v1.EventTypeWarning, "FailedToCreateVirtualService", "Failed to create virtualservice for service %v/%v: %v", service.Namespace, service.Name, err)
log.Error(err, "create virtualservice for service failed.", "service", service)
return err
}
} else {
log.Info("service doesn't have a tcp port.")
return nil
}
}
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(0).Info("service not created yet", "key", 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
}
func (v *VirtualServiceController) deleteStrategy(obj interface{}) {
// nothing to do right now
}
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(0).Info("Dropping service %q out of the queue: %v", "key", key, "error", err)
v.queue.Forget(key)
utilruntime.HandleError(err)
}
......@@ -27,4 +27,4 @@ const (
QueryLevelWorkload
QueryLevelPod
QueryLevelContainer
)
\ No newline at end of file
)
......@@ -306,4 +306,4 @@ func GetWorkspaceOfNamesapce(namespace string) string {
}
return workspace
}
\ No newline at end of file
}
......@@ -61,4 +61,4 @@ type OutputDBBinding struct {
Internal bool
Enable bool `gorm:"not null"`
Updatetime time.Time `gorm:"not null"`
}
\ No newline at end of file
}
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
}
......@@ -18,6 +18,7 @@
package prometheus
import (
"flag"
"io/ioutil"
"net/http"
"net/url"
......@@ -25,8 +26,6 @@ import (
"strings"
"time"
"os"
"github.com/emicklei/go-restful"
"github.com/golang/glog"
)
......@@ -46,10 +45,7 @@ var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc"
var PrometheusAPIEndpoint string
func init() {
if env := os.Getenv(PrometheusAPIServerEnv); env != "" {
PrometheusAPIServer = env
}
PrometheusAPIEndpoint = DefaultScheme + "://" + PrometheusAPIServer + ":" + DefaultPrometheusPort + PrometheusApiPath
flag.StringVar(&PrometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1", "")
}
type MonitoringRequestParams struct {
......
......@@ -85,7 +85,7 @@ func NewNamespaceController(
return controller
}
func (c *NamespaceController) Start(stopCh <-chan struct{}) {
func (c *NamespaceController) Start(stopCh <-chan struct{}) error {
go func() {
defer utilruntime.HandleCrash()
defer c.workqueue.ShutDown()
......@@ -109,6 +109,8 @@ func (c *NamespaceController) Start(stopCh <-chan struct{}) {
<-stopCh
glog.Info("shutting down workers")
}()
return nil
}
func (c *NamespaceController) runWorker() {
......
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.
此差异已折叠。
此差异已折叠。
......@@ -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
......
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, &params, namespaceInfo)
err := extractIstioMetricsQueryParams(request.Request, &params, namespaceInfo)
if err != nil {
RespondWithError(w, http.StatusBadRequest, err.Error())
RespondWithError(response.ResponseWriter, http.StatusBadRequest, err.Error())
return
}
metrics := prom.GetMetrics(&params)
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
......
......@@ -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"
)
func GetNamespaceGraph(request * restful.Request, response *restful.Response) {
defer handlePanic(response.ResponseWriter)
client, err := prometheus.NewClient()
graph.CheckError(err)
graphNamespaces(request, response, client)
}
// 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 GraphNamespaces(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 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))
......
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, &params, namespaceInfo)
err := extractIstioMetricsQueryParams(request.Request, &params, namespaceInfo)
if err != nil {
RespondWithError(w, http.StatusBadRequest, err.Error())
RespondWithError(response.ResponseWriter, http.StatusBadRequest, err.Error())
return
}
metrics := prom.GetMetrics(&params)
RespondWithJSON(w, http.StatusOK, metrics)
RespondWithJSON(response.ResponseWriter, http.StatusOK, metrics)
}
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, &params, namespaceInfo)
err := extractIstioMetricsQueryParams(request.Request, &params, namespaceInfo)
if err != nil {
RespondWithError(w, http.StatusBadRequest, err.Error())
RespondWithError(response.ResponseWriter, http.StatusBadRequest, err.Error())
return
}
metrics := prom.GetMetrics(&params)
RespondWithJSON(w, http.StatusOK, metrics)
RespondWithJSON(response.ResponseWriter, http.StatusOK, metrics)
}
// ServiceDetails is the API handler to fetch full details of an specific service
......
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, &params, namespaceInfo)
err := extractIstioMetricsQueryParams(request.Request, &params, namespaceInfo)
if err != nil {
RespondWithError(w, http.StatusBadRequest, err.Error())
RespondWithError(response.ResponseWriter, http.StatusBadRequest, err.Error())
return
}
metrics := prom.GetMetrics(&params)
RespondWithJSON(w, http.StatusOK, metrics)
RespondWithJSON(response, http.StatusOK, metrics)
}
// WorkloadDashboard is the API handler to fetch Istio dashboard, related to a single workload
......
Subproject commit f8007289b228598dfdf7e6de67ee5f5c391c9d34
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册