github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/actor/v7action/service_instance_details.go (about) 1 package v7action 2 3 import ( 4 "code.cloudfoundry.org/cli/actor/actionerror" 5 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 6 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 7 "code.cloudfoundry.org/cli/resources" 8 "code.cloudfoundry.org/cli/util/extract" 9 "code.cloudfoundry.org/cli/util/railway" 10 ) 11 12 const featureFlagServiceInstanceSharing string = "service_instance_sharing" 13 14 type ServiceInstanceBoundAppCount struct { 15 OrgName string 16 SpaceName string 17 BoundAppCount int 18 } 19 20 type UsageSummaryWithSpaceAndOrg struct { 21 SpaceName string 22 OrganizationName string 23 BoundAppCount int 24 } 25 26 type SharedStatus struct { 27 FeatureFlagIsDisabled bool 28 OfferingDisablesSharing bool 29 IsSharedToOtherSpaces bool 30 IsSharedFromOriginalSpace bool 31 UsageSummary []UsageSummaryWithSpaceAndOrg 32 } 33 34 type ServiceInstanceParameters map[string]interface{} 35 36 type ServiceInstanceUpgradeState int 37 38 type ServiceInstanceUpgradeStatus struct { 39 State ServiceInstanceUpgradeState 40 Description string 41 } 42 43 const ( 44 ServiceInstanceUpgradeNotSupported ServiceInstanceUpgradeState = iota 45 ServiceInstanceUpgradeAvailable 46 ServiceInstanceUpgradeNotAvailable 47 ) 48 49 type ServiceInstanceDetails struct { 50 resources.ServiceInstance 51 SpaceName string 52 OrganizationName string 53 ServiceOffering resources.ServiceOffering 54 ServicePlan resources.ServicePlan 55 ServiceBrokerName string 56 SharedStatus SharedStatus 57 UpgradeStatus ServiceInstanceUpgradeStatus 58 BoundApps []resources.ServiceCredentialBinding 59 } 60 61 func (actor Actor) GetServiceInstanceDetails(serviceInstanceName string, spaceGUID string, omitApps bool) (ServiceInstanceDetails, Warnings, error) { 62 var serviceInstanceDetails ServiceInstanceDetails 63 64 warnings, err := railway.Sequentially( 65 func() (warnings ccv3.Warnings, err error) { 66 serviceInstanceDetails, warnings, err = actor.getServiceInstanceDetails(serviceInstanceName, spaceGUID) 67 return 68 }, 69 func() (warnings ccv3.Warnings, err error) { 70 serviceInstanceDetails.SharedStatus, warnings, err = actor.getServiceInstanceSharedStatus(serviceInstanceDetails, spaceGUID) 71 return 72 }, 73 func() (warnings ccv3.Warnings, err error) { 74 serviceInstanceDetails.UpgradeStatus, warnings, err = actor.getServiceInstanceUpgradeStatus(serviceInstanceDetails) 75 return 76 }, 77 func() (warnings ccv3.Warnings, err error) { 78 if !omitApps { 79 serviceInstanceDetails.BoundApps, warnings, err = actor.getServiceInstanceBoundApps(serviceInstanceDetails.GUID) 80 } 81 return 82 }, 83 ) 84 if err != nil { 85 return ServiceInstanceDetails{}, Warnings(warnings), err 86 } 87 88 return serviceInstanceDetails, Warnings(warnings), nil 89 } 90 91 func (actor Actor) GetServiceInstanceParameters(serviceInstanceName string, spaceGUID string) (ServiceInstanceParameters, Warnings, error) { 92 var serviceInstance resources.ServiceInstance 93 var parameters ServiceInstanceParameters 94 95 warnings, err := railway.Sequentially( 96 func() (warnings ccv3.Warnings, err error) { 97 serviceInstance, _, warnings, err = actor.getServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID) 98 return 99 }, 100 func() (warnings ccv3.Warnings, err error) { 101 parameters, warnings, err = actor.getServiceInstanceParameters(serviceInstance.GUID) 102 return 103 }, 104 ) 105 if err != nil { 106 return ServiceInstanceParameters{}, Warnings(warnings), err 107 } 108 109 return parameters, Warnings(warnings), nil 110 } 111 112 func (actor Actor) getServiceInstanceDetails(serviceInstanceName string, spaceGUID string) (ServiceInstanceDetails, ccv3.Warnings, error) { 113 query := []ccv3.Query{ 114 { 115 Key: ccv3.FieldsServicePlan, 116 Values: []string{"name", "guid"}, 117 }, 118 { 119 Key: ccv3.FieldsServicePlanServiceOffering, 120 Values: []string{"name", "guid", "description", "tags", "documentation_url"}, 121 }, 122 { 123 Key: ccv3.FieldsServicePlanServiceOfferingServiceBroker, 124 Values: []string{"name", "guid"}, 125 }, 126 { 127 Key: ccv3.FieldsSpace, 128 Values: []string{"name", "guid"}, 129 }, 130 { 131 Key: ccv3.FieldsSpaceOrganization, 132 Values: []string{"name", "guid"}, 133 }, 134 } 135 136 serviceInstance, included, warnings, err := actor.CloudControllerClient.GetServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID, query...) 137 switch err.(type) { 138 case nil: 139 case ccerror.ServiceInstanceNotFoundError: 140 return ServiceInstanceDetails{}, warnings, actionerror.ServiceInstanceNotFoundError{Name: serviceInstanceName} 141 default: 142 return ServiceInstanceDetails{}, warnings, err 143 } 144 145 result := ServiceInstanceDetails{ 146 ServiceInstance: serviceInstance, 147 ServicePlan: extractServicePlan(included), 148 ServiceOffering: extractServiceOffering(included), 149 ServiceBrokerName: extract.First("Name", included.ServiceBrokers), 150 SpaceName: extract.First("Name", included.Spaces), 151 OrganizationName: extract.First("Name", included.Organizations), 152 } 153 154 return result, warnings, nil 155 } 156 157 func (actor Actor) getServiceInstanceParameters(serviceInstanceGUID string) (ServiceInstanceParameters, ccv3.Warnings, error) { 158 params, warnings, err := actor.CloudControllerClient.GetServiceInstanceParameters(serviceInstanceGUID) 159 160 switch err := err.(type) { 161 case nil: 162 return ServiceInstanceParameters(params), warnings, nil 163 case ccerror.ResourceNotFoundError, 164 ccerror.ServiceInstanceParametersFetchNotSupportedError: 165 return ServiceInstanceParameters{}, warnings, actionerror.ServiceInstanceParamsFetchingNotSupportedError{} 166 default: 167 return ServiceInstanceParameters{}, warnings, err 168 } 169 } 170 171 func (actor Actor) getServiceInstanceSharedStatus(serviceInstanceDetails ServiceInstanceDetails, targetedSpace string) (SharedStatus, ccv3.Warnings, error) { 172 if serviceInstanceDetails.Type != resources.ManagedServiceInstance { 173 return SharedStatus{}, nil, nil 174 } 175 176 if targetedSpace != serviceInstanceDetails.SpaceGUID { 177 return SharedStatus{IsSharedFromOriginalSpace: true}, nil, nil 178 } 179 180 var ( 181 featureFlag resources.FeatureFlag 182 offeringDisablesSharing bool 183 sharedSpaces []ccv3.SpaceWithOrganization 184 usageSummaries []resources.ServiceInstanceUsageSummary 185 ) 186 187 warnings, err := railway.Sequentially( 188 func() (warnings ccv3.Warnings, err error) { 189 featureFlag, warnings, err = actor.CloudControllerClient.GetFeatureFlag(featureFlagServiceInstanceSharing) 190 return 191 }, 192 func() (warnings ccv3.Warnings, err error) { 193 offeringDisablesSharing, warnings, err = actor.getOfferingSharingDetails(serviceInstanceDetails.ServiceOffering.GUID) 194 return 195 }, 196 func() (warnings ccv3.Warnings, err error) { 197 sharedSpaces, warnings, err = actor.CloudControllerClient.GetServiceInstanceSharedSpaces(serviceInstanceDetails.GUID) 198 return 199 }, 200 func() (warnings ccv3.Warnings, err error) { 201 if len(sharedSpaces) > 0 { 202 usageSummaries, warnings, err = actor.CloudControllerClient.GetServiceInstanceUsageSummary(serviceInstanceDetails.GUID) 203 } 204 return 205 }, 206 ) 207 if err != nil { 208 return SharedStatus{}, warnings, err 209 } 210 211 sharedStatus := SharedStatus{ 212 IsSharedToOtherSpaces: len(sharedSpaces) > 0, 213 OfferingDisablesSharing: offeringDisablesSharing, 214 FeatureFlagIsDisabled: !featureFlag.Enabled, 215 UsageSummary: buildUsageSummary(sharedSpaces, usageSummaries), 216 } 217 218 return sharedStatus, warnings, nil 219 } 220 221 func (actor Actor) getOfferingSharingDetails(serviceOfferingGUID string) (bool, ccv3.Warnings, error) { 222 serviceOffering, serviceOfferingWarning, err := 223 actor.CloudControllerClient.GetServiceOfferingByGUID(serviceOfferingGUID) 224 225 switch err := err.(type) { 226 case nil: 227 return !serviceOffering.AllowsInstanceSharing, serviceOfferingWarning, nil 228 case ccerror.ServiceOfferingNotFoundError: 229 return false, serviceOfferingWarning, nil 230 default: 231 return false, serviceOfferingWarning, err 232 } 233 } 234 235 func (actor Actor) getServiceInstanceUpgradeStatus(serviceInstanceDetails ServiceInstanceDetails) (ServiceInstanceUpgradeStatus, ccv3.Warnings, error) { 236 if !serviceInstanceDetails.UpgradeAvailable.Value { 237 if serviceInstanceDetails.MaintenanceInfoVersion == "" { 238 return ServiceInstanceUpgradeStatus{State: ServiceInstanceUpgradeNotSupported}, nil, nil 239 } 240 return ServiceInstanceUpgradeStatus{State: ServiceInstanceUpgradeNotAvailable}, nil, nil 241 } 242 243 servicePlan, warnings, err := actor.CloudControllerClient.GetServicePlanByGUID(serviceInstanceDetails.ServicePlanGUID) 244 switch err.(type) { 245 case nil: 246 return ServiceInstanceUpgradeStatus{ 247 State: ServiceInstanceUpgradeAvailable, 248 Description: servicePlan.MaintenanceInfoDescription, 249 }, warnings, nil 250 case ccerror.ServicePlanNotFound: 251 return ServiceInstanceUpgradeStatus{ 252 State: ServiceInstanceUpgradeAvailable, 253 Description: "No upgrade details where found", 254 }, warnings, nil 255 default: 256 return ServiceInstanceUpgradeStatus{}, warnings, err 257 } 258 } 259 260 func (actor Actor) getServiceInstanceBoundApps(serviceInstanceGUID string) ([]resources.ServiceCredentialBinding, ccv3.Warnings, error) { 261 return actor.CloudControllerClient.GetServiceCredentialBindings( 262 ccv3.Query{Key: ccv3.Include, Values: []string{"app"}}, 263 ccv3.Query{Key: ccv3.ServiceInstanceGUIDFilter, Values: []string{serviceInstanceGUID}}, 264 ccv3.Query{Key: ccv3.TypeFilter, Values: []string{"app"}}, 265 ) 266 } 267 268 func extractServicePlan(included ccv3.IncludedResources) resources.ServicePlan { 269 if len(included.ServicePlans) == 1 { 270 return included.ServicePlans[0] 271 } 272 273 return resources.ServicePlan{} 274 } 275 276 func extractServiceOffering(included ccv3.IncludedResources) resources.ServiceOffering { 277 if len(included.ServiceOfferings) == 1 { 278 return included.ServiceOfferings[0] 279 } 280 281 return resources.ServiceOffering{} 282 } 283 284 func buildUsageSummary(sharedSpaces []ccv3.SpaceWithOrganization, usageSummaries []resources.ServiceInstanceUsageSummary) []UsageSummaryWithSpaceAndOrg { 285 var spaceGUIDToNames = make(map[string]ccv3.SpaceWithOrganization) 286 var sharedSpacesUsage []UsageSummaryWithSpaceAndOrg 287 288 for _, sharedSpace := range sharedSpaces { 289 spaceGUIDToNames[sharedSpace.SpaceGUID] = sharedSpace 290 } 291 for _, usageSummary := range usageSummaries { 292 summary := UsageSummaryWithSpaceAndOrg{ 293 SpaceName: spaceGUIDToNames[usageSummary.SpaceGUID].SpaceName, 294 OrganizationName: spaceGUIDToNames[usageSummary.SpaceGUID].OrganizationName, 295 BoundAppCount: usageSummary.BoundAppCount, 296 } 297 sharedSpacesUsage = append(sharedSpacesUsage, summary) 298 } 299 return sharedSpacesUsage 300 }