github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/actor/v2action/composite/service_broker_summary.go (about) 1 package composite 2 3 import ( 4 "code.cloudfoundry.org/cli/actor/actionerror" 5 "code.cloudfoundry.org/cli/actor/v2action" 6 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant" 7 ) 8 9 //go:generate counterfeiter . ServiceActor 10 11 type ServiceActor interface { 12 GetServicesWithPlans(filters ...v2action.Filter) (v2action.ServicesWithPlans, v2action.Warnings, error) 13 ServiceExistsWithName(serviceName string) (bool, v2action.Warnings, error) 14 } 15 16 //go:generate counterfeiter . BrokerActor 17 18 type BrokerActor interface { 19 GetServiceBrokerByName(brokerName string) (v2action.ServiceBroker, v2action.Warnings, error) 20 GetServiceBrokers() ([]v2action.ServiceBroker, v2action.Warnings, error) 21 } 22 23 //go:generate counterfeiter . OrganizationActor 24 25 type OrganizationActor interface { 26 GetOrganization(organizationGUID string) (v2action.Organization, v2action.Warnings, error) 27 OrganizationExistsWithName(organizationName string) (bool, v2action.Warnings, error) 28 } 29 30 //go:generate counterfeiter . VisibilityActor 31 32 type VisibilityActor interface { 33 GetServicePlanVisibilities(planGUID string) ([]v2action.ServicePlanVisibility, v2action.Warnings, error) 34 } 35 36 type ServiceBrokerSummaryCompositeActor struct { 37 ServiceActor ServiceActor 38 BrokerActor BrokerActor 39 OrgActor OrganizationActor 40 VisibilityActor VisibilityActor 41 } 42 43 // GetServiceBrokerSummaries returns summaries for service brokers that match the arguments passed. 44 // An error will be returned if any of the options are invalid (i.e. there is no broker, service or 45 // organization with the given names). Consider the structure of Service Brokers, Services, 46 // and Plans as a tree (a Broker may have many Services, a Service may have many Plans) for the purpose 47 // of this explanation. Each of the provided arguments will act as a filtering mechanism, 48 // with the expectation that the caller does not want matches for "parent" concepts, if they have no 49 // "children" matching a filtered argument. 50 // 51 // For example, given a Broker "Foo", only containing a Service "Bar": 52 // 53 // `GetServiceBrokerSummaries("Foo", "NotBar", "")` will return a slice of broker summaries that does not 54 // include the Broker "Foo". 55 // 56 // Similarly, given a broker "Foo", containing a Service "Bar", that has plans available only in Organization "Baz": 57 // 58 // `GetServiceBrokerSummaries("Foo", "Bar", "NotBaz") will recurse upwards resulting in a slice of broker 59 // summaries that does not include the Broker "Foo" either. 60 func (c *ServiceBrokerSummaryCompositeActor) GetServiceBrokerSummaries(brokerName string, serviceName string, organizationName string) ([]v2action.ServiceBrokerSummary, v2action.Warnings, error) { 61 var warnings v2action.Warnings 62 63 if organizationName != "" { 64 orgExistsWarnings, err := c.ensureOrgExists(organizationName) 65 warnings = append(warnings, orgExistsWarnings...) 66 if err != nil { 67 return nil, warnings, err 68 } 69 } 70 71 if serviceName != "" { 72 serviceExistsWarnings, err := c.ensureServiceExists(serviceName) 73 warnings = append(warnings, serviceExistsWarnings...) 74 if err != nil { 75 return nil, warnings, err 76 } 77 } 78 79 brokers, brokerWarnings, err := c.getServiceBrokers(brokerName) 80 warnings = append(warnings, brokerWarnings...) 81 if err != nil { 82 return nil, warnings, err 83 } 84 85 brokerSummaries, brokerSummaryWarnings, err := c.fetchBrokerSummaries(brokers, serviceName, organizationName) 86 warnings = append(warnings, brokerSummaryWarnings...) 87 if err != nil { 88 return nil, warnings, err 89 } 90 91 if organizationName != "" || serviceName != "" { 92 brokerSummaries = pruneEmptyLeaves(brokerSummaries) 93 } 94 95 return brokerSummaries, warnings, nil 96 } 97 98 func (c *ServiceBrokerSummaryCompositeActor) ensureOrgExists(organizationName string) (v2action.Warnings, error) { 99 organizationExists, warnings, err := c.OrgActor.OrganizationExistsWithName(organizationName) 100 if err != nil { 101 return warnings, err 102 } 103 104 if !organizationExists { 105 return warnings, actionerror.OrganizationNotFoundError{Name: organizationName} 106 } 107 108 return warnings, nil 109 } 110 111 func (c *ServiceBrokerSummaryCompositeActor) ensureServiceExists(serviceName string) (v2action.Warnings, error) { 112 serviceExists, warnings, err := c.ServiceActor.ServiceExistsWithName(serviceName) 113 if err != nil { 114 return warnings, err 115 } 116 117 if !serviceExists { 118 return warnings, actionerror.ServiceNotFoundError{Name: serviceName} 119 } 120 121 return warnings, nil 122 } 123 124 func (c *ServiceBrokerSummaryCompositeActor) getServiceBrokers(brokerName string) ([]v2action.ServiceBroker, v2action.Warnings, error) { 125 if brokerName != "" { 126 broker, brokerWarnings, err := c.BrokerActor.GetServiceBrokerByName(brokerName) 127 return []v2action.ServiceBroker{broker}, brokerWarnings, err 128 } 129 return c.BrokerActor.GetServiceBrokers() 130 } 131 132 func (c *ServiceBrokerSummaryCompositeActor) fetchBrokerSummaries(brokers []v2action.ServiceBroker, serviceName, organizationName string) ([]v2action.ServiceBrokerSummary, v2action.Warnings, error) { 133 var ( 134 brokerSummaries []v2action.ServiceBrokerSummary 135 warnings v2action.Warnings 136 ) 137 138 for _, broker := range brokers { 139 brokerSummary, brokerWarnings, err := c.fetchBrokerSummary(v2action.ServiceBroker(broker), serviceName, organizationName) 140 warnings = append(warnings, brokerWarnings...) 141 if err != nil { 142 return nil, warnings, err 143 } 144 brokerSummaries = append(brokerSummaries, brokerSummary) 145 } 146 147 return brokerSummaries, warnings, nil 148 } 149 150 func (c *ServiceBrokerSummaryCompositeActor) fetchBrokerSummary(broker v2action.ServiceBroker, serviceName, organizationName string) (v2action.ServiceBrokerSummary, v2action.Warnings, error) { 151 filters := []v2action.Filter{filterByBrokerGUID(broker.GUID)} 152 if serviceName != "" { 153 filters = append(filters, filterByServiceName(serviceName)) 154 } 155 156 servicesWithPlans, warnings, err := c.ServiceActor.GetServicesWithPlans(filters...) 157 if err != nil { 158 return v2action.ServiceBrokerSummary{}, warnings, err 159 } 160 161 var services []v2action.ServiceSummary 162 for service, servicePlans := range servicesWithPlans { 163 serviceSummary, serviceWarnings, err := c.fetchServiceSummary(service, servicePlans, organizationName) 164 warnings = append(warnings, serviceWarnings...) 165 if err != nil { 166 return v2action.ServiceBrokerSummary{}, warnings, err 167 } 168 services = append(services, serviceSummary) 169 } 170 171 return v2action.ServiceBrokerSummary{ 172 ServiceBroker: v2action.ServiceBroker(broker), 173 Services: services, 174 }, warnings, nil 175 } 176 177 func (c *ServiceBrokerSummaryCompositeActor) fetchServiceSummary(service v2action.Service, servicePlans []v2action.ServicePlan, organizationName string) (v2action.ServiceSummary, v2action.Warnings, error) { 178 var warnings v2action.Warnings 179 var servicePlanSummaries []v2action.ServicePlanSummary 180 for _, plan := range servicePlans { 181 var visibleTo []string 182 if !plan.Public { 183 serviceVisibilities, visibilityWarnings, visErr := c.VisibilityActor.GetServicePlanVisibilities(plan.GUID) 184 warnings = append(warnings, visibilityWarnings...) 185 if visErr != nil { 186 return v2action.ServiceSummary{}, v2action.Warnings(warnings), visErr 187 } 188 189 for _, serviceVisibility := range serviceVisibilities { 190 org, orgWarnings, orgsErr := c.OrgActor.GetOrganization(serviceVisibility.OrganizationGUID) 191 warnings = append(warnings, orgWarnings...) 192 if orgsErr != nil { 193 return v2action.ServiceSummary{}, v2action.Warnings(warnings), orgsErr 194 } 195 196 visibleTo = append(visibleTo, org.Name) 197 } 198 } 199 200 if isPlanVisibleToOrg(organizationName, visibleTo, plan.Public) { 201 servicePlanSummaries = append(servicePlanSummaries, 202 v2action.ServicePlanSummary{ 203 ServicePlan: v2action.ServicePlan(plan), 204 VisibleTo: visibleTo, 205 }) 206 } 207 } 208 209 return v2action.ServiceSummary{ 210 Service: v2action.Service(service), 211 Plans: servicePlanSummaries, 212 }, v2action.Warnings(warnings), nil 213 } 214 215 func isPlanVisibleToOrg(organizationName string, visibleTo []string, isPlanPublic bool) bool { 216 if organizationName == "" || isPlanPublic { 217 return true 218 } 219 220 for _, visibleOrgName := range visibleTo { 221 if visibleOrgName == organizationName { 222 return true 223 } 224 } 225 return false 226 } 227 228 func pruneEmptyLeaves(brokerSummaries []v2action.ServiceBrokerSummary) []v2action.ServiceBrokerSummary { 229 filteredBrokerSummaries := []v2action.ServiceBrokerSummary{} 230 231 for _, brokerSummary := range brokerSummaries { 232 filteredServiceSummaries := []v2action.ServiceSummary{} 233 for _, serviceSummary := range brokerSummary.Services { 234 if len(serviceSummary.Plans) != 0 { 235 filteredServiceSummaries = append(filteredServiceSummaries, serviceSummary) 236 } 237 } 238 239 if len(filteredServiceSummaries) != 0 { 240 filteredBrokerSummaries = append(filteredBrokerSummaries, brokerSummary) 241 } 242 } 243 244 return filteredBrokerSummaries 245 } 246 247 func filterByServiceName(serviceName string) v2action.Filter { 248 return v2action.Filter{ 249 Type: constant.LabelFilter, 250 Operator: constant.EqualOperator, 251 Values: []string{serviceName}, 252 } 253 } 254 func filterByBrokerGUID(brokerGUID string) v2action.Filter { 255 return v2action.Filter{ 256 Type: constant.ServiceBrokerGUIDFilter, 257 Operator: constant.EqualOperator, 258 Values: []string{brokerGUID}, 259 } 260 }