...

Source file src/sigs.k8s.io/cli-utils/pkg/kstatus/polling/statusreaders/pod_controller.go

Documentation: sigs.k8s.io/cli-utils/pkg/kstatus/polling/statusreaders

     1  // Copyright 2020 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package statusreaders
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  
    10  	"k8s.io/apimachinery/pkg/api/meta"
    11  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    12  	"k8s.io/apimachinery/pkg/runtime/schema"
    13  	"sigs.k8s.io/cli-utils/pkg/kstatus/polling/engine"
    14  	"sigs.k8s.io/cli-utils/pkg/kstatus/polling/event"
    15  	"sigs.k8s.io/cli-utils/pkg/kstatus/status"
    16  	"sigs.k8s.io/cli-utils/pkg/object"
    17  )
    18  
    19  func newPodControllerStatusReader(mapper meta.RESTMapper, podStatusReader resourceTypeStatusReader) *podControllerStatusReader {
    20  	return &podControllerStatusReader{
    21  		mapper:          mapper,
    22  		podStatusReader: podStatusReader,
    23  		groupKind: schema.GroupKind{
    24  			Group: "",
    25  			Kind:  "Pod",
    26  		},
    27  		statusFunc:                status.Compute,
    28  		statusForGenResourcesFunc: statusForGeneratedResources,
    29  	}
    30  }
    31  
    32  // podControllerStatusReader encapsulates the logic needed to compute the status
    33  // for resource types that act as controllers for pods. This is quite common, so
    34  // the logic is here instead of duplicated in each resource specific StatusReader.
    35  type podControllerStatusReader struct {
    36  	mapper          meta.RESTMapper
    37  	podStatusReader resourceTypeStatusReader
    38  	groupKind       schema.GroupKind
    39  
    40  	statusFunc func(u *unstructured.Unstructured) (*status.Result, error)
    41  	// TODO(mortent): See if we can avoid this. For now it is useful for testing.
    42  	statusForGenResourcesFunc statusForGenResourcesFunc
    43  }
    44  
    45  func (p *podControllerStatusReader) readStatus(ctx context.Context, reader engine.ClusterReader, obj *unstructured.Unstructured) (*event.ResourceStatus, error) {
    46  	identifier := object.UnstructuredToObjMetadata(obj)
    47  
    48  	podResourceStatuses, err := p.statusForGenResourcesFunc(ctx, p.mapper, reader, p.podStatusReader, obj,
    49  		p.groupKind, "spec", "selector")
    50  	if err != nil {
    51  		return errResourceToResourceStatus(err, obj)
    52  	}
    53  
    54  	res, err := p.statusFunc(obj)
    55  	if err != nil {
    56  		return errResourceToResourceStatus(err, obj, podResourceStatuses...)
    57  	}
    58  
    59  	// If the status comes back as pending, we take a look at the pods to make sure
    60  	// none of them are in the failed state. If at least one of them are, then
    61  	// it is unlikely (but not impossible) that the status of the PodController will become
    62  	// Current without some kind of intervention.
    63  	if res.Status == status.InProgressStatus {
    64  		var failedPods []*event.ResourceStatus
    65  		for _, podResourceStatus := range podResourceStatuses {
    66  			if podResourceStatus.Status == status.FailedStatus {
    67  				failedPods = append(failedPods, podResourceStatus)
    68  			}
    69  		}
    70  		if len(failedPods) > 0 {
    71  			return &event.ResourceStatus{
    72  				Identifier:         identifier,
    73  				Status:             status.FailedStatus,
    74  				Resource:           obj,
    75  				Message:            fmt.Sprintf("%d pods have failed", len(failedPods)),
    76  				GeneratedResources: podResourceStatuses,
    77  			}, nil
    78  		}
    79  	}
    80  
    81  	return &event.ResourceStatus{
    82  		Identifier:         identifier,
    83  		Status:             res.Status,
    84  		Resource:           obj,
    85  		Message:            res.Message,
    86  		GeneratedResources: podResourceStatuses,
    87  	}, nil
    88  }
    89  

View as plain text