Files
kubevela/pkg/resourcetracker/app.go
yangsoon 6cee468743 Feat: add more performance optimization and prometheus metrics for controller (#3086)
* Feat: add more prometheus metrics

Signed-off-by: yangsoon <yangsoonlx@gmail.com>

* Feat: add detail gc rt duration metrics

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Feat: add monitor to client

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Feat: add all cache object

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Fix: watch job

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Feat: add deleg client

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Feat: add optimize for rt list and disable controllerrevision

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Feat: add apprev disable optimize

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Fix: optimize log

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Feat: add time recorder for app ctrl

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Feat: add in-memory workflow context

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Feat: add reconcile-reduction & random-pick-gc & optimize rt record

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Feat: add optimize for healthcheck & resourcetracker trigger

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

* Chore: refactor

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

* Feat: record the resource-tracker number by informer event-handler

Signed-off-by: yangsoon <songyang.song@alibaba-inc.com>

* Feat: add promethus collect annotation in template

Signed-off-by: yangsoon <songyang.song@alibaba-inc.com>

* Fix: command line comment bug

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

* Chore: rename args and remove legacy controller metrics

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

* Fix: make code reviewable

Signed-off-by: yangsoon <songyang.song@alibaba-inc.com>

* Chore: optimize flag descriptions

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

* Chore: break optimize package

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

* Fix: gc policy test

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

Co-authored-by: Yin Da <yd219913@alibaba-inc.com>
Co-authored-by: yangsoon <songyang.song@alibaba-inc.com>
2022-01-14 15:18:02 +08:00

160 lines
6.8 KiB
Go

/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resourcetracker
import (
"context"
"fmt"
"github.com/oam-dev/kubevela/pkg/monitor/metrics"
"github.com/crossplane/crossplane-runtime/pkg/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/oam"
)
const (
// Finalizer for resourcetracker to clean up recorded resources
Finalizer = "resourcetracker.core.oam.dev/finalizer"
)
func getPublishVersion(obj client.Object) string {
if obj.GetAnnotations() != nil {
return obj.GetAnnotations()[oam.AnnotationPublishVersion]
}
return ""
}
func getRootResourceTrackerName(app *v1beta1.Application) string {
return fmt.Sprintf("%s-%s", app.Name, app.Namespace)
}
func getCurrentResourceTrackerName(app *v1beta1.Application) string {
return fmt.Sprintf("%s-v%d-%s", app.Name, app.GetGeneration(), app.Namespace)
}
func getComponentRevisionResourceTrackerName(app *v1beta1.Application) string {
return fmt.Sprintf("%s-comp-rev-%s", app.Name, app.Namespace)
}
func createResourceTracker(ctx context.Context, cli client.Client, app *v1beta1.Application, rtName string, rtType v1beta1.ResourceTrackerType) (*v1beta1.ResourceTracker, error) {
rt := &v1beta1.ResourceTracker{}
rt.SetName(rtName)
meta.AddFinalizer(rt, Finalizer)
meta.AddLabels(rt, map[string]string{
oam.LabelAppName: app.Name,
oam.LabelAppNamespace: app.Namespace,
oam.LabelAppUID: string(app.UID),
})
if app.Status.LatestRevision != nil {
meta.AddLabels(rt, map[string]string{oam.LabelAppRevision: app.Status.LatestRevision.Name})
}
rt.Spec.Type = rtType
if rtType == v1beta1.ResourceTrackerTypeVersioned {
rt.Spec.ApplicationGeneration = app.GetGeneration()
if publishVersion := getPublishVersion(app); publishVersion != "" {
meta.AddAnnotations(rt, map[string]string{oam.AnnotationPublishVersion: publishVersion})
}
} else {
rt.Spec.ApplicationGeneration = 0
}
if err := cli.Create(ctx, rt); err != nil {
return nil, err
}
return rt, nil
}
// CreateRootResourceTracker create root resourcetracker for application
func CreateRootResourceTracker(ctx context.Context, cli client.Client, app *v1beta1.Application) (*v1beta1.ResourceTracker, error) {
return createResourceTracker(ctx, cli, app, getRootResourceTrackerName(app), v1beta1.ResourceTrackerTypeRoot)
}
// CreateCurrentResourceTracker create versioned resourcetracker for the latest generation of application
func CreateCurrentResourceTracker(ctx context.Context, cli client.Client, app *v1beta1.Application) (*v1beta1.ResourceTracker, error) {
if publishVersion := getPublishVersion(app); publishVersion != "" {
return createResourceTracker(ctx, cli, app, fmt.Sprintf("%s-%s-%s", app.Name, publishVersion, app.Namespace), v1beta1.ResourceTrackerTypeVersioned)
}
return createResourceTracker(ctx, cli, app, getCurrentResourceTrackerName(app), v1beta1.ResourceTrackerTypeVersioned)
}
// CreateComponentRevisionResourceTracker create resourcetracker to record all component revision for application
func CreateComponentRevisionResourceTracker(ctx context.Context, cli client.Client, app *v1beta1.Application) (*v1beta1.ResourceTracker, error) {
return createResourceTracker(ctx, cli, app, getComponentRevisionResourceTrackerName(app), v1beta1.ResourceTrackerTypeComponentRevision)
}
// ListApplicationResourceTrackers list resource trackers for application with all historyRTs sorted by version number
func ListApplicationResourceTrackers(ctx context.Context, cli client.Client, app *v1beta1.Application) (rootRT *v1beta1.ResourceTracker, currentRT *v1beta1.ResourceTracker, historyRTs []*v1beta1.ResourceTracker, crRT *v1beta1.ResourceTracker, err error) {
metrics.ListResourceTrackerCounter.WithLabelValues("application").Inc()
rts := v1beta1.ResourceTrackerList{}
if err = cli.List(ctx, &rts, client.MatchingLabels{
oam.LabelAppName: app.Name,
oam.LabelAppNamespace: app.Namespace,
}); err != nil {
return nil, nil, nil, nil, err
}
for _, _rt := range rts.Items {
rt := _rt.DeepCopy()
if rt.GetLabels() != nil && rt.GetLabels()[oam.LabelAppUID] != "" && rt.GetLabels()[oam.LabelAppUID] != string(app.UID) {
return nil, nil, nil, nil, fmt.Errorf("resourcetracker %s exists but controlled by another application (uid: %s), this could probably be cased by some mistakes while garbage collecting outdated resource. Please check this resourcetrakcer and delete it manually", rt.Name, rt.GetLabels()[oam.LabelAppUID])
}
switch rt.Spec.Type {
case v1beta1.ResourceTrackerTypeRoot:
rootRT = rt
case v1beta1.ResourceTrackerTypeVersioned:
if publishVersion := getPublishVersion(app); publishVersion != "" {
if getPublishVersion(rt) == publishVersion {
currentRT = rt
} else {
historyRTs = append(historyRTs, rt)
}
} else {
if rt.Spec.ApplicationGeneration == app.GetGeneration() {
currentRT = rt
} else {
historyRTs = append(historyRTs, rt)
}
}
case v1beta1.ResourceTrackerTypeComponentRevision:
crRT = rt
}
}
historyRTs = SortResourceTrackersByVersion(historyRTs, false)
if currentRT != nil && len(historyRTs) > 0 && currentRT.Spec.ApplicationGeneration < historyRTs[len(historyRTs)-1].Spec.ApplicationGeneration {
return nil, nil, nil, nil, fmt.Errorf("current publish version %s(gen-%d) is in-use and outdated, found newer gen-%d", getPublishVersion(app), currentRT.Spec.ApplicationGeneration, historyRTs[len(historyRTs)-1].Spec.ApplicationGeneration)
}
return rootRT, currentRT, historyRTs, crRT, nil
}
// RecordManifestInResourceTracker records resources in ResourceTracker
func RecordManifestInResourceTracker(ctx context.Context, cli client.Client, rt *v1beta1.ResourceTracker, manifest *unstructured.Unstructured, metaOnly bool) error {
if updated := rt.AddManagedResource(manifest, metaOnly); !updated {
return nil
}
return cli.Update(ctx, rt)
}
// DeletedManifestInResourceTracker marks resources as deleted in resourcetracker, if remove is true, resources will be removed from resourcetracker
func DeletedManifestInResourceTracker(ctx context.Context, cli client.Client, rt *v1beta1.ResourceTracker, manifest *unstructured.Unstructured, remove bool) error {
if updated := rt.DeleteManagedResource(manifest, remove); !updated {
return nil
}
return cli.Update(ctx, rt)
}