Ctrl K
ComunidadGuías…

pkg/ownership/resolve.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package ownership

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"

	"github.com/skyhook-io/radar/pkg/readreason"
	"github.com/skyhook-io/radar/pkg/resourceid"
)

// OwnerState is what one owner reference resolves to, judged as Kubernetes'
// garbage collector judges it.
type OwnerState uint8

const (
	// OwnerUnknown: whether the owner exists can't be told; the resolution's
	// Gap says why.
	OwnerUnknown OwnerState = iota
	// OwnerFound: the object the reference names exists with the reference's
	// UID.
	OwnerFound
	// OwnerGone: no object has the reference's coordinates. The collector
	// treats the reference as dangling.
	OwnerGone
	// OwnerReplaced: an object has the coordinates under another UID, a
	// later incarnation. The collector treats the reference as dangling too.
	OwnerReplaced
	// OwnerUnresolvable: the collector can't resolve the reference — its
	// apiVersion doesn't parse, it names no object, or it names a namespaced
	// owner for a cluster-scoped object — so it never collects the dependent
	// through it. A kind or version its RESTMapper doesn't map is unknown
	// instead (kind_unknown): the collector retries those, since the next
	// discovery may serve them. The RESTMapper maps a kind's all-lowercase
	// spelling too, and the internal version to any serving one.
	OwnerUnresolvable
	// OwnerExcluded: the reference names an Event, which ownership doesn't
	// read.
	OwnerExcluded
	// OwnerWithheld: the caller may not read the owner, so whether it exists
	// isn't said. Only a View, which reads for one caller, withholds.
	OwnerWithheld
)

func (s OwnerState) String() string {
	switch s {
	case OwnerFound:
		return "found"
	case OwnerGone:
		return "gone"
	case OwnerReplaced:
		return "replaced"
	case OwnerUnresolvable:
		return "unresolvable"
	case OwnerExcluded:
		return "excluded"
	case OwnerWithheld:
		return "withheld"
	default:
		return "unknown"
	}
}

// OwnerResolution is one owner reference resolved.
type OwnerResolution struct {
	State OwnerState
	// Ref is where the reference points. It is unset when the reference is
	// unresolvable, and when Radar can't map its kind or version to a scope
	// (OwnerUnknown with a gap saying why).
	Ref resourceid.Ref
	// Owner is the object at Ref, when Found or Replaced.
	Owner Observation
	// Gap says why, when Unknown.
	Gap Gap
}

// readFor reads an object for one caller, saying whether the caller may read
// it; an object the caller may not read is not read.
type readFor func(resourceid.Ref) (ObjectRead, Decision)

// ResolveOwner resolves one of dependent's owner references in s. The
// reference names an owner by group, kind and name; the owner is in the
// dependent's namespace when its kind is namespaced, cluster-wide otherwise,
// and only its UID tells one incarnation from the next.
func ResolveOwner(s ReadSession, dependent Observation, ref metav1.OwnerReference) OwnerResolution {
	return resolveOwner(s.Catalog(), dependent, ref, func(owner resourceid.Ref) (ObjectRead, Decision) {
		return s.Object(owner), Allowed
	})
}

// resolveOwner is ResolveOwner for the caller read reads for.
func resolveOwner(catalog *Catalog, dependent Observation, ref metav1.OwnerReference, read readFor) OwnerResolution {
	gv, err := schema.ParseGroupVersion(ref.APIVersion)
	if err != nil || ref.APIVersion == "" || ref.Kind == "" || ref.Name == "" {
		return OwnerResolution{State: OwnerUnresolvable}
	}
	gk, spelled := catalog.referencedKind(resourceid.GroupKind{Group: gv.Group, Kind: ref.Kind})
	if IsEvent(gk) {
		// Events are outside ownership, whatever discovery lists.
		return OwnerResolution{State: OwnerExcluded, Ref: resourceid.Ref{Group: gk.Group, Kind: gk.Kind, Namespace: dependent.Ref.Namespace, Name: ref.Name}}
	}
	unknown := OwnerResolution{Gap: Gap{Kind: gk, Reason: readreason.ReadError}}
	if !spelled || catalog.Ambiguous(gk) {
		return unknown
	}
	kind, known := catalog.Kind(gk)
	if !known || !catalog.mapsAt(gk, gv.Version) {
		// The collector retries a reference its RESTMapper can't map, since
		// its next discovery may serve the kind, and the catalog can be older
		// than the collector's discovery. So what discovery didn't list is
		// unknown, never unresolvable.
		if !catalog.Complete() {
			return unknown
		}
		return OwnerResolution{Gap: Gap{Kind: gk, Reason: readreason.KindUnknown}}
	}
	if kind.Namespaced && dependent.Ref.Namespace == "" {
		return OwnerResolution{State: OwnerUnresolvable}
	}
	owner := resourceid.Ref{Group: gk.Group, Kind: gk.Kind, Name: ref.Name}
	if kind.Namespaced {
		owner.Namespace = dependent.Ref.Namespace
	}
	got, may := read(owner)
	r := OwnerResolution{Ref: owner}
	switch may {
	case Denied:
		r.State = OwnerWithheld
		return r
	case Undecided:
		r.Gap = Gap{Kind: gk, Namespace: owner.Namespace, Reason: readreason.UserPermissionCheckFailed}
		return r
	}
	switch got.State {
	case Present:
		r.State, r.Owner = OwnerReplaced, got.Object
		if got.Object.UID == ref.UID {
			r.State = OwnerFound
		}
	case Absent:
		r.State = OwnerGone
	case Excluded:
		r.State = OwnerExcluded
	default:
		r.Gap = got.Gap
	}
	return r
}