From b6dd77e2b557c1c25a7f86d30921da6e49f3fe02 Mon Sep 17 00:00:00 2001 From: Yeh-lei Wu Date: Fri, 12 Apr 2019 21:33:34 +0800 Subject: [PATCH 01/13] Separate and ensure setup before e2e-build (#375) * Ensure check-setup before build Signed-off-by: Aylei * Separate e2e-setup and check-setupt Signed-off-by: Aylei * Update docs accordingly Signed-off-by: Aylei * Refine grammar Signed-off-by: Aylei --- Makefile | 9 ++++++--- docs/CONTRIBUTING.md | 17 ++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 10afb27e39..470dee6994 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,10 @@ scheduler: discovery: $(GO) -ldflags '$(LDFLAGS)' -o images/tidb-operator/bin/tidb-discovery cmd/discovery/main.go +e2e-setup: + # ginkgo doesn't work with retool for Go 1.11 + @GO111MODULE=on CGO_ENABLED=0 go get github.com/onsi/ginkgo@v1.6.0 + e2e-docker-push: e2e-docker docker push "${DOCKER_REGISTRY}/pingcap/tidb-operator-e2e:latest" @@ -50,7 +54,7 @@ e2e-docker: e2e-build cp -r charts/tidb-backup tests/images/e2e docker build -t "${DOCKER_REGISTRY}/pingcap/tidb-operator-e2e:latest" tests/images/e2e -e2e-build: +e2e-build: e2e-setup $(GO) -ldflags '$(LDFLAGS)' -o tests/images/e2e/bin/e2e tests/cmd/e2e/main.go stability-test-build: @@ -74,10 +78,9 @@ check-all: lint check-static check-shadow check-gosec megacheck errcheck check-setup: @which retool >/dev/null 2>&1 || go get github.com/twitchtv/retool @GO111MODULE=off retool sync - # ginkgo and govet doesn't work with retool for Go 1.11 + # govet doesn't work with retool for Go 1.11 # so install separately @GO111MODULE=on CGO_ENABLED=0 go get github.com/dnephin/govet@4a96d43e39d340b63daa8bc5576985aa599885f6 - @GO111MODULE=on CGO_ENABLED=0 go get github.com/onsi/ginkgo@v1.6.0 check: check-setup lint check-static diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 06fc1ba6c1..677c253951 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -96,14 +96,6 @@ $ git checkout -b myfeature ### Step 4: Develop -#### Setup - -Make sure all the related tools are properly installed. - -```sh -$ make check-setup -``` - #### Edit the code You can now edit the code on the `myfeature` branch. @@ -152,7 +144,14 @@ $ git rebase upstream/master ### Step 6: Commit -Commit your changes. +Before you commit, make sure that all the checks and unit tests are passed: + +```sh +$ make check +$ meke test +``` + +Then commit your changes. ```sh $ git commit From 3a60132e1c40e6c7c63ca9194e092b6e1534a43f Mon Sep 17 00:00:00 2001 From: Yeh-lei Wu Date: Fri, 12 Apr 2019 23:19:28 +0800 Subject: [PATCH 02/13] Fix codegen.sh and lock related depedencies (#371) Signed-off-by: Aylei --- go.mod | 7 ++- go.sum | 15 ++++- hack/codegen.sh | 2 +- hack/generate-groups.sh | 10 +-- pkg/client/clientset/versioned/clientset.go | 2 - .../versioned/fake/clientset_generated.go | 9 +-- .../clientset/versioned/fake/register.go | 16 ++--- .../clientset/versioned/scheme/register.go | 16 ++--- .../v1alpha1/fake/fake_tidbcluster.go | 2 +- .../informers/externalversions/factory.go | 61 +++++++++++++++++-- tools/tools.go | 3 + 11 files changed, 104 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index 0ded357e45..3df29ee161 100644 --- a/go.mod +++ b/go.mod @@ -80,11 +80,10 @@ require ( go.uber.org/atomic v1.3.2 // indirect go.uber.org/multierr v1.1.0 // indirect go.uber.org/zap v1.9.1 // indirect - golang.org/x/crypto v0.0.0-20180807104621-f027049dab0a // indirect - golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e + golang.org/x/net v0.0.0-20190311183353-d8887717615a golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 // indirect - golang.org/x/sys v0.0.0-20180807162357-acbc56fc7007 // indirect golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 // indirect + golang.org/x/tools v0.0.0-20190405180640-052fc3cfdbc2 // indirect google.golang.org/genproto v0.0.0-20180731170733-daca94659cb5 // indirect google.golang.org/grpc v1.12.0 // indirect gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect @@ -102,6 +101,8 @@ require ( k8s.io/apiserver v0.0.0-20190118115647-a748535592ba k8s.io/cli-runtime v0.0.0-20190118125240-caee4253d968 k8s.io/client-go v2.0.0-alpha.0.0.20190115164855-701b91367003+incompatible + k8s.io/code-generator v0.0.0-20181128191024-b1289fc74931 // indirect + k8s.io/gengo v0.0.0-20190327210449-e17681d19d3a // indirec k8s.io/klog v0.2.0 // indirect k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580 // indirect k8s.io/kubernetes v1.12.5 diff --git a/go.sum b/go.sum index 8c7f444514..4ff377357c 100644 --- a/go.sum +++ b/go.sum @@ -187,14 +187,17 @@ go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180807104621-f027049dab0a h1:PulT0Y50PcfTWomfsD39bSQyVrjjWdIuJKfyR4nOCJw= golang.org/x/crypto v0.0.0-20180807104621-f027049dab0a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180808004115-f9ce57c11b24 h1:mEsFm194MmS9vCwxFy+zwu0EU7ZkxxMD1iH++vmGdUY= golang.org/x/net v0.0.0-20180808004115-f9ce57c11b24/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= @@ -208,8 +211,8 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20190403183509-8a44e74612bc h1:9OQUxGJQk/Rt2SmlbFsqnsyFaX1YiLbBfUJezBkCaa0= -golang.org/x/tools v0.0.0-20190403183509-8a44e74612bc/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190405180640-052fc3cfdbc2 h1:rlaAa9eBBj6AI2C90gKs2Q/XF6YFbBDpGSX+npdfPlk= +golang.org/x/tools v0.0.0-20190405180640-052fc3cfdbc2/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -288,6 +291,12 @@ k8s.io/client-go v9.0.0+incompatible h1:2kqW3X2xQ9SbFvWZjGEHBLlWc1LG9JIJNXWkuqwd k8s.io/client-go v9.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34= k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/code-generator v0.0.0-20180228050103-7ead8f38b01c h1:tpq+nvY9+2K8qRsOIUzJY8Mq7sNrfisNwQLc4/Xw76o= +k8s.io/code-generator v0.0.0-20180228050103-7ead8f38b01c/go.mod h1:MYiN+ZJZ9HkETbgVZdWw2AsuAi9PZ4V80cwfuf2axe8= +k8s.io/code-generator v0.0.0-20181128191024-b1289fc74931 h1:5nlNOG+ShM9gcSivU8/IEhrANa/ljMMEJ1sw86/eFzQ= +k8s.io/code-generator v0.0.0-20181128191024-b1289fc74931/go.mod h1:MYiN+ZJZ9HkETbgVZdWw2AsuAi9PZ4V80cwfuf2axe8= +k8s.io/gengo v0.0.0-20190327210449-e17681d19d3a h1:QoHVuRquf80YZ+/bovwxoMO3Q/A3nt3yTgS0/0nejuk= +k8s.io/gengo v0.0.0-20190327210449-e17681d19d3a/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c= k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c h1:3KSCztE7gPitlZmWbNwue/2U0YruD65DqX3INopDAQM= diff --git a/hack/codegen.sh b/hack/codegen.sh index e4c0cb8a11..5d3af6db62 100755 --- a/hack/codegen.sh +++ b/hack/codegen.sh @@ -15,7 +15,7 @@ scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -${scriptdir}/generate-groups.sh \ +GO111MODULE=on ${scriptdir}/generate-groups.sh \ deepcopy,client,lister,informer \ github.com/pingcap/tidb-operator/pkg/client \ github.com/pingcap/tidb-operator/pkg/apis \ diff --git a/hack/generate-groups.sh b/hack/generate-groups.sh index 7477cfa225..d32d0c22e0 100755 --- a/hack/generate-groups.sh +++ b/hack/generate-groups.sh @@ -46,11 +46,11 @@ APIS_PKG="$3" GROUPS_WITH_VERSIONS="$4" shift 4 -GO111MODULE=on go get k8s.io/code-generator/cmd/defaulter-gen@kubernetes-1.10.2 -GO111MODULE=on go get k8s.io/code-generator/cmd/client-gen@kubernetes-1.10.2 -GO111MODULE=on go get k8s.io/code-generator/cmd/lister-gen@kubernetes-1.10.2 -GO111MODULE=on go get k8s.io/code-generator/cmd/informer-gen@kubernetes-1.10.2 -GO111MODULE=on go get k8s.io/code-generator/cmd/deepcopy-gen@kubernetes-1.10.2 +GO111MODULE=on go get k8s.io/code-generator/cmd/defaulter-gen@kubernetes-1.12.5 +GO111MODULE=on go get k8s.io/code-generator/cmd/client-gen@kubernetes-1.12.5 +GO111MODULE=on go get k8s.io/code-generator/cmd/lister-gen@kubernetes-1.12.5 +GO111MODULE=on go get k8s.io/code-generator/cmd/informer-gen@kubernetes-1.12.5 +GO111MODULE=on go get k8s.io/code-generator/cmd/deepcopy-gen@kubernetes-1.12.5 # ( # # To support running this script from anywhere, we have to first cd into this directory diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 9ea75bc0c4..0e07ee9f78 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -19,7 +19,6 @@ limitations under the License. package versioned import ( - glog "github.com/golang/glog" pingcapv1alpha1 "github.com/pingcap/tidb-operator/pkg/client/clientset/versioned/typed/pingcap.com/v1alpha1" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" @@ -74,7 +73,6 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) if err != nil { - glog.Errorf("failed to create the DiscoveryClient: %v", err) return nil, err } return &cs, nil diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index b4f8952f5f..2736320f4b 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -41,9 +41,10 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset { } } - fakePtr := testing.Fake{} - fakePtr.AddReactor("*", "*", testing.ObjectReaction(o)) - fakePtr.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + 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) @@ -53,7 +54,7 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset { return true, watch, nil }) - return &Clientset{fakePtr, &fakediscovery.FakeDiscovery{Fake: &fakePtr}} + return cs } // Clientset implements clientset.Interface. Meant to be embedded into a diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index c2a26e0939..d1c4a05851 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -24,15 +24,14 @@ import ( 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" ) var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) var parameterCodec = runtime.NewParameterCodec(scheme) - -func init() { - v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - AddToScheme(scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + pingcapv1alpha1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition @@ -45,10 +44,13 @@ func init() { // ) // // kclientset, _ := kubernetes.NewForConfig(c) -// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. -func AddToScheme(scheme *runtime.Scheme) { - pingcapv1alpha1.AddToScheme(scheme) +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) } diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index c9ff91beed..f446faa736 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -24,15 +24,14 @@ import ( 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" ) var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) - -func init() { - v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) - AddToScheme(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + pingcapv1alpha1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition @@ -45,10 +44,13 @@ func init() { // ) // // kclientset, _ := kubernetes.NewForConfig(c) -// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. -func AddToScheme(scheme *runtime.Scheme) { - pingcapv1alpha1.AddToScheme(scheme) +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) } diff --git a/pkg/client/clientset/versioned/typed/pingcap.com/v1alpha1/fake/fake_tidbcluster.go b/pkg/client/clientset/versioned/typed/pingcap.com/v1alpha1/fake/fake_tidbcluster.go index 89b7de4e21..96ada8fa3e 100644 --- a/pkg/client/clientset/versioned/typed/pingcap.com/v1alpha1/fake/fake_tidbcluster.go +++ b/pkg/client/clientset/versioned/typed/pingcap.com/v1alpha1/fake/fake_tidbcluster.go @@ -62,7 +62,7 @@ func (c *FakeTidbClusters) List(opts v1.ListOptions) (result *v1alpha1.TidbClust if label == nil { label = labels.Everything() } - list := &v1alpha1.TidbClusterList{} + list := &v1alpha1.TidbClusterList{ListMeta: obj.(*v1alpha1.TidbClusterList).ListMeta} for _, item := range obj.(*v1alpha1.TidbClusterList).Items { if label.Matches(labels.Set(item.Labels)) { list.Items = append(list.Items, item) diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 8f03c7e206..4909ec7728 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -32,12 +32,16 @@ import ( cache "k8s.io/client-go/tools/cache" ) +// 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. @@ -45,23 +49,62 @@ type sharedInformerFactory struct { startedInformers map[reflect.Type]bool } -// NewSharedInformerFactory constructs a new instance of sharedInformerFactory +// 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 NewFilteredSharedInformerFactory(client, defaultResync, v1.NamespaceAll, nil) + 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 &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: namespace, - tweakListOptions: tweakListOptions, + 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. @@ -110,7 +153,13 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal if exists { return informer } - informer = newFunc(f.client, f.defaultResync) + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) f.informers[informerType] = informer return informer diff --git a/tools/tools.go b/tools/tools.go index ad741d0c3c..045e030d64 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -19,5 +19,8 @@ package tools import ( _ "github.com/dnephin/govet" + _ "k8s.io/code-generator" + _ "k8s.io/gengo" + _ "k8s.io/klog" ) From c683ac265ac2b7f44c69792427b80933c519b32a Mon Sep 17 00:00:00 2001 From: zyguan Date: Mon, 15 Apr 2019 13:53:17 +0800 Subject: [PATCH 03/13] stability: add sst-file-corruption case (#382) * stability: add a demo sst-corruption case --- tests/actions.go | 4 +- tests/cmd/stability/main.go | 3 + tests/failover.go | 135 ++++++++++++++++++++++++++++++++++++ tests/pkg/client/client.go | 47 +++++++++++++ tests/pkg/ops/common.go | 81 ++++++++++++++++++++++ tests/pkg/ops/exec.go | 118 +++++++++++++++++++++++++++++++ tests/pkg/ops/tikv.go | 94 +++++++++++++++++++++++++ tests/pkg/util/misc.go | 29 ++++++++ 8 files changed, 510 insertions(+), 1 deletion(-) create mode 100644 tests/pkg/ops/common.go create mode 100644 tests/pkg/ops/exec.go create mode 100644 tests/pkg/ops/tikv.go create mode 100644 tests/pkg/util/misc.go diff --git a/tests/actions.go b/tests/actions.go index ddbc3774b6..35d6d52181 100644 --- a/tests/actions.go +++ b/tests/actions.go @@ -107,6 +107,8 @@ type OperatorActions interface { CreateSecret(info *TidbClusterConfig) error GetPodUIDMap(info *TidbClusterConfig) (map[string]types.UID, error) GetNodeMap(info *TidbClusterConfig, component string) (map[string][]string, error) + TruncateSSTFileThenCheckFailover(info *TidbClusterConfig, tikvFailoverPeriod time.Duration) error + TruncateSSTFileThenCheckFailoverOrDie(info *TidbClusterConfig, tikvFailoverPeriod time.Duration) CheckFailoverPending(info *TidbClusterConfig, faultPoint *time.Time) (bool, error) CheckFailoverPendingOrDie(clusters []*TidbClusterConfig, faultPoint *time.Time) CheckFailover(info *TidbClusterConfig, faultNode string) (bool, error) @@ -1331,7 +1333,7 @@ func cloneOperatorRepo() error { cmd := fmt.Sprintf("git clone https://github.com/pingcap/tidb-operator.git /tidb-operator") glog.Info(cmd) res, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() - if err != nil { + if err != nil && !strings.Contains(string(res), "already exists") { return fmt.Errorf("failed to clone tidb-operator repository: %v, %s", err, string(res)) } diff --git a/tests/cmd/stability/main.go b/tests/cmd/stability/main.go index e26177b88d..df2f5b32d1 100644 --- a/tests/cmd/stability/main.go +++ b/tests/cmd/stability/main.go @@ -214,5 +214,8 @@ func main() { oa.CheckTidbClusterStatusOrDie(cluster) } + // truncate a sst file and check failover + oa.TruncateSSTFileThenCheckFailoverOrDie(cluster1, 5*time.Minute) + glog.Infof("\nFinished.") } diff --git a/tests/failover.go b/tests/failover.go index 59aa87cce4..20d7538ce4 100644 --- a/tests/failover.go +++ b/tests/failover.go @@ -4,13 +4,17 @@ import ( "fmt" "sort" "strings" + "syscall" "time" _ "github.com/go-sql-driver/mysql" "github.com/golang/glog" + "github.com/pingcap/errors" "github.com/pingcap/tidb-operator/pkg/apis/pingcap.com/v1alpha1" "github.com/pingcap/tidb-operator/pkg/label" "github.com/pingcap/tidb-operator/tests/pkg/client" + "github.com/pingcap/tidb-operator/tests/pkg/ops" + "github.com/pingcap/tidb-operator/tests/pkg/util" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -18,6 +22,137 @@ import ( "k8s.io/apimachinery/pkg/util/wait" ) +func (oa *operatorActions) TruncateSSTFileThenCheckFailover(info *TidbClusterConfig, tikvFailoverPeriod time.Duration) error { + const failoverTimeout = 5 * time.Minute + + cli := client.Union(oa.kubeCli, oa.cli) + tikvOps := ops.TiKVOps{ClientOps: ops.ClientOps{Client: cli}} + + // checkout latest tidb cluster + tc, err := cli.PingcapV1alpha1().TidbClusters(info.Namespace).Get(info.ClusterName, metav1.GetOptions{}) + if err != nil { + glog.Errorf("failed to get the cluster: ns=%s tc=%s err=%s", info.Namespace, info.ClusterName, err.Error()) + return err + } + countUpStores := func(tc *v1alpha1.TidbCluster) int { + cnt := 0 + for _, s := range tc.Status.TiKV.Stores { + if s.State == v1alpha1.TiKVStateUp { + cnt++ + } + } + return cnt + } + + origFailures := len(tc.Status.TiKV.FailureStores) + origUps := countUpStores(tc) + + // checkout pd config + pdCfg, err := oa.pdControl.GetPDClient(tc).GetConfig() + if err != nil { + glog.Errorf("failed to get the pd config: tc=%s err=%s", info.ClusterName, err.Error()) + return err + } + maxStoreDownTime := pdCfg.Schedule.MaxStoreDownTime.Duration + glog.Infof("failover config: maxStoreDownTime=%v tikvFailoverPeriod=%v", maxStoreDownTime, tikvFailoverPeriod) + + // find an up store + var store v1alpha1.TiKVStore + for _, v := range tc.Status.TiKV.Stores { + if v.State != v1alpha1.TiKVStateUp { + continue + } + store = v + break + } + if len(store.ID) == 0 { + glog.Errorf("failed to find an up store") + return errors.New("no up store for truncating sst file") + } else { + glog.Infof("target store: id=%s pod=%s", store.ID, store.PodName) + } + + // checkout pod status + podBeforeRestart, err := cli.CoreV1().Pods(info.Namespace).Get(store.PodName, metav1.GetOptions{}) + if err != nil { + glog.Errorf("failed to get target pod: pod=%s err=%s", store.PodName, err.Error()) + return err + } + + var rc int32 + if c := util.GetContainerStatusFromPod(podBeforeRestart, func(status corev1.ContainerStatus) bool { + return status.Name == "tikv" + }); c != nil { + rc = c.RestartCount + } else { + glog.Errorf("failed to get container status from tikv pod") + return errors.New("failed to get container status from tikv pod") + } + + // restart tikv to ensure sst files + err = tikvOps.KillProcess(info.Namespace, store.PodName, "tikv", 1, syscall.SIGTERM) + if err != nil { + glog.Errorf("kill tikv: pod=%s err=%s", store.PodName, err.Error()) + return err + } + + err = tikvOps.PollPod(info.Namespace, store.PodName, + func(pod *corev1.Pod, err error) (bool, error) { + if pod == nil { + glog.Warningf("pod is nil: err=%s", err.Error()) + return false, nil + } + tikv := util.GetContainerStatusFromPod(pod, func(status corev1.ContainerStatus) bool { + return status.Name == "tikv" + }) + + if pod.Status.Phase == corev1.PodRunning && tikv != nil && tikv.RestartCount > rc { + return true, nil + } + return false, nil + }) + if err != nil { + glog.Errorf("tikv process hasn't been restarted: err=%s", err.Error()) + return err + } + + // truncate the sst file and wait for failover + err = tikvOps.TruncateSSTFile(ops.TruncateOptions{ + Namespace: info.Namespace, + Cluster: info.ClusterName, + Store: store.ID, + }) + + // make tikv crash + err = tikvOps.KillProcess(info.Namespace, store.PodName, "tikv", 1, syscall.SIGTERM) + if err != nil { + glog.Errorf("kill tikv: pod=%s err=%s", store.PodName, err.Error()) + return err + } + + tikvOps.SetPoll(DefaultPollInterval, maxStoreDownTime+tikvFailoverPeriod+failoverTimeout) + + return tikvOps.PollTiDBCluster(info.Namespace, info.ClusterName, + func(tc *v1alpha1.TidbCluster, err error) (bool, error) { + glog.Infof("check failure stores: current=%d origin=%d", len(tc.Status.TiKV.FailureStores), origFailures) + if len(tc.Status.TiKV.FailureStores) <= origFailures { + return false, nil + } + ups := countUpStores(tc) + glog.Infof("check up stores: current=%d origin=%d", ups, origUps) + if ups < origUps { + return false, nil + } + return true, nil + }) +} + +func (oa *operatorActions) TruncateSSTFileThenCheckFailoverOrDie(info *TidbClusterConfig, tikvFailoverPeriod time.Duration) { + if err := oa.TruncateSSTFileThenCheckFailover(info, tikvFailoverPeriod); err != nil { + panic(err) + } +} + func (oa *operatorActions) CheckFailoverPending(info *TidbClusterConfig, faultPoint *time.Time) (bool, error) { tc, err := oa.cli.PingcapV1alpha1().TidbClusters(info.Namespace).Get(info.ClusterName, metav1.GetOptions{}) if err != nil { diff --git a/tests/pkg/client/client.go b/tests/pkg/client/client.go index ec2caa63c7..9c9e6f4354 100644 --- a/tests/pkg/client/client.go +++ b/tests/pkg/client/client.go @@ -3,9 +3,12 @@ package client import ( "time" + "github.com/juju/errors" "github.com/pingcap/tidb-operator/pkg/client/clientset/versioned" + "github.com/pingcap/tidb-operator/pkg/client/clientset/versioned/typed/pingcap.com/v1alpha1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" ) func NewCliOrDie() (versioned.Interface, kubernetes.Interface) { @@ -27,3 +30,47 @@ func NewCliOrDie() (versioned.Interface, kubernetes.Interface) { return cli, kubeCli } + +var ( + masterUrl string + kubeconfigPath string +) + +type Client interface { + kubernetes.Interface + PingcapV1alpha1() v1alpha1.PingcapV1alpha1Interface +} + +func Union(kube kubernetes.Interface, tidb versioned.Interface) Client { + return &client{Interface: kube, pingcap: tidb} +} + +func NewOrDie() Client { + cfg, err := clientcmd.BuildConfigFromFlags(masterUrl, kubeconfigPath) + if err != nil { + panic(err) + } + return Union(kubernetes.NewForConfigOrDie(cfg), versioned.NewForConfigOrDie(cfg)) +} + +type client struct { + kubernetes.Interface + pingcap versioned.Interface +} + +func (cli *client) PingcapV1alpha1() v1alpha1.PingcapV1alpha1Interface { + return cli.pingcap.PingcapV1alpha1() +} + +func SetConfigPath(path string) { + kubeconfigPath = path +} + +func SetMasterURL(url string) { + masterUrl = url +} + +func LoadConfig() (*rest.Config, error) { + cfg, err := clientcmd.BuildConfigFromFlags(masterUrl, kubeconfigPath) + return cfg, errors.Trace(err) +} diff --git a/tests/pkg/ops/common.go b/tests/pkg/ops/common.go new file mode 100644 index 0000000000..69239a8113 --- /dev/null +++ b/tests/pkg/ops/common.go @@ -0,0 +1,81 @@ +// Copyright 2019 PingCAP, Inc. +// +// 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, +// See the License for the specific language governing permissions and +// limitations under the License. +package ops + +import ( + "time" + + "github.com/pingcap/tidb-operator/pkg/apis/pingcap.com/v1alpha1" + "github.com/pingcap/tidb-operator/tests/pkg/client" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" +) + +const ( + DefaultPollInterval = 10 * time.Second + DefaultPollTimeout = 10 * time.Minute +) + +type PollFn func(time.Duration, time.Duration, wait.ConditionFunc) error + +type ClientOps struct { + client.Client + + PollInterval *time.Duration + PollTimeout *time.Duration +} + +func (cli *ClientOps) pollArgs(cond wait.ConditionFunc) (time.Duration, time.Duration, wait.ConditionFunc) { + interval := DefaultPollInterval + if cli.PollInterval != nil { + interval = *cli.PollInterval + } + timeout := DefaultPollTimeout + if cli.PollTimeout != nil { + timeout = *cli.PollTimeout + } + return interval, timeout, cond +} + +func (cli *ClientOps) SetPoll(interval time.Duration, timeout time.Duration) { + cli.PollInterval = &interval + cli.PollTimeout = &timeout +} + +func (cli *ClientOps) Poll(cond wait.ConditionFunc) error { + return wait.Poll(cli.pollArgs(cond)) +} + +func (cli *ClientOps) PollImmediate(cond wait.ConditionFunc) error { + return wait.PollImmediate(cli.pollArgs(cond)) +} + +func (cli *ClientOps) PollPod(ns string, name string, cond func(po *corev1.Pod, err error) (bool, error)) error { + return cli.Poll(func() (done bool, err error) { + return cond(cli.CoreV1().Pods(ns).Get(name, metav1.GetOptions{})) + }) +} + +func (cli *ClientOps) PollStatefulSet(ns string, name string, cond func(ss *appsv1.StatefulSet, err error) (bool, error)) error { + return cli.Poll(func() (done bool, err error) { + return cond(cli.AppsV1().StatefulSets(ns).Get(name, metav1.GetOptions{})) + }) +} + +func (cli *ClientOps) PollTiDBCluster(ns string, name string, cond func(tc *v1alpha1.TidbCluster, err error) (bool, error)) error { + return cli.Poll(func() (done bool, err error) { + return cond(cli.PingcapV1alpha1().TidbClusters(ns).Get(name, metav1.GetOptions{})) + }) +} diff --git a/tests/pkg/ops/exec.go b/tests/pkg/ops/exec.go new file mode 100644 index 0000000000..a904d9697a --- /dev/null +++ b/tests/pkg/ops/exec.go @@ -0,0 +1,118 @@ +// Copyright 2019 PingCAP, Inc. +// +// 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, +// See the License for the specific language governing permissions and +// limitations under the License. +package ops + +import ( + "bytes" + "io" + "net/url" + "strconv" + "strings" + "syscall" + + "github.com/golang/glog" + "github.com/pingcap/errors" + "github.com/pingcap/tidb-operator/tests/pkg/client" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/remotecommand" +) + +// ExecOptions passed to ExecWithOptions +type ExecOptions struct { + Command []string + + Namespace string + PodName string + ContainerName string + + Stdin io.Reader + CaptureStdout bool + CaptureStderr bool + // If false, whitespace in std{err,out} will be removed. + PreserveWhitespace bool +} + +// ExecWithOptions executes a command in the specified container, +// returning stdout, stderr and error. `options` allowed for +// additional parameters to be passed. +func (cli *ClientOps) ExecWithOptions(options ExecOptions) (string, string, error) { + glog.Infof("ExecWithOptions %+v", options) + + config, err := client.LoadConfig() + if err != nil { + return "", "", err + } + + const tty = false + + req := cli.CoreV1().RESTClient().Post(). + Resource("pods"). + Name(options.PodName). + Namespace(options.Namespace). + SubResource("exec"). + Param("container", options.ContainerName) + req.VersionedParams(&corev1.PodExecOptions{ + Container: options.ContainerName, + Command: options.Command, + Stdin: options.Stdin != nil, + Stdout: options.CaptureStdout, + Stderr: options.CaptureStderr, + TTY: tty, + }, codec) + + var stdout, stderr bytes.Buffer + err = execute("POST", req.URL(), config, options.Stdin, &stdout, &stderr, tty) + + if options.PreserveWhitespace { + return stdout.String(), stderr.String(), err + } + return strings.TrimSpace(stdout.String()), strings.TrimSpace(stderr.String()), err +} + +func (cli *ClientOps) KillProcess(ns string, pod string, container string, pid int, sig syscall.Signal) error { + _, _, err := cli.ExecWithOptions(ExecOptions{ + Command: []string{"kill", "-" + strconv.Itoa(int(sig)), strconv.Itoa(pid)}, + Namespace: ns, + PodName: pod, + ContainerName: container, + CaptureStderr: true, + CaptureStdout: true, + }) + return err +} + +func execute(method string, url *url.URL, config *rest.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool) error { + exec, err := remotecommand.NewSPDYExecutor(config, method, url) + if err != nil { + return errors.Trace(err) + } + return errors.Trace(exec.Stream(remotecommand.StreamOptions{ + Stdin: stdin, + Stdout: stdout, + Stderr: stderr, + Tty: tty, + })) +} + +var ( + scheme *runtime.Scheme + codec runtime.ParameterCodec +) + +func init() { + scheme = runtime.NewScheme() + corev1.AddToScheme(scheme) + codec = runtime.NewParameterCodec(scheme) +} diff --git a/tests/pkg/ops/tikv.go b/tests/pkg/ops/tikv.go new file mode 100644 index 0000000000..0e06e264cd --- /dev/null +++ b/tests/pkg/ops/tikv.go @@ -0,0 +1,94 @@ +// Copyright 2019 PingCAP, Inc. +// +// 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, +// See the License for the specific language governing permissions and +// limitations under the License. +package ops + +import ( + "strings" + + "github.com/golang/glog" + "github.com/pingcap/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type TruncateOptions struct { + Namespace string + Cluster string + Store string +} + +type TiKVOps struct { + ClientOps +} + +func (ops *TiKVOps) TruncateSSTFile(opts TruncateOptions) error { + glog.Infof("truncate sst option: %+v", opts) + + tc, err := ops.PingcapV1alpha1().TidbClusters(opts.Namespace).Get(opts.Cluster, metav1.GetOptions{}) + if err != nil { + return errors.Trace(err) + } + store, ok := tc.Status.TiKV.Stores[opts.Store] + if !ok { + return errors.New("no such store") + } + + exec := func(cmd ...string) (string, string, error) { + return ops.ExecWithOptions(ExecOptions{ + Command: cmd, + Namespace: opts.Namespace, + PodName: store.PodName, + ContainerName: "tikv", + CaptureStderr: true, + CaptureStdout: true, + }) + } + + stdout, stderr, err := exec("find", "/var/lib/tikv/db", "-name", "*.sst", "-o", "-name", "*.save") + if err != nil { + glog.Errorf("list sst files: stderr=%s err=%s", stderr, err.Error()) + return errors.Annotate(err, "list sst files") + } + + sstCandidates := make(map[string]bool) + + for _, f := range strings.Split(stdout, "\n") { + f = strings.TrimSpace(f) + if len(f) > 0 { + sstCandidates[f] = true + } + } + + sst := "" + for k := range sstCandidates { + if strings.HasSuffix(k, ".sst") && !sstCandidates[k+".save"] { + sst = k + } + } + if len(sst) == 0 { + return errors.New("cannot find a sst file") + } + + _, stderr, err = exec("cp", sst, sst+".save") + if err != nil { + glog.Errorf("backup sst file: stderr=%s err=%s", stderr, err.Error()) + return errors.Annotate(err, "backup sst file") + } + + _, stderr, err = exec("truncate", "-s", "0", sst) + if err != nil { + glog.Errorf("truncate sst file: stderr=%s err=%s", stderr, err.Error()) + return errors.Annotate(err, "truncate sst file") + } + + return nil +} diff --git a/tests/pkg/util/misc.go b/tests/pkg/util/misc.go new file mode 100644 index 0000000000..0540924bb7 --- /dev/null +++ b/tests/pkg/util/misc.go @@ -0,0 +1,29 @@ +// Copyright 2019 PingCAP, Inc. +// +// 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, +// See the License for the specific language governing permissions and +// limitations under the License. +package util + +import ( + corev1 "k8s.io/api/core/v1" +) + +func GetContainerStatusFromPod(pod *corev1.Pod, cond func(corev1.ContainerStatus) bool) *corev1.ContainerStatus { + if pod == nil { + return nil + } + for _, c := range pod.Status.ContainerStatuses { + if cond(c) { + return &c + } + } + return nil +} From 59d080bbae89e399c44702774132294b20c0ffdb Mon Sep 17 00:00:00 2001 From: Tennix Date: Mon, 15 Apr 2019 13:59:12 +0800 Subject: [PATCH 04/13] use release name as default clusterName (#354) * use release name as default clusterName * update the corresponding docs --- charts/tidb-cluster/templates/NOTES.txt | 4 +- charts/tidb-cluster/templates/_helpers.tpl | 4 + .../templates/config/_alert-rules-config.tpl | 100 +++++++++--------- .../templates/config/_drainer-config.tpl | 2 +- .../templates/config/_pump-config.tpl | 2 +- .../templates/discovery-deployment.yaml | 4 +- .../templates/discovery-rbac.yaml | 12 +-- .../templates/discovery-service.yaml | 2 +- .../templates/drainer-configmap.yaml | 2 +- .../templates/drainer-service.yaml | 2 +- .../templates/drainer-statefulset.yaml | 6 +- .../templates/monitor-configmap.yaml | 2 +- .../templates/monitor-deployment.yaml | 14 +-- .../tidb-cluster/templates/monitor-job.yaml | 8 +- .../tidb-cluster/templates/monitor-pvc.yaml | 2 +- .../tidb-cluster/templates/monitor-rbac.yaml | 14 ++- .../templates/monitor-secret.yaml | 2 +- .../templates/monitor-service.yaml | 4 +- .../tidb-cluster/templates/pd-configmap.yaml | 2 +- .../templates/privileged-tidb-configmap.yaml | 2 +- .../templates/privileged-tidb-deployment.yaml | 8 +- .../templates/privileged-tidb-service.yaml | 2 +- .../templates/pump-configmap.yaml | 2 +- .../tidb-cluster/templates/pump-service.yaml | 2 +- .../templates/pump-statefulset.yaml | 6 +- .../templates/scheduled-backup-cronjob.yaml | 6 +- .../templates/scheduled-backup-pvc.yaml | 2 +- .../templates/scripts/_start_drainer.sh.tpl | 4 +- .../templates/scripts/_start_pump.sh.tpl | 2 +- .../scripts/_start_scheduled_backup.sh.tpl | 2 +- .../tidb-cluster/templates/tidb-cluster.yaml | 2 +- .../templates/tidb-configmap.yaml | 2 +- .../templates/tidb-initializer-job.yaml | 10 +- .../tidb-cluster/templates/tidb-service.yaml | 2 +- .../templates/tikv-configmap.yaml | 2 +- charts/tidb-cluster/values.yaml | 5 +- docs/aws-eks-tutorial.md | 6 +- docs/google-kubernetes-tutorial.md | 10 +- docs/local-dind-tutorial.md | 10 +- docs/operation-guide.md | 15 ++- 40 files changed, 148 insertions(+), 142 deletions(-) diff --git a/charts/tidb-cluster/templates/NOTES.txt b/charts/tidb-cluster/templates/NOTES.txt index 4ae6c548cd..b31da27fb6 100644 --- a/charts/tidb-cluster/templates/NOTES.txt +++ b/charts/tidb-cluster/templates/NOTES.txt @@ -12,7 +12,7 @@ Cluster Startup Cluster access * Access tidb-cluster using the MySQL client - kubectl port-forward -n {{ .Release.Namespace }} svc/{{ .Values.clusterName }}-tidb 4000:4000 & + kubectl port-forward -n {{ .Release.Namespace }} svc/{{ template "cluster.name" . }}-tidb 4000:4000 & {{- if .Values.tidb.passwordSecretName }} mysql -h 127.0.0.1 -P 4000 -u root -D test -p {{- else -}} @@ -22,6 +22,6 @@ Cluster access {{- end -}} {{- if .Values.monitor.create }} * View monitor dashboard for TiDB cluster - kubectl port-forward -n {{ .Release.Namespace }} svc/{{ .Values.clusterName }}-grafana 3000:3000 + kubectl port-forward -n {{ .Release.Namespace }} svc/{{ template "cluster.name" . }}-grafana 3000:3000 Open browser at http://localhost:3000. The default username and password is admin/admin. {{- end -}} diff --git a/charts/tidb-cluster/templates/_helpers.tpl b/charts/tidb-cluster/templates/_helpers.tpl index 577ce13793..0791ff1541 100644 --- a/charts/tidb-cluster/templates/_helpers.tpl +++ b/charts/tidb-cluster/templates/_helpers.tpl @@ -22,3 +22,7 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this {{- $wtf := $context.Template.Name | replace $last $name -}} {{ include $wtf $context }} {{- end -}} + +{{- define "cluster.name" -}} +{{- default .Release.Name .Values.clusterName }} +{{- end -}} \ No newline at end of file diff --git a/charts/tidb-cluster/templates/config/_alert-rules-config.tpl b/charts/tidb-cluster/templates/config/_alert-rules-config.tpl index 2f657f55c1..0955dc43d3 100644 --- a/charts/tidb-cluster/templates/config/_alert-rules-config.tpl +++ b/charts/tidb-cluster/templates/config/_alert-rules-config.tpl @@ -5,7 +5,7 @@ groups: expr: sum ( pd_cluster_status{type="store_down_count"} ) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: emergency expr: sum ( pd_cluster_status{type="store_down_count"} ) > 0 annotations: @@ -17,7 +17,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(etcd_disk_wal_fsync_duration_seconds_bucket[1m])) by (instance,job,le) ) > 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: histogram_quantile(0.99, sum(rate(etcd_disk_wal_fsync_duration_seconds_bucket[1m])) by (instance,job,le) ) > 1 annotations: @@ -29,7 +29,7 @@ groups: expr: sum( pd_regions_status{type="miss_peer_region_count"} ) > 100 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: sum( pd_regions_status{type="miss_peer_region_count"} ) > 100 annotations: @@ -41,7 +41,7 @@ groups: expr: sum ( pd_cluster_status{type="store_disconnected_count"} ) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum ( pd_cluster_status{type="store_disconnected_count"} ) > 0 annotations: @@ -53,7 +53,7 @@ groups: expr: sum ( pd_cluster_status{type="store_low_space_count"} ) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum ( pd_cluster_status{type="store_low_space_count"} ) > 0 annotations: @@ -65,7 +65,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(etcd_network_peer_round_trip_time_seconds_bucket[1m])) by (To,instance,job,le) ) > 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: histogram_quantile(0.99, sum(rate(etcd_network_peer_round_trip_time_seconds_bucket[1m])) by (To,instance,job,le) ) > 1 annotations: @@ -77,7 +77,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(pd_client_request_handle_requests_duration_seconds_bucket{type="tso"}[1m])) by (instance,job,le) ) > 0.1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: histogram_quantile(0.99, sum(rate(pd_client_request_handle_requests_duration_seconds_bucket{type="tso"}[1m])) by (instance,job,le) ) > 0.1 annotations: @@ -89,7 +89,7 @@ groups: expr: sum ( pd_regions_status{type="down_peer_region_count"} ) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum ( pd_regions_status{type="down_peer_region_count"} ) > 0 annotations: @@ -101,7 +101,7 @@ groups: expr: sum ( pd_regions_status{type="incorrect_namespace_region_count"} ) > 100 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum ( pd_regions_status{type="incorrect_namespace_region_count"} ) > 0 annotations: @@ -113,7 +113,7 @@ groups: expr: sum( pd_regions_status{type="pending_peer_region_count"} ) > 100 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum( pd_regions_status{type="pending_peer_region_count"} ) > 100 annotations: @@ -125,7 +125,7 @@ groups: expr: count( changes(pd_server_tso{type="save"}[10m]) > 0 ) >= 2 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: count( changes(pd_server_tso{type="save"}[10m]) > 0 ) >= 2 annotations: @@ -137,7 +137,7 @@ groups: expr: sum(pd_cluster_status{type="storage_size"}) / sum(pd_cluster_status{type="storage_capacity"}) * 100 > 80 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum(pd_cluster_status{type="storage_size"}) / sum(pd_cluster_status{type="storage_capacity"}) * 100 > 80 annotations: @@ -148,7 +148,7 @@ groups: expr: increase(tidb_session_schema_lease_error_total{type="outdated"}[15m]) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: emergency expr: increase(tidb_session_schema_lease_error_total{type="outdated"}[15m]) > 0 annotations: @@ -160,7 +160,7 @@ groups: expr: increase( tidb_tikvclient_region_err_total[10m] ) > 6000 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: emergency expr: increase( tidb_tikvclient_region_err_total[10m] ) > 6000 annotations: @@ -172,7 +172,7 @@ groups: expr: increase( tidb_domain_load_schema_total{type="failed"}[10m] ) > 10 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: emergency expr: increase( tidb_domain_load_schema_total{type="failed"}[10m] ) > 10 annotations: @@ -184,7 +184,7 @@ groups: expr: increase(tidb_monitor_keep_alive_total[10m]) < 100 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: emergency expr: increase(tidb_monitor_keep_alive_total[10m]) < 100 annotations: @@ -196,7 +196,7 @@ groups: expr: increase(tidb_server_panic_total[10m]) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: increase(tidb_server_panic_total[10m]) > 0 annotations: @@ -208,7 +208,7 @@ groups: expr: go_memstats_heap_inuse_bytes{job="tidb"} > 1e+10 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: go_memstats_heap_inuse_bytes{job="tidb"} > 1e+10 annotations: @@ -220,7 +220,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(tidb_server_handle_query_duration_seconds_bucket[1m])) BY (le, instance)) > 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: histogram_quantile(0.99, sum(rate(tidb_server_handle_query_duration_seconds_bucket[1m])) BY (le, instance)) > 1 annotations: @@ -232,7 +232,7 @@ groups: expr: increase(tidb_server_server_event{type=~"server_start|server_hang"}[15m]) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: increase(tidb_server_server_event{type=~"server_start|server_hang"}[15m]) > 0 annotations: @@ -244,7 +244,7 @@ groups: expr: increase( tidb_tikvclient_backoff_count[10m] ) > 10 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: increase( tidb_tikvclient_backoff_count[10m] ) > 10 annotations: @@ -256,7 +256,7 @@ groups: expr: increase(tidb_monitor_time_jump_back_total[10m]) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: increase(tidb_monitor_time_jump_back_total[10m]) > 0 annotations: @@ -268,7 +268,7 @@ groups: expr: sum(tidb_ddl_waiting_jobs) > 5 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum(tidb_ddl_waiting_jobs) > 5 annotations: @@ -280,7 +280,7 @@ groups: expr: (node_memory_MemAvailable offset 5m) - node_memory_MemAvailable > 5*1024*1024*1024 for: 5m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: emergency expr: (node_memory_MemAvailable offset 5m) - node_memory_MemAvailable > 5*1024*1024*1024 annotations: @@ -292,7 +292,7 @@ groups: expr: sum(increase(tidb_tikvclient_gc_action_result{type="success"}[6h])) < 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: emergency expr: sum(increase(tidb_tikvclient_gc_action_result{type="success"}[6h])) < 1 annotations: @@ -304,7 +304,7 @@ groups: expr: sum(rate(tikv_server_report_failure_msg_total{type="unreachable"}[10m])) BY (store_id) > 10 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: sum(rate(tikv_server_report_failure_msg_total{type="unreachable"}[10m])) BY (store_id) > 10 annotations: @@ -316,7 +316,7 @@ groups: expr: sum(rate(tikv_channel_full_total[10m])) BY (type, instance) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: sum(rate(tikv_channel_full_total[10m])) BY (type, instance) > 0 annotations: @@ -328,7 +328,7 @@ groups: expr: delta( tikv_engine_write_stall[10m]) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: delta( tikv_engine_write_stall[10m]) > 0 annotations: @@ -340,7 +340,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(tikv_raftstore_log_lag_bucket[1m])) by (le, instance, job)) > 5000 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: histogram_quantile(0.99, sum(rate(tikv_raftstore_log_lag_bucket[1m])) by (le, instance, job)) > 5000 annotations: @@ -352,7 +352,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(tikv_storage_engine_async_request_duration_seconds_bucket{type="snapshot"}[1m])) by (le, instance, job,type)) > 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: histogram_quantile(0.99, sum(rate(tikv_storage_engine_async_request_duration_seconds_bucket{type="snapshot"}[1m])) by (le, instance, job,type)) > 1 annotations: @@ -364,7 +364,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(tikv_storage_engine_async_request_duration_seconds_bucket{type="write"}[1m])) by (le, instance, job,type)) > 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: histogram_quantile(0.99, sum(rate(tikv_storage_engine_async_request_duration_seconds_bucket{type="write"}[1m])) by (le, instance, job,type)) > 1 annotations: @@ -376,7 +376,7 @@ groups: expr: histogram_quantile(0.9999, sum(rate(tikv_coprocessor_request_wait_seconds_bucket[1m])) by (le, instance, job,req)) > 10 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: histogram_quantile(0.9999, sum(rate(tikv_coprocessor_request_wait_seconds_bucket[1m])) by (le, instance, job,req)) > 10 annotations: @@ -388,7 +388,7 @@ groups: expr: sum(rate(tikv_thread_cpu_seconds_total{name=~"raftstore_.*"}[1m])) by (job, name) > 0.8 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: sum(rate(tikv_thread_cpu_seconds_total{name=~"raftstore_.*"}[1m])) by (job, name) > 0.8 annotations: @@ -400,7 +400,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(tikv_raftstore_append_log_duration_seconds_bucket[1m])) by (le, instance, job)) > 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: histogram_quantile(0.99, sum(rate(tikv_raftstore_append_log_duration_seconds_bucket[1m])) by (le, instance, job)) > 1 annotations: @@ -412,7 +412,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(tikv_raftstore_apply_log_duration_seconds_bucket[1m])) by (le, instance, job)) > 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: histogram_quantile(0.99, sum(rate(tikv_raftstore_apply_log_duration_seconds_bucket[1m])) by (le, instance, job)) > 1 annotations: @@ -424,7 +424,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(tikv_scheduler_latch_wait_duration_seconds_bucket[1m])) by (le, instance, job,type)) > 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: histogram_quantile(0.99, sum(rate(tikv_scheduler_latch_wait_duration_seconds_bucket[1m])) by (le, instance, job,type)) > 1 annotations: @@ -437,7 +437,7 @@ groups: expr: sum(rate(tikv_thread_cpu_seconds_total{name="apply_worker"}[1m])) by (job) > 0.9 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: sum(rate(tikv_thread_cpu_seconds_total{name="apply_worker"}[1m])) by (job) > 0.9 annotations: @@ -449,7 +449,7 @@ groups: expr: sum(increase(tidb_tikvclient_gc_action_result{type="fail"}[1m])) > 10 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: critical expr: sum(increase(tidb_tikvclient_gc_action_result{type="fail"}[1m])) > 10 annotations: @@ -461,7 +461,7 @@ groups: expr: delta(tikv_pd_heartbeat_tick_total{type="leader"}[30s]) < -10 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: delta(tikv_pd_heartbeat_tick_total{type="leader"}[30s]) < -10 annotations: @@ -473,7 +473,7 @@ groups: expr: histogram_quantile(0.999, sum(rate(tikv_raftstore_raft_process_duration_secs_bucket{type='ready'}[1m])) by (le, instance, job,type)) > 2 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: histogram_quantile(0.999, sum(rate(tikv_raftstore_raft_process_duration_secs_bucket{type='ready'}[1m])) by (le, instance, job,type)) > 2 annotations: @@ -485,7 +485,7 @@ groups: expr: histogram_quantile(0.999, sum(rate(tikv_raftstore_raft_process_duration_secs_bucket{type='tick'}[1m])) by (le, instance, job,type)) > 2 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: histogram_quantile(0.999, sum(rate(tikv_raftstore_raft_process_duration_secs_bucket{type='tick'}[1m])) by (le, instance, job,type)) > 2 annotations: @@ -497,7 +497,7 @@ groups: expr: abs(delta( tikv_scheduler_contex_total[5m])) > 1000 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: abs(delta( tikv_scheduler_contex_total[5m])) > 1000 annotations: @@ -509,7 +509,7 @@ groups: expr: histogram_quantile(0.99, sum(rate(tikv_scheduler_command_duration_seconds_bucket[1m])) by (le, instance, job,type) / 1000) > 1 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: histogram_quantile(0.99, sum(rate(tikv_scheduler_command_duration_seconds_bucket[1m])) by (le, instance, job,type) / 1000) > 1 annotations: @@ -521,7 +521,7 @@ groups: expr: sum(rate(tikv_thread_cpu_seconds_total{name=~"storage_schedul.*"}[1m])) by (job) > 0.8 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum(rate(tikv_thread_cpu_seconds_total{name=~"storage_schedul.*"}[1m])) by (job) > 0.8 annotations: @@ -533,7 +533,7 @@ groups: expr: delta( tikv_coprocessor_outdated_request_wait_seconds_count[10m] ) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: delta( tikv_coprocessor_outdated_request_wait_seconds_count[10m] ) > 0 annotations: @@ -545,7 +545,7 @@ groups: expr: increase(tikv_coprocessor_request_error[10m]) > 100 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: increase(tikv_coprocessor_request_error[10m]) > 100 annotations: @@ -557,7 +557,7 @@ groups: expr: delta( tikv_coprocessor_pending_request[10m]) > 5000 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: delta( tikv_coprocessor_pending_request[10m]) > 5000 annotations: @@ -569,7 +569,7 @@ groups: expr: sum(rate(tikv_thread_cpu_seconds_total{name=~"cop_.*"}[1m])) by (job) / ( count(tikv_thread_cpu_seconds_total{name=~"cop_.*"}) * 0.9 ) / count(count(tikv_thread_cpu_seconds_total) by (instance)) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum(rate(tikv_thread_cpu_seconds_total{name=~"cop_.*"}[1m])) by (job) / ( count(tikv_thread_cpu_seconds_total{name=~"cop_.*"}) * 0.9 ) / count(count(tikv_thread_cpu_seconds_total) by (instance)) > 0 annotations: @@ -581,7 +581,7 @@ groups: expr: sum(tikv_worker_pending_task_total) BY (job,instance,name) > 1000 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: sum(tikv_worker_pending_task_total) BY (job,instance,name) > 1000 annotations: @@ -593,7 +593,7 @@ groups: expr: count( (sum(tikv_store_size_bytes{type="available"}) by (job) / sum(tikv_store_size_bytes{type="capacity"}) by (job) < 0.2) and (sum(tikv_raftstore_snapshot_traffic_total{type="applying"}) by (job) > 0 ) ) > 0 for: 1m labels: - env: '{{ .Values.clusterName }}' + env: '{{ template "cluster.name" . }}' level: warning expr: count( (sum(tikv_store_size_bytes{type="available"}) by (job) / sum(tikv_store_size_bytes{type="capacity"}) by (job) < 0.2) and (sum(tikv_raftstore_snapshot_traffic_total{type="applying"}) by (job) > 0 ) ) > 0 annotations: diff --git a/charts/tidb-cluster/templates/config/_drainer-config.tpl b/charts/tidb-cluster/templates/config/_drainer-config.tpl index addc1d1f3f..59f4c7009a 100644 --- a/charts/tidb-cluster/templates/config/_drainer-config.tpl +++ b/charts/tidb-cluster/templates/config/_drainer-config.tpl @@ -11,7 +11,7 @@ detect-interval = {{ .Values.binlog.drainer.detectInterval | default 10 }} data-dir = "/data" # a comma separated list of PD endpoints -pd-urls = "http://{{ .Values.clusterName }}-pd:2379" +pd-urls = "http://{{ template "cluster.name" . }}-pd:2379" #[security] # Path of file that contains list of trusted SSL CAs for connection with cluster components. diff --git a/charts/tidb-cluster/templates/config/_pump-config.tpl b/charts/tidb-cluster/templates/config/_pump-config.tpl index 3d6cfa2cbd..241f0edd73 100644 --- a/charts/tidb-cluster/templates/config/_pump-config.tpl +++ b/charts/tidb-cluster/templates/config/_pump-config.tpl @@ -17,7 +17,7 @@ data-dir = "/data" heartbeat-interval = {{ .Values.binlog.pump.heartbeatInterval | default 2 }} # a comma separated list of PD endpoints -pd-urls = "http://{{ .Values.clusterName }}-pd:2379" +pd-urls = "http://{{ template "cluster.name" . }}-pd:2379" #[security] # Path of file that contains list of trusted SSL CAs for connection with cluster components. diff --git a/charts/tidb-cluster/templates/discovery-deployment.yaml b/charts/tidb-cluster/templates/discovery-deployment.yaml index c0dc462b25..a661efacb4 100644 --- a/charts/tidb-cluster/templates/discovery-deployment.yaml +++ b/charts/tidb-cluster/templates/discovery-deployment.yaml @@ -1,7 +1,7 @@ apiVersion: apps/v1beta1 kind: Deployment metadata: - name: {{ .Values.clusterName }}-discovery + name: {{ template "cluster.name" . }}-discovery labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -27,7 +27,7 @@ spec: serviceAccount: {{ .Values.discovery.serviceAccount }} {{- else }} {{- if .Values.rbac.create }} - serviceAccount: {{ .Values.clusterName }}-discovery + serviceAccount: {{ template "cluster.name" . }}-discovery {{- end }} {{- end }} containers: diff --git a/charts/tidb-cluster/templates/discovery-rbac.yaml b/charts/tidb-cluster/templates/discovery-rbac.yaml index cecd8e84f5..7e49bbdb26 100644 --- a/charts/tidb-cluster/templates/discovery-rbac.yaml +++ b/charts/tidb-cluster/templates/discovery-rbac.yaml @@ -2,7 +2,7 @@ kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: - name: {{ .Values.clusterName}}-discovery + name: {{ template "cluster.name" . }}-discovery labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -12,13 +12,13 @@ metadata: rules: - apiGroups: ["pingcap.com"] resources: ["tidbclusters"] - resourceNames: [{{ .Values.clusterName | quote }}] + resourceNames: [{{ template "cluster.name" . }}] verbs: ["get"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: - name: {{ .Values.clusterName }}-discovery + name: {{ template "cluster.name" . }}-discovery labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -27,16 +27,16 @@ metadata: helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} subjects: - kind: ServiceAccount - name: {{ .Values.clusterName }}-discovery + name: {{ template "cluster.name" . }}-discovery roleRef: kind: Role - name: {{ .Values.clusterName }}-discovery + name: {{ template "cluster.name" . }}-discovery apiGroup: rbac.authorization.k8s.io --- kind: ServiceAccount apiVersion: v1 metadata: - name: {{ .Values.clusterName }}-discovery + name: {{ template "cluster.name" . }}-discovery labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/discovery-service.yaml b/charts/tidb-cluster/templates/discovery-service.yaml index 5b8d3f1500..7d1f8f1cd6 100644 --- a/charts/tidb-cluster/templates/discovery-service.yaml +++ b/charts/tidb-cluster/templates/discovery-service.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: Service metadata: - name: {{ .Values.clusterName }}-discovery + name: {{ template "cluster.name" . }}-discovery labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/drainer-configmap.yaml b/charts/tidb-cluster/templates/drainer-configmap.yaml index a30ab8074c..832fb12879 100644 --- a/charts/tidb-cluster/templates/drainer-configmap.yaml +++ b/charts/tidb-cluster/templates/drainer-configmap.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ .Values.clusterName }}-drainer + name: {{ template "cluster.name" . }}-drainer labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/drainer-service.yaml b/charts/tidb-cluster/templates/drainer-service.yaml index 6bec774eb2..05bb9bffcc 100644 --- a/charts/tidb-cluster/templates/drainer-service.yaml +++ b/charts/tidb-cluster/templates/drainer-service.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: - name: {{ .Values.clusterName }}-drainer + name: {{ template "cluster.name" . }}-drainer labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/drainer-statefulset.yaml b/charts/tidb-cluster/templates/drainer-statefulset.yaml index 5ae92cd7ca..89d604001e 100644 --- a/charts/tidb-cluster/templates/drainer-statefulset.yaml +++ b/charts/tidb-cluster/templates/drainer-statefulset.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1 kind: StatefulSet metadata: - name: {{ .Values.clusterName }}-drainer + name: {{ template "cluster.name" . }}-drainer labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -16,7 +16,7 @@ spec: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: tidb-operator app.kubernetes.io/component: drainer - serviceName: {{ .Values.clusterName }}-drainer + serviceName: {{ template "cluster.name" . }}-drainer replicas: 1 template: metadata: @@ -50,7 +50,7 @@ spec: volumes: - name: config configMap: - name: {{ .Values.clusterName }}-drainer + name: {{ template "cluster.name" . }}-drainer items: - key: drainer-config path: drainer.toml diff --git a/charts/tidb-cluster/templates/monitor-configmap.yaml b/charts/tidb-cluster/templates/monitor-configmap.yaml index 36e7b73040..a1d010d901 100644 --- a/charts/tidb-cluster/templates/monitor-configmap.yaml +++ b/charts/tidb-cluster/templates/monitor-configmap.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/monitor-deployment.yaml b/charts/tidb-cluster/templates/monitor-deployment.yaml index 7dc1d29868..2d7127e02a 100644 --- a/charts/tidb-cluster/templates/monitor-deployment.yaml +++ b/charts/tidb-cluster/templates/monitor-deployment.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1beta1 kind: Deployment metadata: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -27,7 +27,7 @@ spec: serviceAccount: {{ .Values.monitor.serviceAccount }} {{- else }} {{- if .Values.rbac.create }} - serviceAccount: {{ .Values.clusterName }}-monitor + serviceAccount: {{ template "cluster.name" . }}-monitor {{- end }} {{- end }} {{- if .Values.monitor.nodeSelector }} @@ -120,12 +120,12 @@ spec: - name: GF_SECURITY_ADMIN_USER valueFrom: secretKeyRef: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor key: username - name: GF_SECURITY_ADMIN_PASSWORD valueFrom: secretKeyRef: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor key: password - name: TZ value: {{ .Values.timezone | default "UTC" }} @@ -141,13 +141,13 @@ spec: - name: monitor-data {{- if .Values.monitor.persistent }} persistentVolumeClaim: - claimName: {{ .Values.clusterName }}-monitor + claimName: {{ template "cluster.name" . }}-monitor {{- else }} emptyDir: {} {{- end }} - name: prometheus-config configMap: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor items: - key: prometheus-config path: prometheus.yml @@ -156,7 +156,7 @@ spec: {{- if .Values.monitor.grafana.create }} - name: grafana-config configMap: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor items: - key: grafana-config path: grafana.ini diff --git a/charts/tidb-cluster/templates/monitor-job.yaml b/charts/tidb-cluster/templates/monitor-job.yaml index c2651c2c1f..0a0b51745d 100644 --- a/charts/tidb-cluster/templates/monitor-job.yaml +++ b/charts/tidb-cluster/templates/monitor-job.yaml @@ -2,7 +2,7 @@ apiVersion: batch/v1 kind: Job metadata: - name: {{ .Values.clusterName }}-monitor-configurator + name: {{ template "cluster.name" . }}-monitor-configurator labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -23,16 +23,16 @@ spec: image: {{ .Values.monitor.dashboardInstaller.image }} imagePullPolicy: {{ .Values.monitor.dashboardInstaller.imagePullPolicy | default "IfNotPresent" }} args: - - {{ .Values.clusterName }}-grafana:3000 + - {{ template "cluster.name" . }}-grafana:3000 env: - name: GRAFANA_USERNAME valueFrom: secretKeyRef: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor key: username - name: GRAFANA_PASSWORD valueFrom: secretKeyRef: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor key: password {{- end }} diff --git a/charts/tidb-cluster/templates/monitor-pvc.yaml b/charts/tidb-cluster/templates/monitor-pvc.yaml index 11406e1e1d..8bef475602 100644 --- a/charts/tidb-cluster/templates/monitor-pvc.yaml +++ b/charts/tidb-cluster/templates/monitor-pvc.yaml @@ -2,7 +2,7 @@ kind: PersistentVolumeClaim apiVersion: v1 metadata: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: tidb-operator diff --git a/charts/tidb-cluster/templates/monitor-rbac.yaml b/charts/tidb-cluster/templates/monitor-rbac.yaml index 5503d76805..8f725e3285 100644 --- a/charts/tidb-cluster/templates/monitor-rbac.yaml +++ b/charts/tidb-cluster/templates/monitor-rbac.yaml @@ -3,7 +3,7 @@ kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: - name: {{ .Values.clusterName}}-monitor + name: {{ template "cluster.name" . }}-monitor labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -18,7 +18,7 @@ rules: kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -27,17 +27,21 @@ metadata: helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} subjects: - kind: ServiceAccount - name: {{ .Values.monitor.serviceAccount | default (print .Values.clusterName "-monitor") }} + {{- if .Values.monitor.serviceAccount }} + name: {{ .Values.monitor.serviceAccount }} + {{- else }} + name: {{ template "cluster.name" . }}-monitor + {{- end }} roleRef: kind: Role - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor apiGroup: rbac.authorization.k8s.io --- {{- if not .Values.monitor.serviceAccount }} kind: ServiceAccount apiVersion: v1 metadata: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/monitor-secret.yaml b/charts/tidb-cluster/templates/monitor-secret.yaml index c75faaa4d8..f1df734252 100644 --- a/charts/tidb-cluster/templates/monitor-secret.yaml +++ b/charts/tidb-cluster/templates/monitor-secret.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Secret metadata: - name: {{ .Values.clusterName }}-monitor + name: {{ template "cluster.name" . }}-monitor labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/monitor-service.yaml b/charts/tidb-cluster/templates/monitor-service.yaml index 516c8c853a..8c57ee4024 100644 --- a/charts/tidb-cluster/templates/monitor-service.yaml +++ b/charts/tidb-cluster/templates/monitor-service.yaml @@ -3,7 +3,7 @@ apiVersion: v1 kind: Service metadata: - name: {{ .Values.clusterName }}-grafana + name: {{ template "cluster.name" . }}-grafana labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -26,7 +26,7 @@ spec: apiVersion: v1 kind: Service metadata: - name: {{ .Values.clusterName }}-prometheus + name: {{ template "cluster.name" . }}-prometheus labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/pd-configmap.yaml b/charts/tidb-cluster/templates/pd-configmap.yaml index c97ae7558d..683a7a7f1d 100644 --- a/charts/tidb-cluster/templates/pd-configmap.yaml +++ b/charts/tidb-cluster/templates/pd-configmap.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ .Values.clusterName }}-pd + name: {{ template "cluster.name" . }}-pd labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/privileged-tidb-configmap.yaml b/charts/tidb-cluster/templates/privileged-tidb-configmap.yaml index 1b57e99e3f..f13962d086 100644 --- a/charts/tidb-cluster/templates/privileged-tidb-configmap.yaml +++ b/charts/tidb-cluster/templates/privileged-tidb-configmap.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ .Values.clusterName }}-privileged-tidb + name: {{ template "cluster.name" . }}-privileged-tidb labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/privileged-tidb-deployment.yaml b/charts/tidb-cluster/templates/privileged-tidb-deployment.yaml index a633229bd8..78141998e3 100644 --- a/charts/tidb-cluster/templates/privileged-tidb-deployment.yaml +++ b/charts/tidb-cluster/templates/privileged-tidb-deployment.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1beta1 kind: Deployment metadata: - name: {{ .Values.clusterName }}-privileged-tidb + name: {{ template "cluster.name" . }}-privileged-tidb labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -56,7 +56,7 @@ spec: protocol: TCP env: - name: CLUSTER_NAME - value: {{ .Values.clusterName }} + value: {{ template "cluster.name" . }} - name: TZ value: {{ .Values.timezone | default "UTC" }} volumeMounts: @@ -73,7 +73,7 @@ spec: volumes: - name: config configMap: - name: {{ .Values.clusterName }}-privileged-tidb + name: {{ template "cluster.name" . }}-privileged-tidb items: - key: config-file path: tidb.toml @@ -85,7 +85,7 @@ spec: fieldPath: metadata.annotations - name: startup-script configMap: - name: {{ .Values.clusterName }}-privileged-tidb + name: {{ template "cluster.name" . }}-privileged-tidb items: - key: startup-script path: privileged_tidb_start_script.sh diff --git a/charts/tidb-cluster/templates/privileged-tidb-service.yaml b/charts/tidb-cluster/templates/privileged-tidb-service.yaml index 1f348a3ea9..54f5c758f3 100644 --- a/charts/tidb-cluster/templates/privileged-tidb-service.yaml +++ b/charts/tidb-cluster/templates/privileged-tidb-service.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: - name: {{ .Values.clusterName }}-privileged-tidb + name: {{ template "cluster.name" . }}-privileged-tidb labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/pump-configmap.yaml b/charts/tidb-cluster/templates/pump-configmap.yaml index 2488cc99ed..2956184188 100644 --- a/charts/tidb-cluster/templates/pump-configmap.yaml +++ b/charts/tidb-cluster/templates/pump-configmap.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ .Values.clusterName }}-pump + name: {{ template "cluster.name" . }}-pump labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/pump-service.yaml b/charts/tidb-cluster/templates/pump-service.yaml index 3166a67457..5190350485 100644 --- a/charts/tidb-cluster/templates/pump-service.yaml +++ b/charts/tidb-cluster/templates/pump-service.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: - name: {{ .Values.clusterName }}-pump + name: {{ template "cluster.name" . }}-pump labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/pump-statefulset.yaml b/charts/tidb-cluster/templates/pump-statefulset.yaml index c2a05dcf10..e006d4ebdf 100644 --- a/charts/tidb-cluster/templates/pump-statefulset.yaml +++ b/charts/tidb-cluster/templates/pump-statefulset.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1 kind: StatefulSet metadata: - name: {{ .Values.clusterName }}-pump + name: {{ template "cluster.name" . }}-pump labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -16,7 +16,7 @@ spec: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: tidb-operator app.kubernetes.io/component: pump - serviceName: {{ .Values.clusterName }}-pump + serviceName: {{ template "cluster.name" . }}-pump replicas: {{ .Values.binlog.pump.replicas }} template: metadata: @@ -50,7 +50,7 @@ spec: volumes: - name: config configMap: - name: {{ .Values.clusterName }}-pump + name: {{ template "cluster.name" . }}-pump items: - key: pump-config path: pump.toml diff --git a/charts/tidb-cluster/templates/scheduled-backup-cronjob.yaml b/charts/tidb-cluster/templates/scheduled-backup-cronjob.yaml index 74ccf98b7a..6dfdb7adc6 100644 --- a/charts/tidb-cluster/templates/scheduled-backup-cronjob.yaml +++ b/charts/tidb-cluster/templates/scheduled-backup-cronjob.yaml @@ -2,7 +2,7 @@ apiVersion: batch/v1beta1 kind: CronJob metadata: - name: {{ .Values.clusterName }}-scheduled-backup + name: {{ template "cluster.name" . }}-scheduled-backup labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -38,7 +38,7 @@ spec: imagePullPolicy: {{ .Values.scheduledBackup.binlogImagePullPolicy | default "IfNotPresent" }} command: - /binlogctl - - -pd-urls=http://{{ .Values.clusterName }}-pd:2379 + - -pd-urls=http://{{ template "cluster.name" . }}-pd:2379 - -cmd=generate_meta - -data-dir=/savepoint-dir volumeMounts: @@ -88,7 +88,7 @@ spec: emptyDir: {} - name: data persistentVolumeClaim: - claimName: {{ .Values.clusterName }}-scheduled-backup + claimName: {{ template "cluster.name" . }}-scheduled-backup {{- if .Values.scheduledBackup.gcp }} - name: gcp-credentials secret: diff --git a/charts/tidb-cluster/templates/scheduled-backup-pvc.yaml b/charts/tidb-cluster/templates/scheduled-backup-pvc.yaml index 7248b7f781..a7d9491fd2 100644 --- a/charts/tidb-cluster/templates/scheduled-backup-pvc.yaml +++ b/charts/tidb-cluster/templates/scheduled-backup-pvc.yaml @@ -2,7 +2,7 @@ kind: PersistentVolumeClaim apiVersion: v1 metadata: - name: {{ .Values.clusterName }}-scheduled-backup + name: {{ template "cluster.name" . }}-scheduled-backup labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: tidb-operator diff --git a/charts/tidb-cluster/templates/scripts/_start_drainer.sh.tpl b/charts/tidb-cluster/templates/scripts/_start_drainer.sh.tpl index f8c1309b75..7e56bfcaa5 100644 --- a/charts/tidb-cluster/templates/scripts/_start_drainer.sh.tpl +++ b/charts/tidb-cluster/templates/scripts/_start_drainer.sh.tpl @@ -1,6 +1,6 @@ set -euo pipefail -domain=`echo ${HOSTNAME}`.{{ .Values.clusterName }}-drainer +domain=`echo ${HOSTNAME}`.{{ template "cluster.name" . }}-drainer elapseTime=0 period=1 @@ -26,7 +26,7 @@ done /drainer \ -L={{ .Values.binlog.drainer.logLevel | default "info" }} \ --addr=`echo ${HOSTNAME}`.{{ .Values.clusterName }}-drainer:8249 \ +-addr=`echo ${HOSTNAME}`.{{ template "cluster.name" . }}-drainer:8249 \ -config=/etc/drainer/drainer.toml \ -disable-detect={{ .Values.binlog.drainer.disableDetect | default false }} \ -initial-commit-ts={{ .Values.binlog.drainer.initialCommitTs | default 0 }} \ diff --git a/charts/tidb-cluster/templates/scripts/_start_pump.sh.tpl b/charts/tidb-cluster/templates/scripts/_start_pump.sh.tpl index 481eaafd45..8896a8fb71 100644 --- a/charts/tidb-cluster/templates/scripts/_start_pump.sh.tpl +++ b/charts/tidb-cluster/templates/scripts/_start_pump.sh.tpl @@ -1,6 +1,6 @@ set -euo pipefail /pump \ -L={{ .Values.binlog.pump.logLevel | default "info" }} \ --advertise-addr=`echo ${HOSTNAME}`.{{ .Values.clusterName }}-pump:8250 \ +-advertise-addr=`echo ${HOSTNAME}`.{{ template "cluster.name" . }}-pump:8250 \ -config=/etc/pump/pump.toml \ -log-file= diff --git a/charts/tidb-cluster/templates/scripts/_start_scheduled_backup.sh.tpl b/charts/tidb-cluster/templates/scripts/_start_scheduled_backup.sh.tpl index 0c732bc975..d67fc4ba15 100644 --- a/charts/tidb-cluster/templates/scripts/_start_scheduled_backup.sh.tpl +++ b/charts/tidb-cluster/templates/scripts/_start_scheduled_backup.sh.tpl @@ -1,6 +1,6 @@ set -euo pipefail dirname=scheduled-backup-`date +%Y-%m-%dT%H%M%S`-${MY_POD_NAME} -host=`echo {{ .Values.clusterName }}_TIDB_SERVICE_HOST | tr '[a-z]' '[A-Z]' | tr '-' '_'` +host=`echo {{ template "cluster.name" . }}_TIDB_SERVICE_HOST | tr '[a-z]' '[A-Z]' | tr '-' '_'` mkdir -p /data/${dirname}/ cp /savepoint-dir/savepoint /data/${dirname}/ diff --git a/charts/tidb-cluster/templates/tidb-cluster.yaml b/charts/tidb-cluster/templates/tidb-cluster.yaml index d8eaea3d0d..a0a91c4dab 100644 --- a/charts/tidb-cluster/templates/tidb-cluster.yaml +++ b/charts/tidb-cluster/templates/tidb-cluster.yaml @@ -1,7 +1,7 @@ apiVersion: pingcap.com/v1alpha1 kind: TidbCluster metadata: - name: {{ .Values.clusterName }} + name: {{ template "cluster.name" . }} labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/tidb-configmap.yaml b/charts/tidb-cluster/templates/tidb-configmap.yaml index 5ee5a9f099..6d01bda5d4 100644 --- a/charts/tidb-cluster/templates/tidb-configmap.yaml +++ b/charts/tidb-cluster/templates/tidb-configmap.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ .Values.clusterName }}-tidb + name: {{ template "cluster.name" . }}-tidb labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/tidb-initializer-job.yaml b/charts/tidb-cluster/templates/tidb-initializer-job.yaml index 647dcd68fc..f406b6a1fd 100644 --- a/charts/tidb-cluster/templates/tidb-initializer-job.yaml +++ b/charts/tidb-cluster/templates/tidb-initializer-job.yaml @@ -2,11 +2,11 @@ apiVersion: batch/v1 kind: Job metadata: - name: {{ .Values.clusterName }}-tidb-initializer + name: {{ template "cluster.name" . }}-tidb-initializer labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Values.clusterName }} + app.kubernetes.io/instance: {{ template "cluster.name" . }} app.kubernetes.io/component: tidb-initializer helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} spec: @@ -15,7 +15,7 @@ spec: metadata: labels: app.kubernetes.io/name: {{ template "chart.name" . }} - app.kubernetes.io/instance: {{ .Values.clusterName }} + app.kubernetes.io/instance: {{ template "cluster.name" . }} app.kubernetes.io/component: tidb-initializer spec: restartPolicy: OnFailure @@ -28,7 +28,7 @@ spec: - -c - | import os, MySQLdb - host = {{ printf "%s-tidb" .Values.clusterName | quote }} + host = '{{ template "cluster.name" . }}-tidb' port = 4000 password_dir = '/etc/tidb/password' conn = MySQLdb.connect(host=host, port=port, user='root', connect_timeout=5) @@ -66,7 +66,7 @@ spec: {{- if .Values.tidb.initSql }} - name: init-sql configMap: - name: {{ .Values.clusterName }}-tidb + name: {{ template "cluster.name" . }}-tidb items: - key: init-sql path: init.sql diff --git a/charts/tidb-cluster/templates/tidb-service.yaml b/charts/tidb-cluster/templates/tidb-service.yaml index 8467b42383..fd9d4821a7 100644 --- a/charts/tidb-cluster/templates/tidb-service.yaml +++ b/charts/tidb-cluster/templates/tidb-service.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: Service metadata: - name: {{ .Values.clusterName }}-tidb + name: {{ template "cluster.name" . }}-tidb labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/templates/tikv-configmap.yaml b/charts/tidb-cluster/templates/tikv-configmap.yaml index 1af42f708f..8d80451d6d 100644 --- a/charts/tidb-cluster/templates/tikv-configmap.yaml +++ b/charts/tidb-cluster/templates/tikv-configmap.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ .Values.clusterName }}-tikv + name: {{ template "cluster.name" . }}-tikv labels: app.kubernetes.io/name: {{ template "chart.name" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} diff --git a/charts/tidb-cluster/values.yaml b/charts/tidb-cluster/values.yaml index 7e5228603a..b273332377 100644 --- a/charts/tidb-cluster/values.yaml +++ b/charts/tidb-cluster/values.yaml @@ -7,9 +7,8 @@ rbac: create: true -# clusterName is the TiDB cluster name, it is required and should be unique -# if multiple clusters are deployed in the same namespace. -clusterName: demo +# clusterName is the TiDB cluster name, if not specified, the chart release name will be used +# clusterName: demo # Add additional TidbCluster labels # ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ diff --git a/docs/aws-eks-tutorial.md b/docs/aws-eks-tutorial.md index 275e6e940d..53179b0609 100644 --- a/docs/aws-eks-tutorial.md +++ b/docs/aws-eks-tutorial.md @@ -374,10 +374,10 @@ max-open-files = 1024 ```sh # Deploy your first TiDB cluster -helm install ./charts/tidb-cluster -n tidb --namespace=tidb --set pd.storageClassName=gp2,tikv.storageClassName=gp2 +helm install ./charts/tidb-cluster -n demo --namespace=tidb --set pd.storageClassName=gp2,tikv.storageClassName=gp2 # Or if something goes wrong later and you want to update the deployment, use command: -# helm upgrade tidb ./charts/tidb-cluster --namespace=tidb --set pd.storageClassName=gp2,tikv.storageClassName=gp2 +# helm upgrade demo ./charts/tidb-cluster --namespace=tidb --set pd.storageClassName=gp2,tikv.storageClassName=gp2 # verify and wait until tidb-initializer pod status becomes completed: kubectl get pods --namespace tidb -o wide @@ -465,7 +465,7 @@ the TiDB (V2.0) should be able to finish the first TPC-H query with 15 seconds. With a single command we can easily scale out the TiDB cluster. To scale out TiKV: ```sh -helm upgrade tidb charts/tidb-cluster --set pd.storageClassName=gp2,tikv.storageClassName=gp2,tikv.replicas=5,tidb.replicas=3 +helm upgrade demo charts/tidb-cluster --set pd.storageClassName=gp2,tikv.storageClassName=gp2,tikv.replicas=5,tidb.replicas=3 ``` Now the number of TiKV pods is increased from the default 3 to 5. You can check it with: diff --git a/docs/google-kubernetes-tutorial.md b/docs/google-kubernetes-tutorial.md index 62e73e3b8b..8809d5ec1f 100644 --- a/docs/google-kubernetes-tutorial.md +++ b/docs/google-kubernetes-tutorial.md @@ -107,7 +107,7 @@ When you see `Running`, `Control + C` and proceed to launch a TiDB cluster! Now with a single command we can bring-up a full TiDB cluster: - helm install ./charts/tidb-cluster -n tidb --namespace=tidb --set pd.storageClassName=pd-ssd,tikv.storageClassName=pd-ssd + helm install ./charts/tidb-cluster -n demo --namespace=tidb --set pd.storageClassName=pd-ssd,tikv.storageClassName=pd-ssd It will take a few minutes to launch. You can monitor the progress with: @@ -151,7 +151,7 @@ If you did not specify a password in helm, set one now: With a single command we can easily scale out the TiDB cluster. To scale out TiKV: - helm upgrade tidb charts/tidb-cluster --set pd.storageClassName=pd-ssd,tikv.storageClassName=pd-ssd,tikv.replicas=5 + helm upgrade demo charts/tidb-cluster --set pd.storageClassName=pd-ssd,tikv.storageClassName=pd-ssd,tikv.replicas=5 Now the number of TiKV pods is increased from the default 3 to 5. You can check it with: @@ -161,12 +161,12 @@ Now the number of TiKV pods is increased from the default 3 to 5. You can check When the TiDB cluster is not needed, you can delete it with the following command: - helm delete tidb --purge + helm delete demo --purge The above commands only delete the running pods, the data is persistent. If you do not need the data anymore, you should run the following commands to clean the data and the dynamically created persistent disks: - kubectl delete pvc -n tidb -l app.kubernetes.io/instance=tidb,app.kubernetes.io/managed-by=tidb-operator && - kubectl get pv -l app.kubernetes.io/namespace=tidb,app.kubernetes.io/managed-by=tidb-operator,app.kubernetes.io/instance=tidb -o name | xargs -I {} kubectl patch {} -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}' + kubectl delete pvc -n tidb -l app.kubernetes.io/instance=demo,app.kubernetes.io/managed-by=tidb-operator && + kubectl get pv -l app.kubernetes.io/namespace=tidb,app.kubernetes.io/managed-by=tidb-operator,app.kubernetes.io/instance=demo -o name | xargs -I {} kubectl patch {} -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}' ## Shut down the Kubernetes cluster diff --git a/docs/local-dind-tutorial.md b/docs/local-dind-tutorial.md index f40ced5b38..85c777e242 100644 --- a/docs/local-dind-tutorial.md +++ b/docs/local-dind-tutorial.md @@ -60,8 +60,8 @@ tidb-scheduler-56757c896c-clzdg 2/2 Running 0 1m ## Step 3: Deploy a TiDB cluster in the DinD Kubernetes cluster ```sh -$ helm install charts/tidb-cluster --name=tidb-cluster --namespace=tidb -$ watch kubectl get pods --namespace tidb -l app.kubernetes.io/instance=tidb-cluster -o wide +$ helm install charts/tidb-cluster --name=demo --namespace=tidb +$ watch kubectl get pods --namespace tidb -l app.kubernetes.io/instance=demo -o wide $ # wait a few minutes to get all TiDB components created and ready $ kubectl get tidbcluster -n tidb @@ -147,7 +147,7 @@ You can scale out or scale in the TiDB cluster simply by modifying the number of 2. Run the following command to apply the changes: ```sh - helm upgrade tidb-cluster charts/tidb-cluster --namespace=tidb + helm upgrade demo charts/tidb-cluster --namespace=tidb ``` > **Note:** If you need to scale in TiKV, the consumed time depends on the volume of your existing data, because the data needs to be migrated safely. @@ -161,7 +161,7 @@ You can scale out or scale in the TiDB cluster simply by modifying the number of 2. Run the following command to apply the changes: ```sh - helm upgrade tidb-cluster charts/tidb-cluster --namespace=tidb + helm upgrade demo charts/tidb-cluster --namespace=tidb ``` ## Destroy the TiDB cluster @@ -169,7 +169,7 @@ You can scale out or scale in the TiDB cluster simply by modifying the number of When you are done with your test, use the following command to destroy the TiDB cluster: ```sh -$ helm delete tidb-cluster --purge +$ helm delete demo --purge ``` > **Note:** This only deletes the running pods and other resources, the data is persisted. If you do not need the data anymore, run the following commands to clean up the data. (Be careful, this permanently deletes the data). diff --git a/docs/operation-guide.md b/docs/operation-guide.md index 60a5c3fdb3..75b95ffa2b 100644 --- a/docs/operation-guide.md +++ b/docs/operation-guide.md @@ -1,13 +1,12 @@ # TiDB Cluster Operation Guide -TiDB Operator can manage multiple clusters in the same Kubernetes cluster. Clusters are qualified by `namespace` and `clusterName`, namely different clusters may have same `namespace` or `clusterName` but not both. +TiDB Operator can manage multiple clusters in the same Kubernetes cluster. -The default `clusterName` is `demo` which is defined in charts/tidb-cluster/values.yaml. The following variables will be used in the rest of the document: +The following variables will be used in the rest of the document: ```shell -$ releaseName="tidb-cluster" +$ releaseName="demo" $ namespace="tidb" -$ clusterName="demo" # Make sure this is the same as variable defined in charts/tidb-cluster/values.yaml ``` > **Note:** The rest of the document will use `values.yaml` to reference `charts/tidb-cluster/values.yaml` @@ -38,20 +37,20 @@ $ kubectl get svc -n ${namespace} # check the available services By default the TiDB cluster has no password set. You can specify a password by setting `tidb.password` in `values.yaml` before deploying. You can retrieve the password from the initialization `Secret`: ```shell -$ PASSWORD=$(kubectl get secret -n ${namespace} ${clusterName}-tidb -ojsonpath="{.data.password}" | base64 --decode | awk '{print $6}') +$ PASSWORD=$(kubectl get secret -n ${namespace} ${releaseName}-tidb -ojsonpath="{.data.password}" | base64 --decode | awk '{print $6}') $ echo ${PASSWORD} ``` * Access inside of the Kubernetes cluster - When your application is deployed in the same Kubernetes cluster, you can access TiDB via domain name `demo-tidb.tidb.svc` with port `4000`. Here `demo` is the `clusterName` which can be modified in `values.yaml`. And the latter `tidb` is the namespace you specified when using `helm install` to deploy TiDB cluster. + When your application is deployed in the same Kubernetes cluster, you can access TiDB via domain name `demo-tidb.tidb.svc` with port `4000`. Here `demo` is the `releaseName`. And the latter `tidb` is the namespace you specified when using `helm install` to deploy TiDB cluster. * Access outside of the Kubernetes cluster * Using kubectl portforward ```shell - $ kubectl port-forward -n ${namespace} svc/${clusterName}-tidb 4000:4000 &>/tmp/portforward-tidb.log + $ kubectl port-forward -n ${namespace} svc/${releaseName}-tidb 4000:4000 &>/tmp/portforward-tidb.log $ mysql -h 127.0.0.1 -P 4000 -u root -p ``` @@ -125,7 +124,7 @@ By default the monitor data is not persistent, when the monitor pod is killed fo You can view the dashboard using `kubectl portforward`: ```shell -$ kubectl port-forward -n ${namespace} svc/${clusterName}-grafana 3000:3000 &>/tmp/portforward-grafana.log +$ kubectl port-forward -n ${namespace} svc/${releaseName}-grafana 3000:3000 &>/tmp/portforward-grafana.log ``` Then open your browser at http://localhost:3000 The default username and password are both `admin` From 37d9c5f95fd109e503f2a7f4f93613cbd8b106f9 Mon Sep 17 00:00:00 2001 From: qiffang <947321353@qq.com> Date: Mon, 15 Apr 2019 14:05:12 +0800 Subject: [PATCH 05/13] Add util class to support to add annotations to Grafana (#378) * Add util class for adding annotation to grafana --- tests/pkg/metrics/annotation_util.go | 147 ++++++++++++++++++++++ tests/pkg/metrics/annotation_util_test.go | 46 +++++++ 2 files changed, 193 insertions(+) create mode 100644 tests/pkg/metrics/annotation_util.go create mode 100644 tests/pkg/metrics/annotation_util_test.go diff --git a/tests/pkg/metrics/annotation_util.go b/tests/pkg/metrics/annotation_util.go new file mode 100644 index 0000000000..661ffcc121 --- /dev/null +++ b/tests/pkg/metrics/annotation_util.go @@ -0,0 +1,147 @@ +// Copyright 2018 PingCAP, Inc. +// +// 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, +// See the License for the specific language governing permissions and +// limitations under the License. + +package metrics + +import ( + "bytes" + "encoding/json" + "fmt" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "net" + "net/http" + "net/url" + "os" + "path" + "sync" +) + +//Client request grafana API on a set of resource paths. +type client struct { + // base is the root URL for all invocations of the client + baseUrl url.URL + client *http.Client +} + +//Annotation is a specification of the desired behavior of adding annotation +type Annotation struct { + AnnotationOptions + Text string `json:"text"` + Tags []string `json:"tags"` + TimestampInMilliSec int64 `json:"time"` +} + +//AnnotationOptions is the query options to a standard REST list call. +type AnnotationOptions struct { + DashboardId int `json:"dashboardId, omitempty"` + PanelId int `json:"panelId, omitempty"` + IsRegin bool `json:"isRegion, omitempty"` + TimeEnd int64 `json:"timeEnd, omitempty"` +} + +//NewClient creats a new grafanaClient. This client performs rest functions +//such as Get, Post on specified paths. +func NewClient(grafanaUrl string, userName string, password string, prometheusExporterPort int) (*client, error) { + u, err := url.Parse(grafanaUrl) + if err != nil { + return nil, err + } + + initFunc(prometheusExporterPort) + u.User = url.UserPassword(userName, password) + return &client{ + baseUrl: *u, + client: &http.Client{}, + }, nil +} + +func (annotation Annotation) getBody() ([]byte, error) { + body, err := json.Marshal(annotation) + if err != nil { + return nil, err + } + + return body, nil +} + +var ( + initedOnce sync.Once + counterMetric prometheus.Counter + annotationSubPath = "api/annotations" +) + +//initFunc is called with sync.Once, we use sync.Once to keep the thread safe. +func initFunc(port int) { + initedOnce.Do(func() { + counterMetric = initErrorMetric() + prometheus.MustRegister(counterMetric) + mux := http.NewServeMux() + + l, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + if err != nil { + fmt.Fprintf(os.Stderr, "listening port %d failed, %v", port, err) + panic(err) + } + + mux.Handle("/metrics", promhttp.Handler()) + srv := &http.Server{Handler: mux} + go srv.Serve(l) + }) +} + +func initErrorMetric() prometheus.Counter { + return prometheus.NewCounter(prometheus.CounterOpts{ + Name: "error_count", + Help: "record error count", + ConstLabels: map[string]string{"fortest": "true"}, + }) +} + +//IncreErrorCountWithAnno increments the errorcount by 1, +//and add the annotation to grafanan. +func (cli *client) AddAnnotation(annotation Annotation) error { + body, err := annotation.getBody() + if err != nil { + return fmt.Errorf("create request body faield, %v", err) + } + + req, err := http.NewRequest("POST", cli.getAnnotationPath(), bytes.NewBuffer(body)) + if err != nil { + return fmt.Errorf("create request failed, %v", err) + } + + req.Header.Add("Accept", "application/json, text/plain, */*") + req.Header.Add("Content-Type", "application/json;charset=UTF-8") + resp, error := cli.client.Do(req) + if error != nil { + return fmt.Errorf("add annotation faield, %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("add annotation faield, statusCode=%v", resp.Status) + } + + return nil +} + +func (cli *client) IncrErrorCount() { + counterMetric.Inc() +} + +func (cli *client) getAnnotationPath() string { + u := cli.baseUrl + u.Path = path.Join(cli.baseUrl.Path, annotationSubPath) + return u.String() +} diff --git a/tests/pkg/metrics/annotation_util_test.go b/tests/pkg/metrics/annotation_util_test.go new file mode 100644 index 0000000000..fa5bbce402 --- /dev/null +++ b/tests/pkg/metrics/annotation_util_test.go @@ -0,0 +1,46 @@ +// Copyright 2018 PingCAP, Inc. +// +// 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, +// See the License for the specific language governing permissions and +// limitations under the License. +package metrics + +import ( + "encoding/json" + "fmt" + "github.com/onsi/gomega" + "testing" +) + +func TestAnnotationGetBody(t *testing.T) { + tags := []string{"1", "2", "3"} + + options := AnnotationOptions{ + DashboardId: 1, + PanelId: 2, + } + + annotation := Annotation{ + Tags: tags, + TimestampInMilliSec: 1, + Text: "abc", + } + + annotation.AnnotationOptions = options + + b, _ := annotation.getBody() + re := make(map[string]interface{}) + json.Unmarshal(b, &re) + + g := gomega.NewGomegaWithT(t) + g.Expect(fmt.Sprintf("%v", re["dashboardId"])).To(gomega.Equal(fmt.Sprintf("%v", 1))) + g.Expect(re["text"]).To(gomega.Equal("abc")) + g.Expect(re["time"]).To(gomega.Equal(float64(1))) +} From b5deab3e0e0e786ace322ece12745273cac0fbd4 Mon Sep 17 00:00:00 2001 From: qiffang <947321353@qq.com> Date: Mon, 15 Apr 2019 16:37:14 +0800 Subject: [PATCH 06/13] Use grafana provisioning to replace dashboard installer (#388) --- .../templates/config/_grafana-dashboard.tpl | 14 +++++++ .../templates/config/_grafana-datasource.tpl | 14 +++++++ .../templates/monitor-configmap.yaml | 5 ++- .../monitor-dashboard-configmap.yaml | 35 ++++++++++++++++ .../templates/monitor-deployment.yaml | 40 +++++++++++++++++++ .../tidb-cluster/templates/monitor-job.yaml | 38 ------------------ charts/tidb-cluster/values.yaml | 5 +-- 7 files changed, 108 insertions(+), 43 deletions(-) create mode 100644 charts/tidb-cluster/templates/config/_grafana-dashboard.tpl create mode 100644 charts/tidb-cluster/templates/config/_grafana-datasource.tpl create mode 100644 charts/tidb-cluster/templates/monitor-dashboard-configmap.yaml delete mode 100644 charts/tidb-cluster/templates/monitor-job.yaml diff --git a/charts/tidb-cluster/templates/config/_grafana-dashboard.tpl b/charts/tidb-cluster/templates/config/_grafana-dashboard.tpl new file mode 100644 index 0000000000..fae79bc94c --- /dev/null +++ b/charts/tidb-cluster/templates/config/_grafana-dashboard.tpl @@ -0,0 +1,14 @@ +{ + "apiVersion": 1, + "providers": [ + { + "folder": "", + "name": "0", + "options": { + "path": "/grafana-dashboard-definitions/tidb" + }, + "orgId": 1, + "type": "file" + } + ] +} diff --git a/charts/tidb-cluster/templates/config/_grafana-datasource.tpl b/charts/tidb-cluster/templates/config/_grafana-datasource.tpl new file mode 100644 index 0000000000..5713bfb6c7 --- /dev/null +++ b/charts/tidb-cluster/templates/config/_grafana-datasource.tpl @@ -0,0 +1,14 @@ +{ + "apiVersion": 1, + "datasources": [ + { + "access": "proxy", + "editable": false, + "name": "tidb-cluster", + "orgId": 1, + "type": "prometheus", + "url": "http://127.0.0.1:9090", + "version": 1 + } + ] +} diff --git a/charts/tidb-cluster/templates/monitor-configmap.yaml b/charts/tidb-cluster/templates/monitor-configmap.yaml index a1d010d901..650b4176bc 100644 --- a/charts/tidb-cluster/templates/monitor-configmap.yaml +++ b/charts/tidb-cluster/templates/monitor-configmap.yaml @@ -12,10 +12,13 @@ metadata: data: prometheus-config: |- {{ tuple "config/_prometheus-config.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} - alert-rules-config: |- {{ tuple "config/_alert-rules-config.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} {{- if .Values.monitor.grafana.create }} + datasource-config: |- +{{ tuple "config/_grafana-datasource.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + dashboard-config: |- +{{ tuple "config/_grafana-dashboard.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} grafana-config: |- {{ tuple "config/_grafana-config.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} {{- end }} diff --git a/charts/tidb-cluster/templates/monitor-dashboard-configmap.yaml b/charts/tidb-cluster/templates/monitor-dashboard-configmap.yaml new file mode 100644 index 0000000000..94c804d3eb --- /dev/null +++ b/charts/tidb-cluster/templates/monitor-dashboard-configmap.yaml @@ -0,0 +1,35 @@ +# In the higher version of grafana, it improve the experience by adding a new active provisioning system that uses config files. +# When Grafana starts, it will update/insert all dashboards available in the dashboard provision configured path. + +# Declare configMap to be passed into the dashboard provision configured path. + +# To avoid dashboard files that are too large to exceed the limit of configMap, compress the files by gzip and +# decompress the gzip files with postStart command. + +# If you want to update dashboard contents(get the origin files from tidb-ansible repository or tidb-docker-composse repository), please follow these steps: +# 1. Make sure there is not the ${DS_TEST-CLUSTER} variables in the dashboard files. +# Replace this variables with datasource name in _grafana_datasource.tpl, default value is tidb-cluster +# Please deleted invalid graphs, like "System Info" and "Services Port Status" +# 2. $ gzip overview.json -c > overview.json.gz +# 3. $ kubectl create configmap overview --from-file=overview.json.gz --dry-run -o yaml > overview.yaml +{{- if .Values.monitor.grafana.create }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "cluster.name" . }}-monitor-dashboard + labels: + app.kubernetes.io/name: {{ template "chart.name" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: monitor + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} +binaryData: + pd.json.gz: |- + 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 + tidb.json.gz: |- + H4sICCJnsVwAA3RpZGIuanNvbgDtnd1y27iSgO/zFFhdbCWnHB/JthJrq6ZqEzvJySbZOJEnU3UmKRZNwhKPKVJDUrYVV/at9gX2yRbg/w9IQxJNAHT7YkZhUxTQBNEfG+juuycIDTTNw3+tLA/7g/9Af5IjCN2F/yWyYL3E5OhgqTvYHuwlhy2THpx5+nKeHXT0RXjuu+Lha+z5lutQySA89muP/RumHui+u/IMXP6hpecucDDHK7/6a2cMWe4nR/vD/WH8u+S/P+g5A91x3EAPyCm0y1FDBrblB6kCsuYRycXKsoP39HKjvexorrnkdwLLvHhu2Cs/wN4gdxZ29AubnhF4K5w7PrdMxlHLcJ0T13Y9eklvdqE/He6hg9GI/Gc83kOjZ/lLJxp4lfUG/Tt6ZWMv8PPnZfr15xeu7pmDWPYr/P+PJ/EtGWDTCkqtHcwcHLynN8FZ2XZ0hN7ec9e1A2tJjg/Dg7Q7J64TeK5NVXqp2370favwXdtyrsJRFt0HD1+SUTenjTscRm0eeO4NYxwarm3rSx/nrx3pEVuzOb1vg4OjYTYCwvHq525n/obSEWBbuh9qOhwBv/bywgvd88s/FN9yf/4RO7OANnk0rMhw3dc4Rgo579Ky7eIgSxR4XPwtG8+wY6ZDN+vV9YzVAKq/ledhJ6iRLvTbOonl1Ej8uXtTGcChJCCj0a751rVurzIt5WTFO0DGSXhW+eqh4MYyoxtQluSGVnqYDr0z13KCT274wIUHimpfYnJnnECfVUZXJKbf9nTTWtHLj6sy9k0n6jaxh8Mn+dJ2g+Jv+tizsP+ZTFQeeXIY7faXuoHrxhoR0tvyongw0I0rZlPISFsusfmR6I4pD3RvhoPi00L/iqOLThC3y7A/czJVumQeWGh/rXQnsGz8dLg/mUz2kL9aPPX0AD+lo1wjvSQ91Oa6Y9qYnIu9tWauvHCuIkIy2Zm+drEyrnDw52jx49kzdLFGT2387Nlgr/zbl6630IPoAVpgLVJg9TRyP8iP6vZb3QjCafSgckr09LxNr0caXr0OmZrCaW/walAQ/drbSUWqaqhBQa/bVNBYUQWNGxR00qKCiCFQUkHHwwYFnZYUlPtXcVIM5hQXXNtkTJi0xW8JC+ZwoyCbzq3LgC0MQuQZnMZaK87UQUo6JWPrz3UPm2wT6LtekLBR7nBo/bSExyzHtK4tc0WMZa0hTM4tonYoutVvLb/arOhW+4yeUnMeG0GqkNINSXCS8a16U5+a8z9/1HZhrd9iDtuSjT3GiLP1C2wzG0eF7uy1HqJhdRxGZMP8WoQ2TFGuwxs9urk+zOkI2LYfo4fuR/4JSz/neic/KzPeVTKZ54XTUvXqTMKeeSFjlzoWHjsqjKh67ratmfPKP48bxAJfHjRnPGD0verNYhms68X/xJ7byPWM79VjvUdfp6bRy+lm2O+TL/0Ro/nBuDz1xTNi2CSG6BT7Rs0vcr1OlIb4Q71NEL1NI/YeFUcG8zUD6T76Se8OvG7s9LrBBJ6IdMLBkeMawgcrO9gFbUi/6t6Tt0OfsKHo7i5q2q9fje8a1SmcKJPqfrgVQ96nubhRv30ffP7wffCLKhIh9/LSxwEamTsgItO9ta2OD+/V8RpTC2Hq68b3lDrlTkrKFcSfX86mnOi58L9i37VXQeTkZE3Gu8KpsVqsbILD1xjgVCjYDRhvTsCn0vOpiQ1rodusod4Rux6UiIaPXRnPUYSuDEFL5Mri093AlTkh1nJrNB2yppYMTBlSmbgU8DMveVD8xLfYWBEu0UgLArwgqqxAKLWLnXrX7u7oT26Jlody0M80USf6vC0Hsd9XAYQkBKEtPHUAQozeyQ9CO8FOsTVNsNMq6zygm0407LTgpNt2yR98dJtCUvMkFj7u4cMXar86TcUqLW+1aLLxUoPYvT7Abpkr8mMZhLtQAmC7uvkkYbEvZ1P0eo3exx3s0it1wJo9YMmU/slEMQBjjN4BjEUwNgEay4uBxoDGHo7GSmrt2C9mOYaHyfRbwLLIRYa1cEZhesf2UAJPnTJbymnP8/SmMqm91S0bm+hLuMb8+ewToFq/UQ38Znz9UB/V6oNBRiNOvoJokMcUDSIOBNhb+et2qvu2exN7bpaea2Dfl3C/um7bYeu6CgzhUJbhLiVVFG3ZPcpqNUiEQ1k3uhVIrC3avA0iRgTB5ZToE4X6hJAIwdAIIRFiiDH+lD5Z5BldYr382MRH35P5QI9fqRjir+5NIZI6bc95/MDlR1POGR++201Xi4WeexAj+dT6GZ4zf8EOrc+FTRcunkZN57xOasZMd7SXrrAF+YE9mm0x+dZuSfmRXWo/oUIrqg8cY5pz8+0cStBaPAan668+XKAciyGIzpJwVXQ8FLVYCzvnpIe5wXB/OBz13gN4z6pKBnTZBYBtYneiYLRpYbUWuAi4qAOPZmvJSVrhoq3QJ/1h1BP4mYwfFn6Yix2t0Y+nO2So102O6tARy5YXjgE+VboB+NQLfDooGkxwDQECJVrsIQK1lsBOHALtuPFLOgCagPcn6RV4fzLRY8KXPu7/6oZejkV7f4BegF66oxfAF/nwBfgl7RXwSyYCfon/gF+aQg2POuQXwdGCMoX1AbzkJS3Dy0ZBdSLyTKH/RH0BkXIAHTrFATkEHCI7hziuU24coAhfVx4bihALYHjWMn5IB+dzjMLJz9FtNP3yEVk+WvlkEiCvdufW6WtkBT62L/dF8MyLYz6e6T60b+vU7OBPidSoNJKUvSY+ra+nEcMceJYRYFPz/7JjKDkc+j+6dYpsxR8jOfjjfX4ikivzJQRj5S8FyZZkwI74k/h4rNJrQkvhWIOD8XCZZfuBkKyGlSs+UHpYx49M61bg+UFszGqeEO/L28RKflZQaTfpNSs3roh4FfHGhJf3NRmu42Ajqo/cIcft7FM62r5KTk33O+XYmhHIsSu73HFBMHuSKg6duCsnAJgFmM2JAGaRsj60bjKHdhlmv1Pi0HrnWveZQxmTCABjXsk99svNXG2BF7QUja/Nsb7ULGflY+1iHWD/7l/uxW//8z18qPf/9n3AYCopQ/AXmDoV7+udypz0D9IX9AkvXG+NfvfpcN8KlGC5sTtOqhlzCWAwfNDqUVLbnXh0EWf1OTtfdLnPGvYppYf7nPBTGHQgYpdnrucSO+S0iRkP6TKSwu6/S5S2kXsEfB998X1AZkU17Xp5AxHdJDQNfcUIXxPb4e/zcsDRpEMOgHgrQAEhW5Wvc1VxhwLrsj3nKowrBRq8CeeRDUp4ABUAFajcD/WpoN7Kj7uMSgIrD1ZehJUnbbKMNgKR2l5dCBvGX+Fro+m1USPkHSGwDN1uL0arbdUkLeTVTrlshyA4+t0x3MXCddAbqliAJICkSqcBklSDpOMuq8QCJAEkdRAiVcQCYrEsYpm1K4yXGhnH17hSDFVIGVS1Fk0+EO2hV1R7YPjB8Fc6DYZfTsNfWjNJEz49XfnPELkPiMyugeXMUOBeYWcPWQEi2ljZJrrAyF/oto1WNHEXMlwnsuPGGtnWgpxn+YjMssYcmzzrLnS76ZnLeBhpvyelZ4bejVG5sPEtY7agW0QPjmqfq7hQK+euDyjUCoQiXUpfcm0tfDY7r6NZnV3LBDOZyM8t73CAzqn+UDL3ScUufSk90CLb/N//bp/cDsiGsx+1T+OaPazC9/8asxTKPuLrtGP5sfCk/Elk0Hi0W6TtcHGo3pkdbEqq0+WmG9h8mx6GyJ+8pJOMPKFZ18MQ3IqviZp0wno0UQ/5JCRx4PO7u+T3twzxliRtz3mmZ8jaowTcQaBz13SXAVj2ffmRpH7B6iUsWMUycAfF2lOaILjdQVW04CuRkKJGp6wxmfBTxkaT8MbFQRXT25hXb+VdQbvojVVsXi29HQ959XYih2NSSnfkYyTSrTFui/TV4GzsHY7CJvNYBjgaa68NHC2OKjVwlGaIwQsadOasFgkbRHmoRUOVEBjlgyp5tcaPVJJsUM+7A6eJWtF/rxbAWIIZS24+Ac6ShbO6WYk8LDp7YEMYrCUiCdCrrrpH4K0LsWw5OIDFxFS2Mz1MI4Wjr1ThaYwbLCoCXuRFsKiIgC6a9zm95KML8AglGgI8SU6QGU8YPo7Rfq2LI8KWOpdGt46M0ZAxX28BJvfM5Fu60GTSVOOO/jYXHCdKDJxJ07iRZB0x7/SK0JXf4QXQWugpQCuzb3J1ow1ojT+JDEXIPbZtxyMcDlO1qhmPYGLDWug26+nuiOFfcnoIORmeIWipAorgOIfYArBmUyI5xb7BlkJ8RF77Pd7dWGQ8fIuNFc3FQcTY8VmpOIT5Mbd6QziUw3X5JlEnehNr2JfMdQkFTfKXag2fqvUwAQP76bsUz0STdounABMBEwETZXlcbd3RDJpOB5CoDSSi9eGJPtDvPs1udEa0i06odoGLHgEXbbEzH7CofFSkdyx5jWnbNTY4GA+Xt9lVlXSPdYN7I4izjWVtLmMflCVXHNNiYgDo2Llwdc/kXXkCjMtLuomUqKzzmuQ8ukNurjumjcnJ2FtzhlKKiJSY8JTrOW1zKVgijbWd6b9Rm1mF5Y17vRWZH7V4zyrL92qN8iHPIG9zv8NYQoXRE1tR55hLnZLslziN9L5pOkh4GSz0tL8h2oPh/nA4HMPbYKV38GYUvxlxhnwLeu9pCC9iiQS/+cALiyC/Mx9/GLRCdoQfXQIaNyxHzY7GcAtMLJhJvoBvWgUc6dqMV1f5gUWARaJgo2K7gUWARdITZA4mYrOIb+iOdoXXvrbUvcDS7TAOBBgkVnInDHIWaR5YBFikJAIWUZVFGmqkcwYrQyoUyD4nKMa4buEkg4VcsOhDFcPaPch4o7lxy8U3yVTSGD7bzeqaZBoZKxBQPCUqQx+IyiBznup8BxmKOfvRa8Q7BsRLBYB4aiJe3h8k3IrLhXpSqaYz5KsmV5ZcM2qhX+IFBAQEBCx3GhBQOQTkLL0KCAgIKBkCSmXDZQA/qRQigYdPKn2oAHmAdoB2dZ0GtJMT7brZTHbUboaXbUGy0zQt4W8yRHGelm35dPc8LbBHTUJMZQb4BtbVtWFbtISX4S45Y/gsh/TEMTrmk7u75He3zO4ix161E3fpuQb2yYOKppGW0aSUuxr2q+Vk8hBPl5QAOV3KR0XmdIk3mLad0uVgnD6JkM6lIVBgG7RjTY2C2G4zH6LkOfiA7UTHQtaxXRPcXZDWuZeXTVzXebKWpnodDRT3oIVN5FaZsPVpmdVyrIDf8sO3uL4JZO5AgPtFETg36Z+izs1causiGO1ExsVmNqXz6NLrqXJia0hQnddij+G4lls8PKOOTdIrmZNUl8J04wTbSX25qAYJpuvGPs6ctWGQcZcwza3ksJ+/fR/E/bAoLvrr74NfO4ZEz+umgO3uh19aTi6qr4zWghjy3DoJlUxIkipZyirPwJL5S0HBPMDJRLTzNsjDDkmPJVUO9ZqebXCDov6SXuKhkhjzavddCmKLD9/Q60hrGwAFbK3rCy2A90lNXOhm+fVQdDUN5dADlmAfK3vYrnGlefQ9m/o7ohrZvswkUnI48XWlFV+TINT5SLqFvkbdAu8J8FBJBN4TBDjUiEPHnCn0AYcAh/JafLQ4ZNhYd1ZLjTzEV+JRKGlNtH9J99bapW7ZKw9rMkLSPcaF4wbopubrlzgcmcVFOdrv3ZfitrgFpUbF+pd/Be5zMMdetO7mAzoCOpZEgI5ItriND9/ixxUiN8RE5XLm74OoXNiclqi/x5y8TeSGh/8iAyAo7bcPGe7fCMS9O0kRLo3PJT/idbwJP/zJ53d34f+3jc+Vw0EY7tUPdZ7u1qcBulS7Ye8koj5YQM1fCrbuC0e+7PtAQPHiKWeRKyAgIKBE/Y+QgFoFoO6LsnPt9FKXe0KGAOwB7IlEgD30D7CnAXsOutwzBsuc6WGAl7xEPLwEt45mLEzOxGoALluCy8nCLEALpFMDWklEQCv0D2ilKY1Cl8tUkEYB/DRIUdQB0gn/5CEd4BzgnFgEnEP/pNt/VMn41tIOpMHBeLjMlllgF1I93hUtOtCdqst34AETXVZgc/oLc1PJGfqoHPdtveWcOQsA7vVjxzkgX4Z82feBfeId2GLZp4fOKaAQqSmkHGCYFivqFjp2rVUkDXic3zoAHgAeRRGEuiHgjmbuAPAIZQAePQIPznLXJSKJkmL7dVWe1a2nKAejUECJUmL7tC40KtX1BlbJZMAqNX0GVnnMrHIoOqOTiEUe2laGCBZ5SjKgHEI5o3sQ58azAgIn1k+sXawD3LO60fJwzh9Uz4juHUCvqZ7J0NmSdrbcAnTAevABd+hfAyeEz8TWnFAd4rAmlIxgAB60DfC0W0yEIQDeAd7Jn9BL3rm6ls2nQ3AAcfLOa3V458O30LEDrKMC60jFCH1hHfDtJJKNs3UD6iQiQJ2S7PGhzlZ5ot0rIVmiVWaXj0SdaJqos/Nc0UAuQC7S9oNNLvEnwcFaJ4VK2hCplZ3XUdogObIlMiWC9g2V3ZzAXSpz19LUYuKi0VJz3TFtTD/6NZFTaZrDwHeLeQ7VCqQaycFlZ6foJFQ/Ovl0CiU8AMtKIsAy+qeoQ4mYBcOzlvEzOhDBL4ddhpo/Gn6BdECi+YUj8+EGZFPK4FxBGzEJgkh3nrfKOPdYBv5USz1QLY9my1XedtLfsFf6G/Lo70SOKnlFxq6kv4lOBtBOZfKAtrxwCpAtC2R3FD3Y7qotcDT4AROhxH5AWggXm03uQPD/tckmb4m+wQmoBptAwCDgyeY+wPM5RslMitxLpKNo1kWGbhP7N0PvcHA+feWvHQOt6Lsj8rCBydNnooB89XxK/u2v7GBfBAS9nPBBUIeII55hwBcoN8Pct5ZZcqp0CTCkaRt4T+6Z0xu0kRSsizUS/1NWrcTNa6Q6WdjtfPoZeE0JXnNcp9w4iTgHeA14LZW1x2svgddSAfBaTtjPtVv2+ljni7Z9WKuVQ5XqrM1KoS+Gh0jCtVjKzH/oVgArsVG3VKBnWIkFdG4NnX0ya1F0phNB/LLPYmcyDS1dx8di0JmzACOgM6CzrOjM7faTjWPkRWh1VSoWpZXVmzpI/fXsBIg66hYQdSYCoqZ/csV1p5t+2g7sPhinDyMEdTcEdXP6xWEzZ6IheDtITlDw7aCcOtB0F7rlxBl2jDle6Jw10mVMl7zAgWfRLFJN6Xmk3wYapecJ74WMEGc5pnVtmSsyjwDEiYI42ADK6F3PkabYmiak4fRXAtIkGnrESNM8N4RPEb3W3/f/FgWA/L06P8RPU/MDqw453QtIdUU89wREvWQ41BCEm3HRvcxnFHKMpVdQk57k2o0J4JS/VGvUMawOd6CnXtKTiQ1roYd+rGKwaEdYxRnx8mBYNSc2+81iGazZl6Xif1LMaCg5CkymApMpBkuWY3iYzGIRMPnY90PvUUQWNpVo4VOoQvXzEiqR3yU3RlMZiGIW+kjvA3pD7wPhok/ARX3nIsAirn6wsSj+JHJhMHluyftM20uDkPOZe3lQNPP1Etsg1YtobGOvDo4rq4OmnWzT+pd7wbky2H0Guj4kfzk9/Ziu9qHJWCI+g11b+UvBgp9oNsu+Lz+kMHEjBIsXXSaRq/EW7ehM6qZuWEflv7Z3JQGLtM4ilQqnFEQu9MCYa7ppapZ5qzaLSEEcr6k+0SvTRO/J4LrN6IO/lCn4fnqSoQTwgtE7pfGi9I4Ni1XCvR5AGKIII0WIG90KLGdGnRkMay98n45shEB9En9EKkP/RVRWqkAYnQxsAGzA7hqwAZKSDcZQByqWgXmPtdeGeX8hyrwX95+Edt71rrCnuct4YTa38wTMPpfZ598iAna+L/s/IDK8d5a+OCeDFwAw4fFiQmNENAdD8K847CHCCOTMvTjhr5gVCEIcUTPCj1FLVMGPP0Ll5zZETIBGBNMIuBwARLZfjij6fsHlACyh9IoC754FEy9td63RkgCEJeoI4oBBEILJQSFcCFWMpqGKN02YArgAzguV+9FrZoBlilgGzBBr71Ewg3vjEFaIwy6AHB6OHD5TRaN/hIoGfghl8vCDvDYX2EEBdhC98AHsAOwggB1WS/LsUMtuX2rX3NwghhjUAYXfQ62iKdEq+oY9mt4EQAFAodrhxwQK8SeRKTJOTz+2nRpD+az59Ux0xMlEUMYKkEaeFBSkRQE50zJ8TV8FrqY7ur3+iTOyYezC6JZkaLNQ3Ky0yN1WqSgO5UhF8Yp26FXcoc1zUgDqwJqKyv1g404//CJHUAU+EwADiGYAPlNfThsqIM36DvmlZDTqX7gTo4MxB2Oucj/6bMxfFn8LjDkYc/le6CsV53JWnn70NcvRDTISdWOt0bPEv9BvWXK6bOjvmUL5Syeroram+sht1pUeK6icsQLFo6dUdeh9qjr0lagOOBE4EThRbU4sMRFwInCijE6fpY9Xpqth8q9FOW1Hp8ZaZT/PWahE9CZV4gZV8MCIgxFXuR99NuITzoSeYMTBiIs04uZqsdQuMTYvSFtg6aaVCFeiUvQ2VimYczDnlU6DOVfOnHOW/wBzDuZcpDlPAkpCrzpY8xaDSUJnOxhzMOblTj8mYx5/EhlEMk0nO4gl4U8syrn1BOJrEw0B/6jDP3T3qWU2pf40aCEMyRYmpKAbus30/SlsMAWuqXT6MXFNP5wUY86NA2DlEw2BlZfZynPuUL3f/EtSa3Qy4akq0ubWy+PK1ktllHU85FGWJFsxY4yCJCOSsNTW/FEdlxzJz/eHwxHDjQkolbuKaigluh4roBSgVPcotcCBrgAbqFOb7RNRKPqcKNSHCil9gASokMLXDzYgxJ9EriHRpxJWj7hh6Bgyu8cygKFYe0rDULWAXGBdXRu2RdSozYyklFxUjU2VbTRS4E5cB+6VEUeyQFFa0ZAjNyH0m3T64Qo5hjykmQCMt2jjzenJKFr0Bv8F7AiJhWn0CngoZDHe8ho8MNwKGG5IHpoJwHCLNtxkvLBMMzHMl9YM3qzvMcsnoZrAIoNFBoucXUU1i3wMFjkVgEUWbZHv84Nf6pa98jDETeSEsTl+d4LeRtoBL7cEZllukwamWQHTPAHTnArANMtumqO1aS2qyQlr01x79KNF6a+hysBqg9WudBqstmpWewIlNTIBWG3ZrbaHZ1GaZFdb6M5as13jyofX65wwttXnros+EQ2hj1RD6I3nuR6YbDDZlU4/JpMdfxK5cf7dyX3b5p/EDRz4xhwv9G/Y86NGjI6iw8E6upSpe1fhxcg0O8smkUGAF0ubtNyZpQ8QsWF+kIzkX9FZVvhExPLLaLIZOO7N81HyLJLpIT42KHxtaZGn0Mu+TOY+OpVpyUSafyAG41yWqdEw94/D/D9Gi+zzOPd5lP/H4TAvyWaMwUHu88iM9Pgj6QOd+t1luBG50K66X8lf+EX+wvlfOTjK/8PMPr808+1N2lJQ3083tJaDC8+98WNSy03c709fPz+JIO75uXX6OpJfp8Pg8MmvJ/8PFYQnmOfjAgA= + tikv.json.gz: |- + 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 + overview.json.gz: |- + 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 +{{- end }} diff --git a/charts/tidb-cluster/templates/monitor-deployment.yaml b/charts/tidb-cluster/templates/monitor-deployment.yaml index 2d7127e02a..21f876b769 100644 --- a/charts/tidb-cluster/templates/monitor-deployment.yaml +++ b/charts/tidb-cluster/templates/monitor-deployment.yaml @@ -94,6 +94,17 @@ spec: - name: grafana image: {{ .Values.monitor.grafana.image }} imagePullPolicy: {{ .Values.monitor.grafana.imagePullPolicy | default "IfNotPresent" }} + lifecycle: + postStart: + exec: + command: + - "/bin/sh" + - "-c" + - > + gzip -dc /tmp/dashboard-gz/tidb.json.gz > /grafana-dashboard-definitions/tidb/tidb.json && + gzip -dc /tmp/dashboard-gz/pd.json.gz > /grafana-dashboard-definitions/tidb/pd.json && + gzip -dc /tmp/dashboard-gz/tikv.json.gz > /grafana-dashboard-definitions/tidb/tikv.json && + gzip -dc /tmp/dashboard-gz/overview.json.gz > /grafana-dashboard-definitions/tidb/overview.json {{- if .Values.monitor.grafana.resources }} resources: {{ toYaml .Values.monitor.grafana.resources | indent 12 }} @@ -136,6 +147,18 @@ spec: # mountPath: /etc/grafana - name: monitor-data mountPath: /data + - mountPath: /etc/grafana/provisioning/datasources + name: datasource + readOnly: false + - mountPath: /etc/grafana/provisioning/dashboards + name: dashboards-provisioning + readOnly: false + - mountPath: /tmp/dashboard-gz + name: dashboard-gz + readOnly: false + - mountPath: /grafana-dashboard-definitions/tidb + name: grafana-dashboard + readOnly: false {{- end }} volumes: - name: monitor-data @@ -160,6 +183,23 @@ spec: items: - key: grafana-config path: grafana.ini + - configMap: + name: {{ template "cluster.name" . }}-monitor + items: + - key: datasource-config + path: datasource.yaml + name: datasource + - configMap: + name: {{ template "cluster.name" . }}-monitor + items: + - key: dashboard-config + path: dashboards.yaml + name: dashboards-provisioning + - emptyDir: {} + name: grafana-dashboard + - configMap: + name: {{ template "cluster.name" . }}-monitor-dashboard + name: dashboard-gz {{- end }} {{- if .Values.monitor.tolerations }} tolerations: diff --git a/charts/tidb-cluster/templates/monitor-job.yaml b/charts/tidb-cluster/templates/monitor-job.yaml deleted file mode 100644 index 0a0b51745d..0000000000 --- a/charts/tidb-cluster/templates/monitor-job.yaml +++ /dev/null @@ -1,38 +0,0 @@ -{{- if (.Values.monitor.create) and (.Values.monitor.grafana.create) }} -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ template "cluster.name" . }}-monitor-configurator - labels: - app.kubernetes.io/name: {{ template "chart.name" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: monitor-configurator - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} -spec: - template: - metadata: - labels: - app.kubernetes.io/name: {{ template "chart.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: monitor-configurator - spec: - restartPolicy: OnFailure - containers: - - name: tidb-dashboard-installer - image: {{ .Values.monitor.dashboardInstaller.image }} - imagePullPolicy: {{ .Values.monitor.dashboardInstaller.imagePullPolicy | default "IfNotPresent" }} - args: - - {{ template "cluster.name" . }}-grafana:3000 - env: - - name: GRAFANA_USERNAME - valueFrom: - secretKeyRef: - name: {{ template "cluster.name" . }}-monitor - key: username - - name: GRAFANA_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "cluster.name" . }}-monitor - key: password -{{- end }} diff --git a/charts/tidb-cluster/values.yaml b/charts/tidb-cluster/values.yaml index b273332377..c3fc1042e7 100644 --- a/charts/tidb-cluster/values.yaml +++ b/charts/tidb-cluster/values.yaml @@ -207,12 +207,9 @@ monitor: persistent: false storageClassName: local-storage storage: 10Gi - dashboardInstaller: - image: pingcap/tidb-dashboard-installer:v2.0.0 - imagePullPolicy: IfNotPresent grafana: create: true - image: grafana/grafana:4.6.5 + image: grafana/grafana:6.0.1 imagePullPolicy: IfNotPresent logLevel: info resources: From ecdf6df0ee04233ea9b085dc8eff85c8ed6f83b5 Mon Sep 17 00:00:00 2001 From: xiaojingchen Date: Mon, 15 Apr 2019 17:11:59 +0800 Subject: [PATCH 07/13] ensure test env is ready before cases running (#386) ensure test env is ready before cases running --- tests/cmd/stability/main.go | 3 +- tests/fault.go | 53 +++++++++++++++++++ .../manager/static_pod_service.go | 9 ++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/tests/cmd/stability/main.go b/tests/cmd/stability/main.go index df2f5b32d1..f3c105bf67 100644 --- a/tests/cmd/stability/main.go +++ b/tests/cmd/stability/main.go @@ -39,6 +39,8 @@ func main() { conf := tests.ParseConfigOrDie() cli, kubeCli := client.NewCliOrDie() oa := tests.NewOperatorActions(cli, kubeCli, conf) + fta := tests.NewFaultTriggerAction(cli, kubeCli, conf) + fta.CheckAndRecoverEnvOrDie() tidbVersion := conf.GetTiDBVersionOrDie() upgardeTiDBVersions := conf.GetUpgradeTidbVersionsOrDie() @@ -203,7 +205,6 @@ func main() { backup.NewBackupCase(oa, clusterBackupFrom, clusterRestoreTo).RunOrDie() // stop a node and failover automatically - fta := tests.NewFaultTriggerAction(cli, kubeCli, conf) physicalNode, node, faultTime := fta.StopNodeOrDie() oa.CheckFailoverPendingOrDie(allClusters, &faultTime) oa.CheckFailoverOrDie(allClusters, node) diff --git a/tests/fault.go b/tests/fault.go index 4f8e75bea9..0f97efdf26 100644 --- a/tests/fault.go +++ b/tests/fault.go @@ -23,6 +23,8 @@ const ( ) type FaultTriggerActions interface { + CheckAndRecoverEnv() error + CheckAndRecoverEnvOrDie() StopNode() (string, string, time.Time, error) StopNodeOrDie() (string, string, time.Time) StartNode(physicalNode string, node string) error @@ -62,6 +64,57 @@ type faultTriggerActions struct { cfg *Config } +func (fa *faultTriggerActions) CheckAndRecoverEnv() error { + glog.Infof("ensure all nodes are running") + for _, physicalNode := range fa.cfg.Nodes { + for _, vNode := range physicalNode.Nodes { + err := fa.StartNode(physicalNode.PhysicalNode, vNode) + if err != nil { + return err + } + } + } + glog.Infof("ensure all etcds are running") + err := fa.StartETCD() + if err != nil { + return err + } + glog.Infof("ensure all kubelets are running") + for _, physicalNode := range fa.cfg.Nodes { + for _, vNode := range physicalNode.Nodes { + err := fa.StartKubelet(vNode) + if err != nil { + return err + } + } + } + glog.Infof("ensure all static pods are running") + for _, physicalNode := range fa.cfg.APIServers { + for _, vNode := range physicalNode.Nodes { + err := fa.StartKubeAPIServer(vNode) + if err != nil { + return err + } + err = fa.StartKubeControllerManager(vNode) + if err != nil { + return err + } + err = fa.StartKubeScheduler(vNode) + if err != nil { + return err + } + } + } + + return nil +} + +func (fa *faultTriggerActions) CheckAndRecoverEnvOrDie() { + if err:=fa.CheckAndRecoverEnv();err!=nil{ + glog.Fatal(err) + } +} + func (fa *faultTriggerActions) StopNode() (string, string, time.Time, error) { now := time.Now() node, err := getFaultNode(fa.kubeCli) diff --git a/tests/pkg/fault-trigger/manager/static_pod_service.go b/tests/pkg/fault-trigger/manager/static_pod_service.go index f30c38e6d1..b58e47cf89 100644 --- a/tests/pkg/fault-trigger/manager/static_pod_service.go +++ b/tests/pkg/fault-trigger/manager/static_pod_service.go @@ -15,6 +15,7 @@ package manager import ( "fmt" + "os" "os/exec" "github.com/golang/glog" @@ -74,6 +75,10 @@ func (m *Manager) StopKubeControllerManager() error { func (m *Manager) stopStaticPodService(serviceName string, fileName string) error { maniest := fmt.Sprintf("%s/%s", staticPodPath, fileName) + if _, err := os.Stat(maniest); os.IsNotExist(err) { + glog.Infof("%s had been stopped before", serviceName) + return nil + } shell := fmt.Sprintf("mkdir -p %s && mv %s %s", staticPodTmpPath, maniest, staticPodTmpPath) cmd := exec.Command("/bin/sh", "-c", shell) @@ -90,6 +95,10 @@ func (m *Manager) stopStaticPodService(serviceName string, fileName string) erro func (m *Manager) startStaticPodService(serviceName string, fileName string) error { maniest := fmt.Sprintf("%s/%s", staticPodTmpPath, fileName) + if _, err := os.Stat(maniest); os.IsNotExist(err) { + glog.Infof("%s had been started before", serviceName) + return nil + } shell := fmt.Sprintf("mv %s %s", maniest, staticPodPath) cmd := exec.Command("/bin/sh", "-c", shell) From 721531eaeea41a9c33babcf9f84b49a8f2f1d41e Mon Sep 17 00:00:00 2001 From: xiaojingchen Date: Tue, 16 Apr 2019 02:02:35 +0800 Subject: [PATCH 08/13] remove monitor config job check (#390) * remove monitor config job * fix fmt bug --- tests/actions.go | 11 ----------- tests/fault.go | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/tests/actions.go b/tests/actions.go index 35d6d52181..301663a12c 100644 --- a/tests/actions.go +++ b/tests/actions.go @@ -1224,17 +1224,6 @@ func (oa *operatorActions) monitorNormal(clusterInfo *TidbClusterConfig) (bool, glog.Infof("monitor ready replicas %d < 1", monitorDeployment.Status.ReadyReplicas) return false, nil } - configuratorJobName := fmt.Sprintf("%s-monitor-configurator", tcName) - monitorJob, err := oa.kubeCli.BatchV1().Jobs(ns).Get(configuratorJobName, metav1.GetOptions{}) - if err != nil { - glog.Infof("get monitor configurator job: [%s/%s] failed", ns, configuratorJobName) - return false, nil - } - if monitorJob.Status.Succeeded == 0 { - glog.Infof("the monitor configurator job: [%s/%s] had not success", ns, configuratorJobName) - return false, nil - } - if err := oa.checkPrometheus(clusterInfo); err != nil { glog.Infof("check [%s/%s]'s prometheus data failed: %v", ns, monitorDeploymentName, err) return false, nil diff --git a/tests/fault.go b/tests/fault.go index 0f97efdf26..d1b2862507 100644 --- a/tests/fault.go +++ b/tests/fault.go @@ -110,7 +110,7 @@ func (fa *faultTriggerActions) CheckAndRecoverEnv() error { } func (fa *faultTriggerActions) CheckAndRecoverEnvOrDie() { - if err:=fa.CheckAndRecoverEnv();err!=nil{ + if err := fa.CheckAndRecoverEnv(); err != nil { glog.Fatal(err) } } From 8e56b4167f681c98fc09d5d96bb8597e4ed051d9 Mon Sep 17 00:00:00 2001 From: Yeh-lei Wu Date: Tue, 16 Apr 2019 16:24:06 +0800 Subject: [PATCH 09/13] Update local-pv documentation (#383) * Update local-pv documentation Signed-off-by: Aylei --- docs/setup.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/setup.md b/docs/setup.md index 1dc33b4c74..564538cb0b 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -91,13 +91,22 @@ Use this command to confirm the mount point exist: $ mount | grep /mnt/disks/local-pv01 ``` -To auto-mount disks when your operating system is booted, you should edit `/etc/fstab` to include these mounting info: +### Auto-mount on reboot +To auto-mount disks when your operating system is booted, you should edit `/etc/fstab` to include these mounting info. + +Disk mount: +```shell +$ echo "/dev/nvme0n1 /mnt/disks/disk01 ext4 defaults 0 0" >> /etc/fstab +``` + +Bind mount: ```shell -$ echo "/dev/nvme0n1 /mnt/disks/disk0 none bind 0 0" >> /etc/fstab $ echo "/data/local-pv01 /mnt/disks/local-pv01 none bind 0 0" >> /etc/fstab ``` +### Deploy local-static-provisioner + After mounting all data disks on Kubernetes nodes, you can deploy [local-volume-provisioner](https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner) to automatically provision the mounted disks as Local PersistentVolumes. ```shell @@ -106,6 +115,20 @@ $ kubectl get po -n kube-system -l app=local-volume-provisioner $ kubectl get pv | grep local-storage ``` +### Remove a mount point + +If we want to remove a mount point, first we need to `umount` the mount point, and then delete the related directories. For example: + +```shell +$ umount /mnt/disks/local-pv01 +$ rm -rf /mnt/disks/local-pv01 +$ rm -rf /data/local-pv01 +``` + +You should also delete the related entries in `/etc/fstab` at the same time, otherwise the automount may cause problems when the machine restarts. + +> Note: The local-volume plugin expects paths to be stable, if you remove a previous mount-point in the discovery directory (default to `/mnt/disks/`), you should remove the PV manually to keep consistency. + ## Install TiDB Operator TiDB Operator uses [CRD](https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/) to extend Kubernetes, so to use TiDB Operator, you should first create `TidbCluster` custom resource kind. This is a one-time job, namely you can only need to do this once in your Kubernetes cluster. From b04d0d28f4961faaf2fd28445adf1fc107a23954 Mon Sep 17 00:00:00 2001 From: Yecheng Fu Date: Tue, 16 Apr 2019 17:32:13 +0800 Subject: [PATCH 10/13] Update Jenkins links in README.md (#395) * Update Jenkins urls in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a23abf7f0..a5ec632060 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - [**Blog**](https://www.pingcap.com/blog/) - [**For support, please contact PingCAP**](http://bit.ly/contact_us_via_github) -[![Build Status](https://internal.pingcap.net/jenkins/job/build_tidb_operator_master/badge/icon)](https://internal.pingcap.net/jenkins/job/build_tidb_operator_master) +[![Build Status](https://internal.pingcap.net/idc-jenkins/job/build_tidb_operator_master/badge/icon)](https://internal.pingcap.net/idc-jenkins/job/build_tidb_operator_master) [![codecov](https://codecov.io/gh/pingcap/tidb-operator/branch/master/graph/badge.svg)](https://codecov.io/gh/pingcap/tidb-operator) TiDB Operator manages [TiDB](https://github.com/pingcap/tidb) clusters on [Kubernetes](https://kubernetes.io) and automates tasks related to operating a TiDB cluster. It makes TiDB a truly cloud-native database. From 052b08752d565c0ea27f3046e7d5bcb7c5c7218f Mon Sep 17 00:00:00 2001 From: Yecheng Fu Date: Tue, 16 Apr 2019 17:34:18 +0800 Subject: [PATCH 11/13] - fix e2e workflow in CONTRIBUTING.md (#392) - use `[` instead of `[[` to be sh-compatible (SHELL defaults to sh on linux) --- Makefile | 6 +++--- docs/CONTRIBUTING.md | 2 +- tests/manifests/e2e/e2e.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 470dee6994..4f360a190e 100644 --- a/Makefile +++ b/Makefile @@ -46,9 +46,9 @@ e2e-docker-push: e2e-docker docker push "${DOCKER_REGISTRY}/pingcap/tidb-operator-e2e:latest" e2e-docker: e2e-build - [[ -d tests/images/e2e/tidb-operator ]] && rm -r tests/images/e2e/tidb-operator || true - [[ -d tests/images/e2e/tidb-cluster ]] && rm -r tests/images/e2e/tidb-cluster || true - [[ -d tests/images/e2e/tidb-backup ]] && rm -r tests/images/e2e/tidb-backup || true + [ -d tests/images/e2e/tidb-operator ] && rm -r tests/images/e2e/tidb-operator || true + [ -d tests/images/e2e/tidb-cluster ] && rm -r tests/images/e2e/tidb-cluster || true + [ -d tests/images/e2e/tidb-backup ] && rm -r tests/images/e2e/tidb-backup || true cp -r charts/tidb-operator tests/images/e2e cp -r charts/tidb-cluster tests/images/e2e cp -r charts/tidb-backup tests/images/e2e diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 677c253951..051f5d3f87 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -122,7 +122,7 @@ $ make e2e-docker-push After Docker images are pushed to the DinD Docker registry, run e2e tests: ```sh -$ kubectl apply -f manifests/tidb-operator-e2e.yaml +$ kubectl apply -f tests/manifests/e2e/e2e.yaml ``` You can get the e2e test report from the log of testing pod: diff --git a/tests/manifests/e2e/e2e.yaml b/tests/manifests/e2e/e2e.yaml index f99a23926f..723e433796 100644 --- a/tests/manifests/e2e/e2e.yaml +++ b/tests/manifests/e2e/e2e.yaml @@ -27,7 +27,7 @@ spec: serviceAccount: tidb-operator-e2e containers: - name: tidb-operator-e2e - image: "" + image: 127.0.0.1:5000/pingcap/tidb-operator-e2e:latest imagePullPolicy: Always command: - /usr/local/bin/e2e From b1c5ec602e8ad79993a619451601595e2b178ba8 Mon Sep 17 00:00:00 2001 From: Yeh-lei Wu Date: Tue, 16 Apr 2019 20:54:34 +0800 Subject: [PATCH 12/13] Support running stability test out of cluster (#397) * Support running stability test out of cluster Signed-off-by: Aylei * Gofmt Signed-off-by: Aylei * Address comments Signed-off-by: Aylei * Address review comments Signed-off-by: Aylei * Add local statbility test doc Signed-off-by: Aylei * Refine documents Signed-off-by: Aylei * Address comments, avoid launch stability test if config not explicitly provided Signed-off-by: Aylei * Update and rename local-stability-test.md to stability-test-cookbook.md --- docs/stability-test-cookbook.md | 54 ++++++++++++++++++++++++++++ tests/actions.go | 16 ++++----- tests/cmd/stability/main.go | 3 +- tests/config.go | 7 +++- tests/pkg/client/client.go | 62 +++++++++++++++++++++++++-------- 5 files changed, 116 insertions(+), 26 deletions(-) create mode 100644 docs/stability-test-cookbook.md diff --git a/docs/stability-test-cookbook.md b/docs/stability-test-cookbook.md new file mode 100644 index 0000000000..e163811d0b --- /dev/null +++ b/docs/stability-test-cookbook.md @@ -0,0 +1,54 @@ +# Stability Test Cookbook + +> Important notes: this guide is under heavy development and have complicated enviroment pre-requesites, things are ought to change in the future. + +The following commands assumes you are in the `tidb-operator` working directory: +```shell +# image will be tagged as YOUR_DOCKER_REGISTRY/pingcap/tidb-operator-stability-test:latest +$ export DOCKER_REGISTRY=${YOUR_DOCKER_REGISTRY} +$ make stability-test-push +$ kubectl apply -f ./tests/manifests/stability/stability-configmap.yaml +# edit the stability.yaml and change .spec.template.spec.containers[].image to the pushed image +$ vi ./tests/manifests/stability/stability.yaml +# apply the stability test pod +$ kubectl apply -f ./tests/manifests/stability/stability.yaml +``` + +## Alternative: run stability test in your local environment + +Deploy & witness flow can be tedious when developing stability-test, this document introduce that how to run stability-test out of the cluster(your local machine, usually) while still operating the remote cluster. + +### TL;DR: +```shell +$ telepresence --new-deployment ${POD_NAME} +$ go build -o stability ./tests/cmd/stability/main.go +$ ./stability --operator-repo-dir=${ABITRARY_EMPTY_DIR_TO_CLONE_OPERATOR_REPO} --kubeconfig=${YOUR_KUBE_CONFIG_PATH} +``` + +### Explained + +Generally we have three problems to solve: + +1. **Out of cluster client**: Now we try to load configs in the following order: + * if `kubeconfig` command line option provided, use it + * if `KUBECONFIG` env variable set, use it + * try loading `InClusterConfig()` +so you have to specify the `kubeconfig` path by either command line option or env variable if you want to test locally. +2. **Privilege issue**: If you don't want to or cannot run stability test with root privilege, change the working dir or create it in advance: + * git repo dir can be overridden by option `--git-repo-dir=xxxx`, but helm dir must be created manually. +```shell +# helm dir +$ mkdir /charts +$ chmod 777 /charts +# git repo dir if you don't set command line option +$ mkdir /tidb-operator +$ chmod 777 /tidb-operator +``` +3. **DNS and network issue**: Two-way proxy using Telepresence. We cannot resolve cluster dns name and access cluster ip easily, `telepresence` helps with that, it creates a proxy pod in the cluster and open a vpn connection to kubernetes cluster via this pod. Just run ([full documentations](https://www.telepresence.io/reference/install)): +```shell +$ brew cask install osxfuse +$ brew install datawire/blackbird/telepresence +$ telepresence --new-deployment ${POD_NAME} +``` +**PS**: If you cannot resolve cluster dns names after set up, try clear DNS cache. +**PSS**: Typically you can't use telepresence VPN mode with other VPNs (of course SSR is ok). diff --git a/tests/actions.go b/tests/actions.go index 301663a12c..02af71ef7a 100644 --- a/tests/actions.go +++ b/tests/actions.go @@ -234,10 +234,10 @@ func (oi *OperatorConfig) OperatorHelmSetString(m map[string]string) string { func (oa *operatorActions) DeployOperator(info *OperatorConfig) error { if info.Tag != "e2e" { - if err := cloneOperatorRepo(); err != nil { + if err := oa.cloneOperatorRepo(); err != nil { return err } - if err := checkoutTag(info.Tag); err != nil { + if err := oa.checkoutTag(info.Tag); err != nil { return err } } @@ -280,7 +280,7 @@ func (oa *operatorActions) CleanOperatorOrDie(info *OperatorConfig) { } func (oa *operatorActions) UpgradeOperator(info *OperatorConfig) error { - if err := checkoutTag(info.Tag); err != nil { + if err := oa.checkoutTag(info.Tag); err != nil { return err } @@ -1318,8 +1318,8 @@ func releaseIsNotFound(err error) bool { return strings.Contains(err.Error(), "not found") } -func cloneOperatorRepo() error { - cmd := fmt.Sprintf("git clone https://github.com/pingcap/tidb-operator.git /tidb-operator") +func (oa *operatorActions) cloneOperatorRepo() error { + cmd := fmt.Sprintf("git clone https://github.com/pingcap/tidb-operator.git %s", oa.cfg.OperatorRepoDir) glog.Info(cmd) res, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() if err != nil && !strings.Contains(string(res), "already exists") { @@ -1329,15 +1329,15 @@ func cloneOperatorRepo() error { return nil } -func checkoutTag(tagName string) error { - cmd := fmt.Sprintf(`cd /tidb-operator && +func (oa *operatorActions) checkoutTag(tagName string) error { + cmd := fmt.Sprintf(`cd %s && git stash -u && git checkout %s && mkdir -p /charts/%s && cp -rf charts/tidb-operator /charts/%s/tidb-operator && cp -rf charts/tidb-cluster /charts/%s/tidb-cluster && cp -rf charts/tidb-backup /charts/%s/tidb-backup`, - tagName, tagName, tagName, tagName, tagName) + oa.cfg.OperatorRepoDir, tagName, tagName, tagName, tagName, tagName) glog.Info(cmd) res, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() if err != nil { diff --git a/tests/cmd/stability/main.go b/tests/cmd/stability/main.go index f3c105bf67..e9a5733eef 100644 --- a/tests/cmd/stability/main.go +++ b/tests/cmd/stability/main.go @@ -21,17 +21,16 @@ import ( "github.com/golang/glog" "github.com/jinzhu/copier" + "github.com/pingcap/tidb-operator/tests/pkg/client" "k8s.io/apiserver/pkg/util/logs" "github.com/pingcap/tidb-operator/tests" "github.com/pingcap/tidb-operator/tests/backup" - "github.com/pingcap/tidb-operator/tests/pkg/client" ) func main() { logs.InitLogs() defer logs.FlushLogs() - go func() { glog.Info(http.ListenAndServe("localhost:6060", nil)) }() diff --git a/tests/config.go b/tests/config.go index ff182258c7..7af7be0a73 100644 --- a/tests/config.go +++ b/tests/config.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/golang/glog" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" ) // Config defines the config of operator tests @@ -22,6 +22,9 @@ type Config struct { Nodes []Nodes `yaml:"nodes" json:"nodes"` ETCDs []Nodes `yaml:"etcds" json:"etcds"` APIServers []Nodes `yaml:"apiservers" json:"apiservers"` + + // For local test + OperatorRepoDir string `yaml:"operator_repo_dir" json:"operator_repo_dir"` } // Nodes defines a series of nodes that belong to the same physical node. @@ -39,6 +42,8 @@ func NewConfig() *Config { flag.StringVar(&cfg.TidbVersions, "tidb-versions", "v2.1.3,v2.1.4", "tidb versions") flag.StringVar(&cfg.OperatorTag, "operator-tag", "master", "operator tag used to choose charts") flag.StringVar(&cfg.OperatorImage, "operator-image", "pingcap/tidb-operator:latest", "operator image") + flag.StringVar(&cfg.OperatorRepoDir, "operator-repo-dir", "/tidb-operator", "local directory to which tidb-operator cloned") + flag.Parse() return cfg } diff --git a/tests/pkg/client/client.go b/tests/pkg/client/client.go index 9c9e6f4354..080d07d79a 100644 --- a/tests/pkg/client/client.go +++ b/tests/pkg/client/client.go @@ -1,6 +1,9 @@ package client import ( + "flag" + "fmt" + "os" "time" "github.com/juju/errors" @@ -11,31 +14,45 @@ import ( "k8s.io/client-go/tools/clientcmd" ) +var ( + masterUrl string + kubeconfigPath string +) + +func init() { + flag.StringVar(&kubeconfigPath, "kubeconfig", "", + "path to a kubeconfig. Only required if out-of-cluster.") + flag.StringVar(&masterUrl, "master", "", + "address of the Kubernetes API server. Overrides any value in kubeconfig. "+ + "Only required if out-of-cluster.") +} + func NewCliOrDie() (versioned.Interface, kubernetes.Interface) { - cfg, err := rest.InClusterConfig() + cfg, err := GetConfig() if err != nil { panic(err) } - cfg.Timeout = 30 * time.Second - cli, err := versioned.NewForConfig(cfg) - if err != nil { - panic(err) - } + return buildClientsOrDie(cfg) +} - kubeCli, err := kubernetes.NewForConfig(cfg) - if err != nil { - panic(err) +func GetConfig() (*rest.Config, error) { + // If kubeconfigPath provided, use that + if len(kubeconfigPath) > 0 { + return clientcmd.BuildConfigFromFlags(masterUrl, kubeconfigPath) + } + // If an env variable is specified with the config locaiton, use that + if len(os.Getenv("KUBECONFIG")) > 0 { + return clientcmd.BuildConfigFromFlags(masterUrl, os.Getenv("KUBECONFIG")) + } + // If no explicit location, try the in-cluster config + if c, err := rest.InClusterConfig(); err == nil { + return c, nil } - return cli, kubeCli + return nil, fmt.Errorf("could not locate a kubeconfig") } -var ( - masterUrl string - kubeconfigPath string -) - type Client interface { kubernetes.Interface PingcapV1alpha1() v1alpha1.PingcapV1alpha1Interface @@ -74,3 +91,18 @@ func LoadConfig() (*rest.Config, error) { cfg, err := clientcmd.BuildConfigFromFlags(masterUrl, kubeconfigPath) return cfg, errors.Trace(err) } + +func buildClientsOrDie(cfg *rest.Config) (versioned.Interface, kubernetes.Interface) { + cfg.Timeout = 30 * time.Second + cli, err := versioned.NewForConfig(cfg) + if err != nil { + panic(err) + } + + kubeCli, err := kubernetes.NewForConfig(cfg) + if err != nil { + panic(err) + } + + return cli, kubeCli +} From 5a7db949b279ebf94664d6f0024de270cc6a3f64 Mon Sep 17 00:00:00 2001 From: Louis Date: Wed, 17 Apr 2019 11:04:15 +0800 Subject: [PATCH 13/13] update tidb secret docs and charts (#398) * update tidb secret docs and charts * update operation-guide.md * add _initialize_tidb_users.py.tpl --- .../scripts/_initialize_tidb_users.py.tpl | 23 ++++++++++++++++++ .../templates/tidb-initializer-job.yaml | 24 +------------------ charts/tidb-cluster/values.yaml | 2 +- docs/operation-guide.md | 11 +++++++-- .../tidb-cluster-values.yaml | 2 +- 5 files changed, 35 insertions(+), 27 deletions(-) create mode 100755 charts/tidb-cluster/templates/scripts/_initialize_tidb_users.py.tpl diff --git a/charts/tidb-cluster/templates/scripts/_initialize_tidb_users.py.tpl b/charts/tidb-cluster/templates/scripts/_initialize_tidb_users.py.tpl new file mode 100755 index 0000000000..19fa043669 --- /dev/null +++ b/charts/tidb-cluster/templates/scripts/_initialize_tidb_users.py.tpl @@ -0,0 +1,23 @@ +import os, MySQLdb +host = '{{ template "cluster.name" . }}-tidb' +port = 4000 +password_dir = '/etc/tidb/password' +conn = MySQLdb.connect(host=host, port=port, user='root', connect_timeout=5) +for file in os.listdir(password_dir): + if file.startswith('.'): + continue + user = file + with open(os.path.join(password_dir, file), 'r') as f: + password = f.read() + if user == 'root': + conn.cursor().execute("set password for 'root'@'%%' = %s;", (password,)) + else: + conn.cursor().execute("create user %s@'%%' identified by %s;", (user, password,)) +conn.cursor().execute("flush privileges;") +conn.commit() +{{- if .Values.tidb.initSql }} +with open('/data/init.sql', 'r') as sql: + for line in sql.readlines(): + conn.cursor().execute(line) + conn.commit() +{{- end }} diff --git a/charts/tidb-cluster/templates/tidb-initializer-job.yaml b/charts/tidb-cluster/templates/tidb-initializer-job.yaml index f406b6a1fd..e4c3eef9eb 100644 --- a/charts/tidb-cluster/templates/tidb-initializer-job.yaml +++ b/charts/tidb-cluster/templates/tidb-initializer-job.yaml @@ -27,29 +27,7 @@ spec: - python - -c - | - import os, MySQLdb - host = '{{ template "cluster.name" . }}-tidb' - port = 4000 - password_dir = '/etc/tidb/password' - conn = MySQLdb.connect(host=host, port=port, user='root', connect_timeout=5) - for file in os.listdir(password_dir): - if file.startswith('.'): - continue - user = file - with open(os.path.join(password_dir, file), 'r') as f: - password = f.read() - if user == 'root': - conn.cursor().execute("set password for 'root'@'%%' = %s;", (password,)) - else: - conn.cursor().execute("create user %s@'%%' identified by %s;", (user, password,)) - conn.cursor().execute("flush privileges;") - conn.commit() - {{- if .Values.tidb.initSql }} - with open('/data/init.sql', 'r') as sql: - for line in sql.readlines(): - conn.cursor().execute(line) - conn.commit() - {{- end }} +{{ tuple "scripts/_initialize_tidb_users.py.tpl" . | include "helm-toolkit.utils.template" | indent 10 }} volumeMounts: - name: password mountPath: /etc/tidb/password diff --git a/charts/tidb-cluster/values.yaml b/charts/tidb-cluster/values.yaml index c3fc1042e7..0ad116d01f 100644 --- a/charts/tidb-cluster/values.yaml +++ b/charts/tidb-cluster/values.yaml @@ -149,7 +149,7 @@ tikvPromGateway: tidb: replicas: 2 # The secret name of root password, you can create secret with following command: - # kubectl create secret generic tidb-secret --from-literal=root_password= + # kubectl create secret generic tidb-secret --from-literal=root= --namespace= # If unset, the root password will be empty and you can set it after connecting # passwordSecretName: tidb-secret # initSql is the SQL statements executed after the TiDB cluster is bootstrapped. diff --git a/docs/operation-guide.md b/docs/operation-guide.md index 75b95ffa2b..cad3ad6335 100644 --- a/docs/operation-guide.md +++ b/docs/operation-guide.md @@ -34,10 +34,17 @@ By default TiDB service is exposed using [`NodePort`](https://kubernetes.io/docs $ kubectl get svc -n ${namespace} # check the available services ``` -By default the TiDB cluster has no password set. You can specify a password by setting `tidb.password` in `values.yaml` before deploying. You can retrieve the password from the initialization `Secret`: +By default the TiDB cluster has no root password set. Setting a password in helm is insecure. Instead you can set the name of a K8s secret as `tidb.passwordSecretName` in `values.yaml`. Note that this is only used to initialize users: once your tidb cluster is initialized you may delete the secret. The format of the secret is `user=password`, so you can set the root user password with: + +``` +kubectl create namespace ${namespace} +kubectl create secret generic tidb-secret --from-literal=root= --namespace=${namespace} +``` + +You can retrieve the password from the initialization `Secret`: ```shell -$ PASSWORD=$(kubectl get secret -n ${namespace} ${releaseName}-tidb -ojsonpath="{.data.password}" | base64 --decode | awk '{print $6}') +$ PASSWORD=$(kubectl get secret -n ${namespace} tidb-secret -ojsonpath="{.data.root}" | base64 --decode) $ echo ${PASSWORD} ``` diff --git a/images/tidb-operator-e2e/tidb-cluster-values.yaml b/images/tidb-operator-e2e/tidb-cluster-values.yaml index 8ca3dc2ddb..734e1d2538 100644 --- a/images/tidb-operator-e2e/tidb-cluster-values.yaml +++ b/images/tidb-operator-e2e/tidb-cluster-values.yaml @@ -121,7 +121,7 @@ tikvPromGateway: tidb: replicas: 2 # The secret name of root password, you can create secret with following command: - # kubectl create secret generic tidb-secret --from-literal=root_password= + # kubectl create secret generic tidb-secret --from-literal=root= --namespace= # If unset, the root password will be empty and you can set it after connecting # passwordSecretName: tidb-secret # initSql is the SQL statements executed after the TiDB cluster is bootstrapped.