github.com/GoogleContainerTools/skaffold/v2@v2.13.2/pkg/diag/validator/config_connector.go (about)

     1  /*
     2  Copyright 2021 The Skaffold Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package validator
    18  
    19  import (
    20  	"context"
    21  
    22  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    23  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    24  	"k8s.io/apimachinery/pkg/runtime/schema"
    25  	"k8s.io/client-go/dynamic"
    26  	"k8s.io/client-go/kubernetes"
    27  	kstatus "sigs.k8s.io/cli-utils/pkg/kstatus/status"
    28  
    29  	"github.com/GoogleContainerTools/skaffold/v2/proto/v1"
    30  )
    31  
    32  var _ Validator = (*ConfigConnectorValidator)(nil)
    33  
    34  // ConfigConnectorValidator implements the Validator interface for Config Connector resources
    35  type ConfigConnectorValidator struct {
    36  	resourceSelector *CustomResourceSelector
    37  }
    38  
    39  // NewConfigConnectorValidator initializes a ConfigConnectorValidator
    40  func NewConfigConnectorValidator(k kubernetes.Interface, d dynamic.Interface, gvk schema.GroupVersionKind) *ConfigConnectorValidator {
    41  	return &ConfigConnectorValidator{resourceSelector: NewCustomResourceSelector(k, d, gvk)}
    42  }
    43  
    44  // Validate implements the Validate method for Validator interface
    45  func (ccv *ConfigConnectorValidator) Validate(ctx context.Context, ns string, opts metav1.ListOptions) ([]Resource, error) {
    46  	resources, err := ccv.resourceSelector.Select(ctx, ns, opts)
    47  	if err != nil {
    48  		return []Resource{}, err
    49  	}
    50  	var rs []Resource
    51  	for _, r := range resources.Items {
    52  		status, ae := getConfigConnectorStatus(r)
    53  		// TODO: add recommendations from error codes
    54  		// TODO: add resource logs
    55  		rs = append(rs, NewResourceFromObject(&r, Status(status), ae, nil))
    56  	}
    57  	return rs, nil
    58  }
    59  
    60  func getConfigConnectorStatus(res unstructured.Unstructured) (kstatus.Status, *proto.ActionableErr) {
    61  	result, err := kstatus.Compute(&res)
    62  	if err != nil || result == nil {
    63  		return kstatus.UnknownStatus, &proto.ActionableErr{ErrCode: proto.StatusCode_STATUSCHECK_UNKNOWN, Message: "unable to check resource status"}
    64  	}
    65  	var ae proto.ActionableErr
    66  	switch result.Status {
    67  	case kstatus.CurrentStatus:
    68  		ae = proto.ActionableErr{ErrCode: proto.StatusCode_STATUSCHECK_SUCCESS}
    69  	case kstatus.InProgressStatus:
    70  		// TODO: config connector resource status doesn't distinguish between resource that is making progress towards reconciling from one that is doomed.
    71  		// This is tracked in b/187759279 internally. As such to avoid stalling the status check phase until timeout in case of a failed resource,
    72  		// we report an error if there's any message reported without the status being success. This can cause skaffold to fail even when resources
    73  		// are rightly in an InProgress state, say while adding new nodes.
    74  		ae = proto.ActionableErr{ErrCode: proto.StatusCode_STATUSCHECK_CONFIG_CONNECTOR_IN_PROGRESS, Message: result.Message}
    75  	case kstatus.FailedStatus:
    76  		ae = proto.ActionableErr{ErrCode: proto.StatusCode_STATUSCHECK_CONFIG_CONNECTOR_FAILED, Message: result.Message}
    77  	case kstatus.TerminatingStatus:
    78  		ae = proto.ActionableErr{ErrCode: proto.StatusCode_STATUSCHECK_CONFIG_CONNECTOR_TERMINATING, Message: result.Message}
    79  	case kstatus.NotFoundStatus:
    80  		ae = proto.ActionableErr{ErrCode: proto.StatusCode_STATUSCHECK_CONFIG_CONNECTOR_NOT_FOUND, Message: result.Message}
    81  	case kstatus.UnknownStatus:
    82  		ae = proto.ActionableErr{ErrCode: proto.StatusCode_STATUSCHECK_UNKNOWN, Message: result.Message}
    83  	}
    84  	return result.Status, &ae
    85  }