mirror of https://github.com/k3s-io/k3s
153 lines
3.6 KiB
Go
153 lines
3.6 KiB
Go
|
package apply
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/rancher/wrangler/pkg/gvk"
|
||
|
|
||
|
"github.com/rancher/wrangler/pkg/kv"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
namer "github.com/rancher/wrangler/pkg/name"
|
||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||
|
"k8s.io/apimachinery/pkg/runtime"
|
||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||
|
"k8s.io/client-go/dynamic"
|
||
|
"k8s.io/client-go/tools/cache"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
ErrOwnerNotFound = errors.New("owner not found")
|
||
|
)
|
||
|
|
||
|
func notFound(name string, gvk schema.GroupVersionKind) error {
|
||
|
// this is not proper, but does it really matter that much? If you find this
|
||
|
// line while researching a bug, then the answer is probably yes.
|
||
|
resource := namer.GuessPluralName(strings.ToLower(gvk.Kind))
|
||
|
return apierrors.NewNotFound(schema.GroupResource{
|
||
|
Group: gvk.Group,
|
||
|
Resource: resource,
|
||
|
}, name)
|
||
|
}
|
||
|
|
||
|
func getGVK(gvkLabel string, gvk *schema.GroupVersionKind) error {
|
||
|
parts := strings.Split(gvkLabel, ", Kind=")
|
||
|
if len(parts) != 2 {
|
||
|
return fmt.Errorf("invalid GVK format: %s", gvkLabel)
|
||
|
}
|
||
|
gvk.Group, gvk.Version = kv.Split(parts[0], "/")
|
||
|
gvk.Kind = parts[1]
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (o desiredSet) FindOwner(obj runtime.Object) (runtime.Object, error) {
|
||
|
if obj == nil {
|
||
|
return nil, ErrOwnerNotFound
|
||
|
}
|
||
|
meta, err := meta.Accessor(obj)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
debugID = fmt.Sprintf("%s/%s", meta.GetNamespace(), meta.GetName())
|
||
|
gvkLabel = meta.GetAnnotations()[LabelGVK]
|
||
|
namespace = meta.GetAnnotations()[LabelNamespace]
|
||
|
name = meta.GetAnnotations()[LabelName]
|
||
|
gvk schema.GroupVersionKind
|
||
|
)
|
||
|
|
||
|
if gvkLabel == "" {
|
||
|
return nil, ErrOwnerNotFound
|
||
|
}
|
||
|
|
||
|
if err := getGVK(gvkLabel, &gvk); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
cache, client, err := o.getControllerAndClient(debugID, gvk)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if cache != nil {
|
||
|
return o.fromCache(cache, namespace, name, gvk)
|
||
|
}
|
||
|
|
||
|
return o.fromClient(client, namespace, name, gvk)
|
||
|
}
|
||
|
|
||
|
func (o *desiredSet) fromClient(client dynamic.NamespaceableResourceInterface, namespace, name string, gvk schema.GroupVersionKind) (runtime.Object, error) {
|
||
|
var (
|
||
|
err error
|
||
|
obj interface{}
|
||
|
)
|
||
|
if namespace == "" {
|
||
|
obj, err = client.Get(o.ctx, name, metav1.GetOptions{})
|
||
|
} else {
|
||
|
obj, err = client.Namespace(namespace).Get(o.ctx, name, metav1.GetOptions{})
|
||
|
}
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if ro, ok := obj.(runtime.Object); ok {
|
||
|
return ro, nil
|
||
|
}
|
||
|
return nil, notFound(name, gvk)
|
||
|
}
|
||
|
|
||
|
func (o *desiredSet) fromCache(cache cache.SharedInformer, namespace, name string, gvk schema.GroupVersionKind) (runtime.Object, error) {
|
||
|
var key string
|
||
|
if namespace == "" {
|
||
|
key = name
|
||
|
} else {
|
||
|
key = namespace + "/" + name
|
||
|
}
|
||
|
item, ok, err := cache.GetStore().GetByKey(key)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
} else if !ok {
|
||
|
return nil, notFound(name, gvk)
|
||
|
} else if ro, ok := item.(runtime.Object); ok {
|
||
|
return ro, nil
|
||
|
}
|
||
|
return nil, notFound(name, gvk)
|
||
|
}
|
||
|
|
||
|
func (o desiredSet) PurgeOrphan(obj runtime.Object) error {
|
||
|
if obj == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
meta, err := meta.Accessor(obj)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if _, err := o.FindOwner(obj); apierrors.IsNotFound(err) {
|
||
|
gvk, err := gvk.Get(obj)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
o.strictCaching = false
|
||
|
_, client, err := o.getControllerAndClient(meta.GetName(), gvk)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if meta.GetNamespace() == "" {
|
||
|
return client.Delete(o.ctx, meta.GetName(), metav1.DeleteOptions{})
|
||
|
} else {
|
||
|
return client.Namespace(meta.GetNamespace()).Delete(o.ctx, meta.GetName(), metav1.DeleteOptions{})
|
||
|
}
|
||
|
} else if err == ErrOwnerNotFound {
|
||
|
return nil
|
||
|
} else if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|