github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/actor/v7action/service_instance_list.go (about)

     1  package v7action
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
     7  	"code.cloudfoundry.org/cli/resources"
     8  	"code.cloudfoundry.org/cli/types"
     9  	"code.cloudfoundry.org/cli/util/batcher"
    10  	"code.cloudfoundry.org/cli/util/extract"
    11  	"code.cloudfoundry.org/cli/util/lookuptable"
    12  	"code.cloudfoundry.org/cli/util/railway"
    13  )
    14  
    15  type ServiceInstance struct {
    16  	Type                resources.ServiceInstanceType
    17  	Name                string
    18  	ServicePlanName     string
    19  	ServiceOfferingName string
    20  	ServiceBrokerName   string
    21  	BoundApps           []string
    22  	LastOperation       string
    23  	UpgradeAvailable    types.OptionalBoolean
    24  }
    25  
    26  type planDetails struct {
    27  	plan, offering, broker string
    28  }
    29  
    30  func (actor Actor) GetServiceInstancesForSpace(spaceGUID string, omitApps bool) ([]ServiceInstance, Warnings, error) {
    31  	var (
    32  		instances []resources.ServiceInstance
    33  		bindings  []resources.ServiceCredentialBinding
    34  		included  ccv3.IncludedResources
    35  	)
    36  
    37  	warnings, err := railway.Sequentially(
    38  		func() (warnings ccv3.Warnings, err error) {
    39  			instances, included, warnings, err = actor.CloudControllerClient.GetServiceInstances(
    40  				ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{spaceGUID}},
    41  				ccv3.Query{Key: ccv3.FieldsServicePlan, Values: []string{"guid", "name", "relationships.service_offering"}},
    42  				ccv3.Query{Key: ccv3.FieldsServicePlanServiceOffering, Values: []string{"guid", "name", "relationships.service_broker"}},
    43  				ccv3.Query{Key: ccv3.FieldsServicePlanServiceOfferingServiceBroker, Values: []string{"guid", "name"}},
    44  				ccv3.Query{Key: ccv3.OrderBy, Values: []string{ccv3.NameOrder}},
    45  				ccv3.Query{Key: ccv3.PerPage, Values: []string{ccv3.MaxPerPage}},
    46  			)
    47  			return
    48  		},
    49  		func() (warnings ccv3.Warnings, err error) {
    50  			if !omitApps {
    51  				return batcher.RequestByGUID(
    52  					extract.UniqueList("GUID", instances),
    53  					func(guids []string) (ccv3.Warnings, error) {
    54  						batch, warnings, err := actor.CloudControllerClient.GetServiceCredentialBindings(
    55  							ccv3.Query{Key: ccv3.ServiceInstanceGUIDFilter, Values: guids},
    56  							ccv3.Query{Key: ccv3.Include, Values: []string{"app"}},
    57  						)
    58  						bindings = append(bindings, batch...)
    59  						return warnings, err
    60  					},
    61  				)
    62  			}
    63  			return
    64  		},
    65  	)
    66  	if err != nil {
    67  		return nil, Warnings(warnings), err
    68  	}
    69  
    70  	planDetailsFromPlanGUIDLookup := buildPlanDetailsLookup(included)
    71  	boundAppsNamesFromInstanceGUIDLookup := buildBoundAppsLookup(bindings, spaceGUID)
    72  
    73  	result := make([]ServiceInstance, len(instances))
    74  	for i, instance := range instances {
    75  		names := planDetailsFromPlanGUIDLookup[instance.ServicePlanGUID]
    76  		result[i] = ServiceInstance{
    77  			Name:                instance.Name,
    78  			Type:                instance.Type,
    79  			UpgradeAvailable:    instance.UpgradeAvailable,
    80  			ServicePlanName:     names.plan,
    81  			ServiceOfferingName: names.offering,
    82  			ServiceBrokerName:   names.broker,
    83  			BoundApps:           boundAppsNamesFromInstanceGUIDLookup[instance.GUID],
    84  			LastOperation:       lastOperation(instance.LastOperation),
    85  		}
    86  	}
    87  
    88  	return result, Warnings(warnings), nil
    89  }
    90  
    91  func lastOperation(lo resources.LastOperation) string {
    92  	if lo.Type != "" && lo.State != "" {
    93  		return fmt.Sprintf("%s %s", lo.Type, lo.State)
    94  	}
    95  	return ""
    96  }
    97  
    98  func buildPlanDetailsLookup(included ccv3.IncludedResources) map[string]planDetails {
    99  	brokerLookup := lookuptable.NameFromGUID(included.ServiceBrokers)
   100  
   101  	type twoNames struct{ broker, offering string }
   102  	offeringLookup := make(map[string]twoNames)
   103  	for _, o := range included.ServiceOfferings {
   104  		brokerName := brokerLookup[o.ServiceBrokerGUID]
   105  		offeringLookup[o.GUID] = twoNames{
   106  			broker:   brokerName,
   107  			offering: o.Name,
   108  		}
   109  	}
   110  
   111  	planLookup := make(map[string]planDetails)
   112  	for _, p := range included.ServicePlans {
   113  		names := offeringLookup[p.ServiceOfferingGUID]
   114  		planLookup[p.GUID] = planDetails{
   115  			broker:   names.broker,
   116  			offering: names.offering,
   117  			plan:     p.Name,
   118  		}
   119  	}
   120  	return planLookup
   121  }
   122  
   123  func buildBoundAppsLookup(bindings []resources.ServiceCredentialBinding, spaceGUID string) map[string][]string {
   124  	appsBoundLookup := make(map[string][]string)
   125  	for _, binding := range bindings {
   126  		if binding.Type == resources.AppBinding && binding.AppSpaceGUID == spaceGUID {
   127  			appsBoundLookup[binding.ServiceInstanceGUID] = append(appsBoundLookup[binding.ServiceInstanceGUID], binding.AppName)
   128  		}
   129  	}
   130  	return appsBoundLookup
   131  }