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