k3s/vendor/github.com/rancher/wrangler/pkg/apply/desiredset_apply.go

280 lines
6.1 KiB
Go
Raw Normal View History

2019-05-09 22:03:45 +00:00
package apply
2019-01-22 20:53:35 +00:00
import (
"crypto/sha1"
"encoding/hex"
"fmt"
"sync"
"time"
"github.com/sirupsen/logrus"
2019-01-22 20:53:35 +00:00
2019-07-12 17:13:20 +00:00
gvk2 "github.com/rancher/wrangler/pkg/gvk"
2019-01-22 20:53:35 +00:00
"github.com/pkg/errors"
2019-05-09 22:03:45 +00:00
"github.com/rancher/wrangler/pkg/apply/injectors"
"github.com/rancher/wrangler/pkg/objectset"
2019-01-22 20:53:35 +00:00
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/client-go/util/flowcontrol"
)
const (
LabelID = "objectset.rio.cattle.io/id"
LabelGVK = "objectset.rio.cattle.io/owner-gvk"
LabelName = "objectset.rio.cattle.io/owner-name"
LabelNamespace = "objectset.rio.cattle.io/owner-namespace"
LabelHash = "objectset.rio.cattle.io/hash"
2020-04-22 22:34:19 +00:00
LabelPrefix = "objectset.rio.cattle.io/"
2019-01-22 20:53:35 +00:00
)
var (
hashOrder = []string{
LabelID,
LabelGVK,
LabelName,
LabelNamespace,
}
rls = map[string]flowcontrol.RateLimiter{}
rlsLock sync.Mutex
)
2019-05-09 22:03:45 +00:00
func (o *desiredSet) getRateLimit(labelHash string) flowcontrol.RateLimiter {
2019-01-22 20:53:35 +00:00
var rl flowcontrol.RateLimiter
rlsLock.Lock()
defer rlsLock.Unlock()
if o.remove {
2019-05-09 22:03:45 +00:00
delete(rls, labelHash)
2019-01-22 20:53:35 +00:00
} else {
2019-05-09 22:03:45 +00:00
rl = rls[labelHash]
2019-01-22 20:53:35 +00:00
if rl == nil {
2019-05-09 22:03:45 +00:00
rl = flowcontrol.NewTokenBucketRateLimiter(o.ratelimitingQps, 10)
rls[labelHash] = rl
2019-01-22 20:53:35 +00:00
}
}
return rl
}
2020-04-22 22:34:19 +00:00
func (o *desiredSet) dryRun() (Plan, error) {
o.createPlan = true
o.plan.Create = objectset.ObjectKeyByGVK{}
o.plan.Update = PatchByGVK{}
o.plan.Delete = objectset.ObjectKeyByGVK{}
err := o.apply()
return o.plan, err
}
2019-05-09 22:03:45 +00:00
func (o *desiredSet) apply() error {
if o.objs == nil || o.objs.Len() == 0 {
o.remove = true
}
2019-01-22 20:53:35 +00:00
if err := o.Err(); err != nil {
return err
}
2020-04-22 22:34:19 +00:00
labelSet, annotationSet, err := GetLabelsAndAnnotations(o.setID, o.owner)
2019-01-22 20:53:35 +00:00
if err != nil {
return o.err(err)
}
rl := o.getRateLimit(labelSet[LabelHash])
if rl != nil {
t := time.Now()
rl.Accept()
if d := time.Now().Sub(t); d.Seconds() > 1 {
logrus.Infof("rate limited %s(%s) %s", o.setID, labelSet, d)
}
2019-01-22 20:53:35 +00:00
}
objList, err := o.injectLabelsAndAnnotations(labelSet, annotationSet)
if err != nil {
return o.err(err)
}
objList, err = o.runInjectors(objList)
if err != nil {
return o.err(err)
}
objs := o.collect(objList)
debugID := o.debugID()
2020-04-22 22:34:19 +00:00
sel, err := GetSelector(labelSet)
2019-01-22 20:53:35 +00:00
if err != nil {
return o.err(err)
}
2019-05-09 22:03:45 +00:00
for _, gvk := range o.objs.GVKOrder(o.knownGVK()...) {
2020-04-22 22:34:19 +00:00
o.process(debugID, sel, gvk, objs[gvk])
2019-01-22 20:53:35 +00:00
}
return o.Err()
}
2019-05-09 22:03:45 +00:00
func (o *desiredSet) knownGVK() (ret []schema.GroupVersionKind) {
for k := range o.pruneTypes {
ret = append(ret, k)
2019-01-22 20:53:35 +00:00
}
2019-05-09 22:03:45 +00:00
return
2019-01-22 20:53:35 +00:00
}
2019-05-09 22:03:45 +00:00
func (o *desiredSet) debugID() string {
2019-01-22 20:53:35 +00:00
if o.owner == nil {
return o.setID
}
metadata, err := meta.Accessor(o.owner)
if err != nil {
return o.setID
}
2019-05-09 22:03:45 +00:00
return fmt.Sprintf("%s %s", o.setID, objectset.ObjectKey{
Namespace: metadata.GetNamespace(),
Name: metadata.GetName(),
2019-01-22 20:53:35 +00:00
})
}
2019-05-09 22:03:45 +00:00
func (o *desiredSet) collect(objList []runtime.Object) objectset.ObjectByGVK {
result := objectset.ObjectByGVK{}
2019-01-22 20:53:35 +00:00
for _, obj := range objList {
2019-05-09 22:03:45 +00:00
result.Add(obj)
2019-01-22 20:53:35 +00:00
}
return result
}
2019-05-09 22:03:45 +00:00
func (o *desiredSet) runInjectors(objList []runtime.Object) ([]runtime.Object, error) {
2019-01-22 20:53:35 +00:00
var err error
for _, inj := range o.injectors {
if inj == nil {
continue
}
objList, err = inj(objList)
if err != nil {
return nil, err
}
}
2019-05-09 22:03:45 +00:00
for _, name := range o.injectorNames {
inj := injectors.Get(name)
if inj == nil {
continue
}
objList, err = inj(objList)
if err != nil {
return nil, err
}
}
2019-01-22 20:53:35 +00:00
return objList, nil
}
// GetSelectorFromOwner returns the label selector for the owner object which is useful
// to list the dependents
func GetSelectorFromOwner(setID string, owner runtime.Object) (labels.Selector, error) {
// Build the labels, we want the hash label for the lister
ownerLabel, _, err := GetLabelsAndAnnotations(setID, owner)
if err != nil {
return nil, err
}
return GetSelector(ownerLabel)
}
2020-04-22 22:34:19 +00:00
func GetSelector(labelSet map[string]string) (labels.Selector, error) {
req, err := labels.NewRequirement(LabelHash, selection.Equals, []string{labelSet[LabelHash]})
if err != nil {
return nil, err
}
return labels.NewSelector().Add(*req), nil
}
func GetLabelsAndAnnotations(setID string, owner runtime.Object) (map[string]string, map[string]string, error) {
if setID == "" && owner == nil {
return nil, nil, fmt.Errorf("set ID or owner must be set")
}
2019-01-22 20:53:35 +00:00
annotations := map[string]string{
2020-04-22 22:34:19 +00:00
LabelID: setID,
2019-01-22 20:53:35 +00:00
}
2020-04-22 22:34:19 +00:00
if owner != nil {
gvk, err := gvk2.Get(owner)
2019-07-12 17:13:20 +00:00
if err != nil {
return nil, nil, err
}
annotations[LabelGVK] = gvk.String()
2020-04-22 22:34:19 +00:00
metadata, err := meta.Accessor(owner)
2019-01-22 20:53:35 +00:00
if err != nil {
2019-07-12 17:13:20 +00:00
return nil, nil, fmt.Errorf("failed to get metadata for %s", gvk)
2019-01-22 20:53:35 +00:00
}
annotations[LabelName] = metadata.GetName()
annotations[LabelNamespace] = metadata.GetNamespace()
}
labels := map[string]string{
LabelHash: objectSetHash(annotations),
}
return labels, annotations, nil
}
2019-05-09 22:03:45 +00:00
func (o *desiredSet) injectLabelsAndAnnotations(labels, annotations map[string]string) ([]runtime.Object, error) {
2019-01-22 20:53:35 +00:00
var result []runtime.Object
2019-05-09 22:03:45 +00:00
for _, objMap := range o.objs.ObjectsByGVK() {
2019-01-22 20:53:35 +00:00
for key, obj := range objMap {
obj = obj.DeepCopyObject()
meta, err := meta.Accessor(obj)
if err != nil {
return nil, errors.Wrapf(err, "failed to get metadata for %s", key)
}
setLabels(meta, labels)
setAnnotations(meta, annotations)
result = append(result, obj)
}
}
return result, nil
}
func setAnnotations(meta metav1.Object, annotations map[string]string) {
objAnn := meta.GetAnnotations()
if objAnn == nil {
objAnn = map[string]string{}
}
delete(objAnn, LabelApplied)
for k, v := range annotations {
objAnn[k] = v
}
meta.SetAnnotations(objAnn)
}
func setLabels(meta metav1.Object, labels map[string]string) {
objLabels := meta.GetLabels()
if objLabels == nil {
objLabels = map[string]string{}
}
for k, v := range labels {
objLabels[k] = v
}
meta.SetLabels(objLabels)
}
func objectSetHash(labels map[string]string) string {
dig := sha1.New()
for _, key := range hashOrder {
dig.Write([]byte(labels[key]))
}
return hex.EncodeToString(dig.Sum(nil))
}