mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-26 18:38:48 +01:00
143 lines
4.1 KiB
Go
143 lines
4.1 KiB
Go
package cache
|
|
|
|
import (
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
|
"github.com/argoproj/argo-cd/util/kube"
|
|
|
|
v1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
)
|
|
|
|
type node struct {
|
|
resourceVersion string
|
|
ref v1.ObjectReference
|
|
ownerRefs []metav1.OwnerReference
|
|
info []appv1.InfoItem
|
|
appName string
|
|
// available only for root application nodes
|
|
resource *unstructured.Unstructured
|
|
// networkingInfo are available only for known types involved into networking: Ingress, Service, Pod
|
|
networkingInfo *appv1.ResourceNetworkingInfo
|
|
images []string
|
|
health *appv1.HealthStatus
|
|
}
|
|
|
|
func (n *node) isRootAppNode() bool {
|
|
return n.appName != "" && len(n.ownerRefs) == 0
|
|
}
|
|
|
|
func (n *node) resourceKey() kube.ResourceKey {
|
|
return kube.NewResourceKey(n.ref.GroupVersionKind().Group, n.ref.Kind, n.ref.Namespace, n.ref.Name)
|
|
}
|
|
|
|
func (n *node) isParentOf(child *node) bool {
|
|
for i, ownerRef := range child.ownerRefs {
|
|
|
|
// backfill UID of inferred owner child references
|
|
if ownerRef.UID == "" && n.ref.Kind == ownerRef.Kind && n.ref.APIVersion == ownerRef.APIVersion && n.ref.Name == ownerRef.Name {
|
|
ownerRef.UID = n.ref.UID
|
|
child.ownerRefs[i] = ownerRef
|
|
return true
|
|
}
|
|
|
|
if n.ref.UID == ownerRef.UID {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func ownerRefGV(ownerRef metav1.OwnerReference) schema.GroupVersion {
|
|
gv, err := schema.ParseGroupVersion(ownerRef.APIVersion)
|
|
if err != nil {
|
|
gv = schema.GroupVersion{}
|
|
}
|
|
return gv
|
|
}
|
|
|
|
func (n *node) getApp(ns map[kube.ResourceKey]*node) string {
|
|
return n.getAppRecursive(ns, map[kube.ResourceKey]bool{})
|
|
}
|
|
|
|
func (n *node) getAppRecursive(ns map[kube.ResourceKey]*node, visited map[kube.ResourceKey]bool) string {
|
|
if !visited[n.resourceKey()] {
|
|
visited[n.resourceKey()] = true
|
|
} else {
|
|
log.Warnf("Circular dependency detected: %v.", visited)
|
|
return n.appName
|
|
}
|
|
|
|
if n.appName != "" {
|
|
return n.appName
|
|
}
|
|
for _, ownerRef := range n.ownerRefs {
|
|
gv := ownerRefGV(ownerRef)
|
|
if parent, ok := ns[kube.NewResourceKey(gv.Group, ownerRef.Kind, n.ref.Namespace, ownerRef.Name)]; ok {
|
|
app := parent.getAppRecursive(ns, visited)
|
|
if app != "" {
|
|
return app
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func newResourceKeySet(set map[kube.ResourceKey]bool, keys ...kube.ResourceKey) map[kube.ResourceKey]bool {
|
|
newSet := make(map[kube.ResourceKey]bool)
|
|
for k, v := range set {
|
|
newSet[k] = v
|
|
}
|
|
for i := range keys {
|
|
newSet[keys[i]] = true
|
|
}
|
|
return newSet
|
|
}
|
|
|
|
func (n *node) asResourceNode() appv1.ResourceNode {
|
|
gv, err := schema.ParseGroupVersion(n.ref.APIVersion)
|
|
if err != nil {
|
|
gv = schema.GroupVersion{}
|
|
}
|
|
parentRefs := make([]appv1.ResourceRef, len(n.ownerRefs))
|
|
for _, ownerRef := range n.ownerRefs {
|
|
ownerGvk := schema.FromAPIVersionAndKind(ownerRef.APIVersion, ownerRef.Kind)
|
|
ownerKey := kube.NewResourceKey(ownerGvk.Group, ownerRef.Kind, n.ref.Namespace, ownerRef.Name)
|
|
parentRefs[0] = appv1.ResourceRef{Name: ownerRef.Name, Kind: ownerKey.Kind, Namespace: n.ref.Namespace, Group: ownerKey.Group, UID: string(ownerRef.UID)}
|
|
}
|
|
return appv1.ResourceNode{
|
|
ResourceRef: appv1.ResourceRef{
|
|
UID: string(n.ref.UID),
|
|
Name: n.ref.Name,
|
|
Group: gv.Group,
|
|
Version: gv.Version,
|
|
Kind: n.ref.Kind,
|
|
Namespace: n.ref.Namespace,
|
|
},
|
|
ParentRefs: parentRefs,
|
|
Info: n.info,
|
|
ResourceVersion: n.resourceVersion,
|
|
NetworkingInfo: n.networkingInfo,
|
|
Images: n.images,
|
|
Health: n.health,
|
|
}
|
|
}
|
|
|
|
func (n *node) iterateChildren(ns map[kube.ResourceKey]*node, parents map[kube.ResourceKey]bool, action func(child appv1.ResourceNode, appName string)) {
|
|
for childKey, child := range ns {
|
|
if n.isParentOf(ns[childKey]) {
|
|
if parents[childKey] {
|
|
key := n.resourceKey()
|
|
log.Warnf("Circular dependency detected. %s is child and parent of %s", childKey.String(), key.String())
|
|
} else {
|
|
action(child.asResourceNode(), child.getApp(ns))
|
|
child.iterateChildren(ns, newResourceKeySet(parents, n.resourceKey()), action)
|
|
}
|
|
}
|
|
}
|
|
}
|