github.com/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  }