diff --git a/pkg/internal/discover/watcher_kube.go b/pkg/internal/discover/watcher_kube.go index f405673be..425c18e29 100644 --- a/pkg/internal/discover/watcher_kube.go +++ b/pkg/internal/discover/watcher_kube.go @@ -248,9 +248,9 @@ func withMetadata(pp processAttrs, info *kube.PodInfo) processAttrs { if info.Owner != nil { ret.metadata[attr.Name(info.Owner.LabelName).Prom()] = info.Owner.Name - topName, topLabel := info.Owner.TopOwnerNameLabel() - ret.metadata[attr.Name(topLabel).Prom()] = topName - ret.metadata[services.AttrOwnerName] = topName + topOwner := info.Owner.TopOwner() + ret.metadata[attr.Name(topOwner.LabelName).Prom()] = topOwner.Name + ret.metadata[services.AttrOwnerName] = topOwner.Name } return ret } diff --git a/pkg/internal/kube/informer.go b/pkg/internal/kube/informer.go index 27418b5be..ec3b3651f 100644 --- a/pkg/internal/kube/informer.go +++ b/pkg/internal/kube/informer.go @@ -324,8 +324,8 @@ func (k *Metadata) AddNodeEventHandler(h cache.ResourceEventHandler) error { } func (i *PodInfo) ServiceName() string { - if on, _ := i.Owner.TopOwnerNameLabel(); on != "" { - return on + if to := i.Owner.TopOwner(); to != nil { + return to.Name } return i.Name } diff --git a/pkg/internal/kube/owner.go b/pkg/internal/kube/owner.go index d8e99b909..13bfbb5ea 100644 --- a/pkg/internal/kube/owner.go +++ b/pkg/internal/kube/owner.go @@ -62,30 +62,30 @@ func unrecognizedOwner(or *metav1.OwnerReference) *Owner { } } -// TopOwnerNameLabel returns the top-level name and metadata label in the owner chain. +// TopOwner returns the top Owner in the owner chain. // For example, if the owner is a ReplicaSet, it will return the Deployment name. -func (o *Owner) TopOwnerNameLabel() (string, OwnerLabel) { - if o == nil { - return "", "" - } - if o.LabelName == OwnerReplicaSet { - // we have two levels of ownership at most - if o.Owner != nil { - return o.Owner.Name, o.Owner.LabelName - } - // if the replicaset informer is disabled, we can't get the owner deployment, - // so we will heuristically extract it from the ReplicaSet Name (and cache it) - topOwnerName := o.Name - if idx := strings.LastIndexByte(topOwnerName, '-'); idx > 0 { - topOwnerName = topOwnerName[:idx] +func (o *Owner) TopOwner() *Owner { + // we have two levels of ownership at most + if o != nil && o.LabelName == OwnerReplicaSet && o.Owner == nil { + // we heuristically extract the Deployment name from the replicaset name + if idx := strings.LastIndexByte(o.Name, '-'); idx > 0 { o.Owner = &Owner{ - Name: topOwnerName, + Name: o.Name[:idx], LabelName: OwnerDeployment, + Kind: "Deployment", } - return topOwnerName, OwnerDeployment + } else { + // just caching the own replicaset as owner, in order to cache the result + o.Owner = o } + return o.Owner + } + + // just return the highest existing owner (two levels of ownership maximum) + if o == nil || o.Owner == nil { + return o } - return o.Name, o.LabelName + return o.Owner } func (o *Owner) String() string { diff --git a/pkg/internal/kube/owner_test.go b/pkg/internal/kube/owner_test.go index db42359ac..9e2cba65c 100644 --- a/pkg/internal/kube/owner_test.go +++ b/pkg/internal/kube/owner_test.go @@ -61,27 +61,33 @@ func TestTopOwnerLabel(t *testing.T) { type testCase struct { expectedLabel OwnerLabel expectedName string + expectedKind string owner *Owner } for _, tc := range []testCase{ - {owner: nil}, - {expectedLabel: OwnerDaemonSet, expectedName: "ds", - owner: &Owner{LabelName: OwnerDaemonSet, Name: "ds"}}, - {expectedLabel: OwnerDeployment, expectedName: "rs-without-dep-meta", - owner: &Owner{LabelName: OwnerReplicaSet, Name: "rs-without-dep-meta-34fb1fa3a"}}, - {expectedLabel: OwnerDeployment, expectedName: "dep", - owner: &Owner{LabelName: OwnerReplicaSet, Name: "dep-34fb1fa3a", - Owner: &Owner{LabelName: OwnerDeployment, Name: "dep"}}}, + {expectedLabel: OwnerDaemonSet, expectedName: "ds", expectedKind: "DaemonSet", + owner: &Owner{LabelName: OwnerDaemonSet, Name: "ds", Kind: "DaemonSet"}}, + {expectedLabel: OwnerDeployment, expectedName: "rs-without-dep-meta", expectedKind: "Deployment", + owner: &Owner{LabelName: OwnerReplicaSet, Name: "rs-without-dep-meta-34fb1fa3a", Kind: "ReplicaSet"}}, + {expectedLabel: OwnerDeployment, expectedName: "dep", expectedKind: "Deployment", + owner: &Owner{LabelName: OwnerReplicaSet, Name: "dep-34fb1fa3a", Kind: "ReplicaSet", + Owner: &Owner{LabelName: OwnerDeployment, Name: "dep", Kind: "Deployment"}}}, } { t.Run(tc.expectedName, func(t *testing.T) { - name, label := tc.owner.TopOwnerNameLabel() - assert.Equal(t, tc.expectedName, name) - assert.Equal(t, tc.expectedLabel, label) + topOwner := tc.owner.TopOwner() + assert.Equal(t, tc.expectedName, topOwner.Name) + assert.Equal(t, tc.expectedLabel, topOwner.LabelName) + assert.Equal(t, tc.expectedKind, topOwner.Kind) // check that the output is consistent (e.g. after ReplicaSet owner data is cached) - name, label = tc.owner.TopOwnerNameLabel() - assert.Equal(t, tc.expectedName, name) - assert.Equal(t, tc.expectedLabel, label) + topOwner = tc.owner.TopOwner() + assert.Equal(t, tc.expectedName, topOwner.Name) + assert.Equal(t, tc.expectedLabel, topOwner.LabelName) + assert.Equal(t, tc.expectedKind, topOwner.Kind) }) } } + +func TestTopOwner_Nil(t *testing.T) { + assert.Nil(t, (*Owner)(nil).TopOwner()) +} diff --git a/pkg/internal/netolly/transform/k8s/kubernetes.go b/pkg/internal/netolly/transform/k8s/kubernetes.go index d5567c921..cd7a69a54 100644 --- a/pkg/internal/netolly/transform/k8s/kubernetes.go +++ b/pkg/internal/netolly/transform/k8s/kubernetes.go @@ -130,11 +130,12 @@ func (n *decorator) decorate(flow *ebpf.Record, prefix, ip string) bool { } return false } + topOwner := ipinfo.Owner.TopOwner() flow.Attrs.Metadata[attr.Name(prefix+attrSuffixNs)] = meta.Namespace flow.Attrs.Metadata[attr.Name(prefix+attrSuffixName)] = meta.Name flow.Attrs.Metadata[attr.Name(prefix+attrSuffixType)] = ipinfo.Kind - flow.Attrs.Metadata[attr.Name(prefix+attrSuffixOwnerName)] = ipinfo.Owner.Name - flow.Attrs.Metadata[attr.Name(prefix+attrSuffixOwnerType)] = ipinfo.Owner.Kind + flow.Attrs.Metadata[attr.Name(prefix+attrSuffixOwnerName)] = topOwner.Name + flow.Attrs.Metadata[attr.Name(prefix+attrSuffixOwnerType)] = topOwner.Kind if ipinfo.HostIP != "" { flow.Attrs.Metadata[attr.Name(prefix+attrSuffixHostIP)] = ipinfo.HostIP if ipinfo.HostName != "" { diff --git a/pkg/transform/k8s.go b/pkg/transform/k8s.go index 498f6123e..92011d205 100644 --- a/pkg/transform/k8s.go +++ b/pkg/transform/k8s.go @@ -130,8 +130,8 @@ func (md *metadataDecorator) appendMetadata(span *request.Span, info *kube.PodIn } if info.Owner != nil { span.ServiceID.Metadata[attr.Name(info.Owner.LabelName)] = info.Owner.Name - topName, topLabel := info.Owner.TopOwnerNameLabel() - span.ServiceID.Metadata[attr.Name(topLabel)] = topName + topOwner := info.Owner.TopOwner() + span.ServiceID.Metadata[attr.Name(topOwner.LabelName)] = topOwner.Name } // override hostname by the Pod name span.ServiceID.HostName = info.Name