...

Source file src/edge-infra.dev/pkg/edge/controllers/util/edgedb/infra_status.go

Documentation: edge-infra.dev/pkg/edge/controllers/util/edgedb

     1  package edgedb
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     9  
    10  	bannerApi "edge-infra.dev/pkg/edge/apis/banner/v1alpha1"
    11  	clusterApi "edge-infra.dev/pkg/edge/apis/cluster/v1alpha1"
    12  	gkeclusterApi "edge-infra.dev/pkg/edge/apis/gkecluster/v1alpha1"
    13  	"edge-infra.dev/pkg/edge/controllers/dbmetrics"
    14  	"edge-infra.dev/pkg/k8s/meta/status"
    15  	"edge-infra.dev/pkg/k8s/runtime/conditions"
    16  	"edge-infra.dev/pkg/lib/fog"
    17  )
    18  
    19  // InfraStatus is an enum whose values are written to the `infra_status` column in the `clusters` & `banners` tables.
    20  type InfraStatus string
    21  
    22  const (
    23  	InfraStatusReady InfraStatus = "READY"
    24  	InfraStatusError InfraStatus = "ERROR"
    25  
    26  	// Provisioning is the default value when rows are created. The db status util does not set this value.
    27  	InfraStatusProvisioning InfraStatus = "PROVISIONING"
    28  )
    29  
    30  const errorLogMessage = "Infra status not recorded"
    31  
    32  const sqlUpdateClusterStatus = "UPDATE clusters SET infra_status=$1, infra_status_details=$2, infra_status_updated_at=$3 WHERE cluster_edge_id=$4"
    33  const sqlUpdateBannerStatus = "UPDATE banners SET infra_status=$1, infra_status_details=$2, infra_status_updated_at=$3 WHERE banner_edge_id=$4"
    34  
    35  // Record takes a Banner, Cluster, or GKECluster object as input, and writes its infra status to the database. Errors are logged using the passed in context.
    36  //
    37  // NOTE: To make integration testing easier for consumers, this function safely returns, without panicing, when the wrapped DB is nil.
    38  func (edb *EdgeDB) RecordInfraStatus(ctx context.Context, obj conditions.Getter, recorder dbmetrics.DBMetrics) {
    39  	var log = fog.FromContext(ctx).WithName("dbinfrastatus")
    40  
    41  	if edb.DB == nil {
    42  		// Quietly exit when the wrapped DB is nil.
    43  		return
    44  	}
    45  
    46  	// choose the sql statement based on the object's kind
    47  	var stmt string
    48  	kind := obj.GetObjectKind().GroupVersionKind().Kind
    49  	switch kind {
    50  	case clusterApi.Kind, gkeclusterApi.Kind:
    51  		stmt = sqlUpdateClusterStatus
    52  	case bannerApi.BannerKind:
    53  		stmt = sqlUpdateBannerStatus
    54  	default:
    55  		err := fmt.Errorf("Kind not supported")
    56  		log.Error(err, errorLogMessage, "kind", kind)
    57  		return
    58  	}
    59  
    60  	var cv = columnValuesForObject(obj)
    61  	_, err := edb.DB.ExecContext(ctx, stmt, cv.InfraStatus, cv.InfraStatusDetails, cv.InfraStatusUpdatedAt, cv.EdgeID)
    62  	if err != nil {
    63  		log.Error(err, errorLogMessage)
    64  		recorder.RecordDBErrorsTotal(ctx, kind, obj.GetName())
    65  	} else {
    66  		recorder.RecordDBStatusWritesTotal(ctx, kind, toString(cv.InfraStatus))
    67  	}
    68  }
    69  
    70  type columnValues struct {
    71  	EdgeID               string
    72  	InfraStatus          InfraStatus
    73  	InfraStatusDetails   string
    74  	InfraStatusUpdatedAt time.Time
    75  }
    76  
    77  func conditionStatusToInfraStatus(v metav1.ConditionStatus) InfraStatus {
    78  	if v == metav1.ConditionTrue {
    79  		return InfraStatusReady
    80  	} else if v == metav1.ConditionFalse {
    81  		return InfraStatusError
    82  	}
    83  	return InfraStatusProvisioning
    84  }
    85  
    86  func columnValuesForObject(obj conditions.Getter) columnValues {
    87  	for _, cs := range obj.GetConditions() {
    88  		if cs.Type == status.ReadyCondition {
    89  			return columnValues{
    90  				EdgeID:               obj.GetName(),
    91  				InfraStatus:          conditionStatusToInfraStatus(cs.Status),
    92  				InfraStatusDetails:   fmt.Sprintf("%s: %s", cs.Reason, cs.Message),
    93  				InfraStatusUpdatedAt: cs.LastTransitionTime.Time,
    94  			}
    95  		}
    96  	}
    97  	return columnValues{
    98  		EdgeID:               obj.GetName(),
    99  		InfraStatus:          InfraStatusProvisioning,
   100  		InfraStatusDetails:   "Ready condition not found",
   101  		InfraStatusUpdatedAt: time.Now(),
   102  	}
   103  }
   104  
   105  func toString(infraStatus InfraStatus) string {
   106  	switch infraStatus {
   107  	case InfraStatusReady:
   108  		return "Ready"
   109  	case InfraStatusError:
   110  		return "Error"
   111  	case InfraStatusProvisioning:
   112  		return "Provisioning"
   113  	default:
   114  		return "Unknown"
   115  	}
   116  }
   117  

View as plain text