github.com/ablease/cli@v6.37.1-0.20180613014814-3adbb7d7fb19+incompatible/actor/v2action/service_instance_summary.go (about) 1 package v2action 2 3 import ( 4 "fmt" 5 "sort" 6 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 8 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant" 9 "code.cloudfoundry.org/cli/util/sorting" 10 log "github.com/sirupsen/logrus" 11 ) 12 13 type ServiceInstanceShareType string 14 15 const ( 16 ServiceInstanceIsSharedFrom ServiceInstanceShareType = "SharedFrom" 17 ServiceInstanceIsSharedTo ServiceInstanceShareType = "SharedTo" 18 ServiceInstanceIsNotShared ServiceInstanceShareType = "NotShared" 19 ) 20 21 type ServiceInstanceSummary struct { 22 ServiceInstance 23 24 ServicePlan ServicePlan 25 Service Service 26 ServiceInstanceSharingFeatureFlag bool 27 ServiceInstanceShareType ServiceInstanceShareType 28 ServiceInstanceSharedFrom ServiceInstanceSharedFrom 29 ServiceInstanceSharedTos []ServiceInstanceSharedTo 30 BoundApplications []BoundApplication 31 } 32 33 func (s ServiceInstanceSummary) IsShareable() bool { 34 return s.ServiceInstanceSharingFeatureFlag && s.Service.Extra.Shareable 35 } 36 37 func (s ServiceInstanceSummary) IsNotShared() bool { 38 return s.ServiceInstanceShareType == ServiceInstanceIsNotShared 39 } 40 41 func (s ServiceInstanceSummary) IsSharedFrom() bool { 42 return s.ServiceInstanceShareType == ServiceInstanceIsSharedFrom 43 } 44 45 func (s ServiceInstanceSummary) IsSharedTo() bool { 46 return s.ServiceInstanceShareType == ServiceInstanceIsSharedTo 47 } 48 49 type BoundApplication struct { 50 AppName string 51 ServiceBindingName string 52 } 53 54 func (actor Actor) GetServiceInstanceSummaryByNameAndSpace(name string, spaceGUID string) (ServiceInstanceSummary, Warnings, error) { 55 serviceInstance, instanceWarnings, err := actor.GetServiceInstanceByNameAndSpace(name, spaceGUID) 56 allWarnings := Warnings(instanceWarnings) 57 if err != nil { 58 return ServiceInstanceSummary{}, allWarnings, err 59 } 60 61 serviceInstanceSummary, warnings, err := actor.getSummaryInfoCompositeForInstance(spaceGUID, serviceInstance, true) 62 return serviceInstanceSummary, append(allWarnings, warnings...), err 63 } 64 65 func (actor Actor) GetServiceInstancesSummaryBySpace(spaceGUID string) ([]ServiceInstanceSummary, Warnings, error) { 66 serviceInstances, warnings, err := actor.CloudControllerClient.GetSpaceServiceInstances( 67 spaceGUID, 68 true) 69 allWarnings := Warnings(warnings) 70 71 log.WithField("number_of_service_instances", len(serviceInstances)).Info("listing number of service instances") 72 73 var summaryInstances []ServiceInstanceSummary 74 for _, instance := range serviceInstances { 75 serviceInstanceSummary, summaryInfoWarnings, summaryInfoErr := actor.getSummaryInfoCompositeForInstance( 76 spaceGUID, 77 ServiceInstance(instance), 78 false) 79 allWarnings = append(allWarnings, summaryInfoWarnings...) 80 if summaryInfoErr != nil { 81 return nil, allWarnings, summaryInfoErr 82 } 83 summaryInstances = append(summaryInstances, serviceInstanceSummary) 84 } 85 86 sort.Slice(summaryInstances, func(i, j int) bool { 87 return sorting.LessIgnoreCase(summaryInstances[i].Name, summaryInstances[j].Name) 88 }) 89 90 return summaryInstances, allWarnings, err 91 } 92 93 // getAndSetSharedInformation gets a service instance's shared from or shared to information, 94 func (actor Actor) getAndSetSharedInformation(summary *ServiceInstanceSummary, spaceGUID string) (Warnings, error) { 95 var ( 96 warnings Warnings 97 err error 98 ) 99 100 // Part of determining if a service instance is shareable, we need to find 101 // out if the service_instance_sharing feature flag is enabled 102 featureFlags, featureFlagsWarnings, featureFlagsErr := actor.CloudControllerClient.GetConfigFeatureFlags() 103 allWarnings := Warnings(featureFlagsWarnings) 104 if featureFlagsErr != nil { 105 return allWarnings, featureFlagsErr 106 } 107 108 for _, flag := range featureFlags { 109 if flag.Name == string(constant.FeatureFlagServiceInstanceSharing) { 110 summary.ServiceInstanceSharingFeatureFlag = flag.Enabled 111 } 112 } 113 114 // Service instance is shared from if: 115 // 1. the source space of the service instance is empty (API returns json null) 116 // 2. the targeted space is not the same as the source space of the service instance AND 117 // we call the shared_from url and it returns a non-empty resource 118 if summary.ServiceInstance.SpaceGUID == "" || summary.ServiceInstance.SpaceGUID != spaceGUID { 119 summary.ServiceInstanceSharedFrom, warnings, err = actor.GetServiceInstanceSharedFromByServiceInstance(summary.ServiceInstance.GUID) 120 allWarnings = append(allWarnings, warnings...) 121 if err != nil { 122 // if the API version does not support service instance sharing, ignore the 404 123 if _, ok := err.(ccerror.ResourceNotFoundError); !ok { 124 return allWarnings, err 125 } 126 } 127 128 if summary.ServiceInstanceSharedFrom.SpaceGUID != "" { 129 summary.ServiceInstanceShareType = ServiceInstanceIsSharedFrom 130 } else { 131 summary.ServiceInstanceShareType = ServiceInstanceIsNotShared 132 } 133 134 return allWarnings, nil 135 } 136 137 // Service instance is shared to if: 138 // the targeted space is the same as the source space of the service instance AND 139 // we call the shared_to url and get a non-empty list 140 summary.ServiceInstanceSharedTos, warnings, err = actor.GetServiceInstanceSharedTosByServiceInstance(summary.ServiceInstance.GUID) 141 allWarnings = append(allWarnings, warnings...) 142 if err != nil { 143 // if the API version does not support service instance sharing, ignore the 404 144 if _, ok := err.(ccerror.ResourceNotFoundError); !ok { 145 return allWarnings, err 146 } 147 } 148 149 if len(summary.ServiceInstanceSharedTos) > 0 { 150 summary.ServiceInstanceShareType = ServiceInstanceIsSharedTo 151 } else { 152 summary.ServiceInstanceShareType = ServiceInstanceIsNotShared 153 } 154 155 return allWarnings, nil 156 } 157 158 func (actor Actor) getSummaryInfoCompositeForInstance(spaceGUID string, serviceInstance ServiceInstance, retrieveSharedInfo bool) (ServiceInstanceSummary, Warnings, error) { 159 log.WithField("GUID", serviceInstance.GUID).Info("looking up service instance info") 160 161 serviceInstanceSummary := ServiceInstanceSummary{ServiceInstance: serviceInstance} 162 var ( 163 serviceBindings []ServiceBinding 164 allWarnings Warnings 165 ) 166 167 if serviceInstance.IsManaged() { 168 log.Debug("service is managed") 169 if retrieveSharedInfo { 170 sharedWarnings, err := actor.getAndSetSharedInformation(&serviceInstanceSummary, spaceGUID) 171 allWarnings = Warnings(sharedWarnings) 172 if err != nil { 173 log.WithField("GUID", serviceInstance.GUID).Errorln("looking up share info:", err) 174 return serviceInstanceSummary, allWarnings, err 175 } 176 } 177 178 servicePlan, planWarnings, err := actor.GetServicePlan(serviceInstance.ServicePlanGUID) 179 allWarnings = append(allWarnings, planWarnings...) 180 if err != nil { 181 log.WithField("service_plan_guid", serviceInstance.ServicePlanGUID).Errorln("looking up service plan:", err) 182 if _, ok := err.(ccerror.ForbiddenError); !ok { 183 return serviceInstanceSummary, allWarnings, err 184 } 185 log.Warning("Forbidden Error - ignoring and continue") 186 allWarnings = append(allWarnings, fmt.Sprintf("This org is not authorized to view necessary data about this service plan. Contact your administrator regarding service GUID %s.", serviceInstance.ServicePlanGUID)) 187 } 188 serviceInstanceSummary.ServicePlan = servicePlan 189 190 service, serviceWarnings, err := actor.GetService(serviceInstance.ServiceGUID) 191 allWarnings = append(allWarnings, serviceWarnings...) 192 if err != nil { 193 log.WithField("service_guid", serviceInstance.ServiceGUID).Errorln("looking up service:", err) 194 if _, ok := err.(ccerror.ForbiddenError); !ok { 195 return serviceInstanceSummary, allWarnings, err 196 } 197 log.Warning("Forbidden Error - ignoring and continue") 198 allWarnings = append(allWarnings, fmt.Sprintf("This org is not authorized to view necessary data about this service. Contact your administrator regarding service GUID %s.", serviceInstance.ServiceGUID)) 199 } 200 serviceInstanceSummary.Service = service 201 202 var bindingsWarnings Warnings 203 serviceBindings, bindingsWarnings, err = actor.GetServiceBindingsByServiceInstance(serviceInstance.GUID) 204 allWarnings = append(allWarnings, bindingsWarnings...) 205 if err != nil { 206 log.WithField("GUID", serviceInstance.GUID).Errorln("looking up service binding:", err) 207 return serviceInstanceSummary, allWarnings, err 208 } 209 } else { 210 log.Debug("service is user provided") 211 var bindingsWarnings Warnings 212 var err error 213 serviceBindings, bindingsWarnings, err = actor.GetServiceBindingsByUserProvidedServiceInstance(serviceInstance.GUID) 214 allWarnings = append(allWarnings, bindingsWarnings...) 215 if err != nil { 216 log.WithField("service_instance_guid", serviceInstance.GUID).Errorln("looking up service bindings:", err) 217 return serviceInstanceSummary, allWarnings, err 218 } 219 } 220 221 for _, serviceBinding := range serviceBindings { 222 log.WithFields(log.Fields{ 223 "app_guid": serviceBinding.AppGUID, 224 "service_binding_guid": serviceBinding.GUID, 225 }).Debug("application lookup") 226 227 app, appWarnings, err := actor.GetApplication(serviceBinding.AppGUID) 228 allWarnings = append(allWarnings, appWarnings...) 229 if err != nil { 230 log.WithFields(log.Fields{ 231 "app_guid": serviceBinding.AppGUID, 232 "service_binding_guid": serviceBinding.GUID, 233 }).Errorln("looking up application:", err) 234 return serviceInstanceSummary, allWarnings, err 235 } 236 237 serviceInstanceSummary.BoundApplications = append(serviceInstanceSummary.BoundApplications, BoundApplication{AppName: app.Name, ServiceBindingName: serviceBinding.Name}) 238 } 239 240 sort.Slice( 241 serviceInstanceSummary.BoundApplications, 242 func(i, j int) bool { 243 return sorting.LessIgnoreCase(serviceInstanceSummary.BoundApplications[i].AppName, serviceInstanceSummary.BoundApplications[j].AppName) 244 }) 245 246 return serviceInstanceSummary, allWarnings, nil 247 }