github.com/verrazzano/verrazzano@v1.7.1/tools/vz/pkg/internal/util/cluster/deployments.go (about)

     1  // Copyright (c) 2021, 2024, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  // Package cluster handles cluster analysis
     5  package cluster
     6  
     7  import (
     8  	encjson "encoding/json"
     9  	"io"
    10  	"os"
    11  	"sync"
    12  
    13  	"go.uber.org/zap"
    14  	appsv1 "k8s.io/api/apps/v1"
    15  )
    16  
    17  var deploymentListMap = make(map[string]*appsv1.DeploymentList)
    18  var deploymentCacheMutex = &sync.Mutex{}
    19  
    20  // GetDeploymentList gets an deployment list
    21  func GetDeploymentList(log *zap.SugaredLogger, path string) (deploymentList *appsv1.DeploymentList, err error) {
    22  	// Check the cache first
    23  	deploymentList = getDeploymentListIfPresent(path)
    24  	if deploymentList != nil {
    25  		log.Debugf("Returning cached deploymentList for %s", path)
    26  		return deploymentList, nil
    27  	}
    28  
    29  	// Not found in the cache, get it from the file
    30  	file, err := os.Open(path)
    31  	if err != nil {
    32  		log.Debugf("file %s not found", path)
    33  		return nil, err
    34  	}
    35  	defer file.Close()
    36  
    37  	fileBytes, err := io.ReadAll(file)
    38  	if err != nil {
    39  		log.Debugf("Failed reading Json file %s", path)
    40  		return nil, err
    41  	}
    42  	err = encjson.Unmarshal(fileBytes, &deploymentList)
    43  	if err != nil {
    44  		log.Debugf("Failed to unmarshal deploymentList at %s", path)
    45  		return nil, err
    46  	}
    47  	putDeploymentListIfNotPresent(path, deploymentList)
    48  	return deploymentList, nil
    49  }
    50  
    51  // IsDeploymentProblematic returns a boolean indicating whether a deployment is deemed problematic or not
    52  func IsDeploymentProblematic(deployment *appsv1.Deployment) bool {
    53  	// If we can't determine the status conditions, we skip it
    54  	if len(deployment.Status.Conditions) == 0 {
    55  		return false
    56  	}
    57  	// If any conditions aren't in Available, flag this deployment as problematic
    58  	// Note that it could be progressing normally, but flagging it for now as it could be stuck
    59  	for _, condition := range deployment.Status.Conditions {
    60  		if condition.Type == appsv1.DeploymentAvailable {
    61  			continue
    62  		}
    63  		return true
    64  	}
    65  	return false
    66  }
    67  
    68  // FindProblematicDeployments will find and return all deployments deemed problematic in the deploymentList
    69  func FindProblematicDeployments(deploymentList *appsv1.DeploymentList) (deployments []appsv1.Deployment) {
    70  	for i, deployment := range deploymentList.Items {
    71  		if IsDeploymentProblematic(&deploymentList.Items[i]) {
    72  			deployments = append(deployments, deployment)
    73  		}
    74  	}
    75  	return deployments
    76  }
    77  
    78  func getDeploymentListIfPresent(path string) (deploymentList *appsv1.DeploymentList) {
    79  	deploymentCacheMutex.Lock()
    80  	deploymentListTest := deploymentListMap[path]
    81  	if deploymentListTest != nil {
    82  		deploymentList = deploymentListTest
    83  	}
    84  	deploymentCacheMutex.Unlock()
    85  	return deploymentList
    86  }
    87  
    88  func putDeploymentListIfNotPresent(path string, deploymentList *appsv1.DeploymentList) {
    89  	deploymentCacheMutex.Lock()
    90  	deploymentListInMap := deploymentListMap[path]
    91  	if deploymentListInMap == nil {
    92  		deploymentListMap[path] = deploymentList
    93  	}
    94  	deploymentCacheMutex.Unlock()
    95  }