blob: 94dabb3a7152916b2e95814678e4c3c62aa0f6c7 [file] [log] [blame]
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package kubernetes
import (
"context"
"strings"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type PodContainer struct {
// pod references
Pod *v1.Pod
ContainerSpec v1.Container
ContainerStatus v1.ContainerStatus
// the kubernetes resource registry
registry *Registry
}
// AnalyzeContainers means query the containers by pod
func AnalyzeContainers(pod *v1.Pod, registry *Registry) []*PodContainer {
containers := make([]*PodContainer, 0)
// nolint
for _, cs := range pod.Status.ContainerStatuses {
// nolint
for _, c := range pod.Spec.Containers {
if c.Name != cs.Name {
continue
}
containers = append(containers, &PodContainer{
Pod: pod,
ContainerSpec: c,
ContainerStatus: cs,
registry: registry,
})
}
}
return containers
}
func (c *PodContainer) CGroupID() string {
cgroupID := c.ContainerStatus.ContainerID
// delete the container runtime prefix is the cgroupid
cgroupID = strings.TrimPrefix(cgroupID, "containerd://")
cgroupID = strings.TrimPrefix(cgroupID, "dockerd://")
cgroupID = strings.TrimPrefix(cgroupID, "docker://")
return cgroupID
}
func (c *PodContainer) ServiceName() string {
return c.registry.FindServiceName(c.Pod.Namespace, c.Pod.Name)
}
// FindOwner means query the owner in the container, it would loop up with parent owner until empty
func (c *PodContainer) FindOwner(ctx context.Context, kindName string, k8sConfig *rest.Config) (*metav1.OwnerReference, error) {
// find in cache result
findedReferences := make([]metav1.OwnerReference, 0)
if owner := c.findOwner(c.Pod.OwnerReferences, kindName); owner != nil {
return owner, nil
}
findedReferences = append(findedReferences, c.Pod.OwnerReferences...)
// found from owner
for len(findedReferences) > 0 {
current := findedReferences[0]
findedReferences = findedReferences[1:]
// must be a controller
if c := current.Controller; c != nil && !*c {
continue
}
// query reference data
restClient, err := c.parseRestClientFromAPIVersion(k8sConfig, current.APIVersion)
if err != nil {
return nil, err
}
do := restClient.Get().Resource(current.Kind + "s").
Name(current.Name).
Namespace(c.Pod.Namespace).
Do(ctx)
if do.Error() != nil {
return nil, do.Error()
}
data := &unstructured.Unstructured{}
if err := do.Into(data); err != nil {
return nil, err
}
// query parent references from current reference
references := data.GetOwnerReferences()
if owner := c.findOwner(references, kindName); owner != nil {
return owner, nil
}
findedReferences = append(findedReferences, references...)
}
return nil, nil
}
func (c *PodContainer) parseRestClientFromAPIVersion(conf *rest.Config, apiVersion string) (rest.Interface, error) {
groupVersion, err := schema.ParseGroupVersion(apiVersion)
if err != nil {
return nil, err
}
queryConf := rest.CopyConfig(conf)
queryConf.GroupVersion = &groupVersion
queryConf.APIPath = "/apis"
queryConf.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
if queryConf.UserAgent == "" {
queryConf.UserAgent = rest.DefaultKubernetesUserAgent()
}
return rest.RESTClientFor(queryConf)
}
func (c *PodContainer) findOwner(refs []metav1.OwnerReference, kindName string) *metav1.OwnerReference {
for _, o := range refs {
if o.Kind == kindName {
return &o
}
}
return nil
}