github.com/cloudfoundry/cli@v7.1.0+incompatible/cf/actors/services_plans.go (about)

     1  package actors
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"code.cloudfoundry.org/cli/cf/api/organizations"
     7  
     8  	"code.cloudfoundry.org/cli/cf/actors/planbuilder"
     9  	"code.cloudfoundry.org/cli/cf/actors/servicebuilder"
    10  	"code.cloudfoundry.org/cli/cf/api"
    11  	"code.cloudfoundry.org/cli/cf/models"
    12  )
    13  
    14  //go:generate counterfeiter . ServicePlanActor
    15  
    16  type ServicePlanActor interface {
    17  	FindServiceAccess(string, string) (ServiceAccess, error)
    18  	UpdateAllPlansForService(string, bool) error
    19  	UpdateOrgForService(string, string, bool) error
    20  	UpdateSinglePlanForService(string, string, bool) error
    21  	UpdatePlanAndOrgForService(string, string, string, bool) error
    22  }
    23  
    24  type ServiceAccess int
    25  
    26  const (
    27  	ServiceAccessError ServiceAccess = iota
    28  	AllPlansArePublic
    29  	AllPlansArePrivate
    30  	AllPlansAreLimited
    31  	SomePlansArePublicSomeAreLimited
    32  	SomePlansArePublicSomeArePrivate
    33  	SomePlansAreLimitedSomeArePrivate
    34  	SomePlansArePublicSomeAreLimitedSomeArePrivate
    35  )
    36  
    37  type ServicePlanHandler struct {
    38  	servicePlanRepo           api.ServicePlanRepository
    39  	servicePlanVisibilityRepo api.ServicePlanVisibilityRepository
    40  	orgRepo                   organizations.OrganizationRepository
    41  	serviceBuilder            servicebuilder.ServiceBuilder
    42  	planBuilder               planbuilder.PlanBuilder
    43  }
    44  
    45  func NewServicePlanHandler(plan api.ServicePlanRepository, vis api.ServicePlanVisibilityRepository, org organizations.OrganizationRepository, planBuilder planbuilder.PlanBuilder, serviceBuilder servicebuilder.ServiceBuilder) ServicePlanHandler {
    46  	return ServicePlanHandler{
    47  		servicePlanRepo:           plan,
    48  		servicePlanVisibilityRepo: vis,
    49  		orgRepo:                   org,
    50  		serviceBuilder:            serviceBuilder,
    51  		planBuilder:               planBuilder,
    52  	}
    53  }
    54  
    55  func (actor ServicePlanHandler) UpdateAllPlansForService(serviceName string, setPlanVisibility bool) error {
    56  	service, err := actor.serviceBuilder.GetServiceByNameWithPlans(serviceName)
    57  	if err != nil {
    58  		return err
    59  	}
    60  
    61  	for _, plan := range service.Plans {
    62  		err = actor.updateSinglePlan(service, plan.Name, setPlanVisibility)
    63  		if err != nil {
    64  			return err
    65  		}
    66  	}
    67  	return nil
    68  }
    69  
    70  func (actor ServicePlanHandler) UpdateOrgForService(serviceName string, orgName string, setPlanVisibility bool) error {
    71  	service, err := actor.serviceBuilder.GetServiceByNameWithPlans(serviceName)
    72  	if err != nil {
    73  		return err
    74  	}
    75  
    76  	org, err := actor.orgRepo.FindByName(orgName)
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	for _, plan := range service.Plans {
    82  		switch {
    83  		case plan.Public:
    84  			continue
    85  		case setPlanVisibility:
    86  			err = actor.servicePlanVisibilityRepo.Create(plan.GUID, org.GUID)
    87  			if err != nil {
    88  				return err
    89  			}
    90  		case !setPlanVisibility:
    91  			err = actor.deleteServicePlanVisibilities(map[string]string{"organization_guid": org.GUID, "service_plan_guid": plan.GUID})
    92  			if err != nil {
    93  				return err
    94  			}
    95  		}
    96  	}
    97  
    98  	return nil
    99  }
   100  
   101  func (actor ServicePlanHandler) UpdatePlanAndOrgForService(serviceName, planName, orgName string, setPlanVisibility bool) error {
   102  	service, err := actor.serviceBuilder.GetServiceByNameWithPlans(serviceName)
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	org, err := actor.orgRepo.FindByName(orgName)
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	found := false
   113  	var servicePlan models.ServicePlanFields
   114  	for i, val := range service.Plans {
   115  		if val.Name == planName {
   116  			found = true
   117  			servicePlan = service.Plans[i]
   118  		}
   119  	}
   120  	if !found {
   121  		return fmt.Errorf("Service plan %s not found", planName)
   122  	}
   123  
   124  	switch {
   125  	case servicePlan.Public:
   126  		return nil
   127  	case setPlanVisibility:
   128  		// Enable service access
   129  		err = actor.servicePlanVisibilityRepo.Create(servicePlan.GUID, org.GUID)
   130  	case !setPlanVisibility:
   131  		// Disable service access
   132  		err = actor.deleteServicePlanVisibilities(map[string]string{"organization_guid": org.GUID, "service_plan_guid": servicePlan.GUID})
   133  	}
   134  
   135  	return err
   136  }
   137  
   138  func (actor ServicePlanHandler) UpdateSinglePlanForService(serviceName string, planName string, setPlanVisibility bool) error {
   139  	serviceOffering, err := actor.serviceBuilder.GetServiceByNameWithPlans(serviceName)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	return actor.updateSinglePlan(serviceOffering, planName, setPlanVisibility)
   144  }
   145  
   146  func (actor ServicePlanHandler) updateSinglePlan(serviceOffering models.ServiceOffering, planName string, setPlanVisibility bool) error {
   147  	var planToUpdate *models.ServicePlanFields
   148  
   149  	for _, servicePlan := range serviceOffering.Plans {
   150  		if servicePlan.Name == planName {
   151  			planToUpdate = &servicePlan
   152  			break
   153  		}
   154  	}
   155  
   156  	if planToUpdate == nil {
   157  		return fmt.Errorf("The plan %s could not be found for service %s", planName, serviceOffering.Label)
   158  	}
   159  
   160  	return actor.updateServicePlanAvailability(serviceOffering.GUID, *planToUpdate, setPlanVisibility)
   161  }
   162  
   163  func (actor ServicePlanHandler) deleteServicePlanVisibilities(queryParams map[string]string) error {
   164  	visibilities, err := actor.servicePlanVisibilityRepo.Search(queryParams)
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	for _, visibility := range visibilities {
   170  		err = actor.servicePlanVisibilityRepo.Delete(visibility.GUID)
   171  		if err != nil {
   172  			return err
   173  		}
   174  	}
   175  
   176  	return nil
   177  }
   178  
   179  func (actor ServicePlanHandler) updateServicePlanAvailability(serviceGUID string, servicePlan models.ServicePlanFields, setPlanVisibility bool) error {
   180  	// We delete all service plan visibilities for the given Plan since the attribute public should function as a giant on/off
   181  	// switch for all orgs. Thus we need to clean up any visibilities laying around so that they don't carry over.
   182  	err := actor.deleteServicePlanVisibilities(map[string]string{"service_plan_guid": servicePlan.GUID})
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	if servicePlan.Public == setPlanVisibility {
   188  		return nil
   189  	}
   190  
   191  	return actor.servicePlanRepo.Update(servicePlan, serviceGUID, setPlanVisibility)
   192  }
   193  
   194  func (actor ServicePlanHandler) FindServiceAccess(serviceName string, orgName string) (ServiceAccess, error) {
   195  	service, err := actor.serviceBuilder.GetServiceByNameForOrg(serviceName, orgName)
   196  	if err != nil {
   197  		return ServiceAccessError, err
   198  	}
   199  
   200  	publicBucket, limitedBucket, privateBucket := 0, 0, 0
   201  
   202  	for _, plan := range service.Plans {
   203  		if plan.Public {
   204  			publicBucket++
   205  		} else if len(plan.OrgNames) > 0 {
   206  			limitedBucket++
   207  		} else {
   208  			privateBucket++
   209  		}
   210  	}
   211  
   212  	if publicBucket > 0 && limitedBucket == 0 && privateBucket == 0 {
   213  		return AllPlansArePublic, nil
   214  	}
   215  	if publicBucket > 0 && limitedBucket > 0 && privateBucket == 0 {
   216  		return SomePlansArePublicSomeAreLimited, nil
   217  	}
   218  	if publicBucket > 0 && privateBucket > 0 && limitedBucket == 0 {
   219  		return SomePlansArePublicSomeArePrivate, nil
   220  	}
   221  
   222  	if limitedBucket > 0 && publicBucket == 0 && privateBucket == 0 {
   223  		return AllPlansAreLimited, nil
   224  	}
   225  	if privateBucket > 0 && publicBucket == 0 && privateBucket == 0 {
   226  		return AllPlansArePrivate, nil
   227  	}
   228  	if limitedBucket > 0 && privateBucket > 0 && publicBucket == 0 {
   229  		return SomePlansAreLimitedSomeArePrivate, nil
   230  	}
   231  	return SomePlansArePublicSomeAreLimitedSomeArePrivate, nil
   232  }
   233  
   234  type PlanAccess int
   235  
   236  const (
   237  	PlanAccessError PlanAccess = iota
   238  	All
   239  	Limited
   240  	None
   241  )
   242  
   243  func (actor ServicePlanHandler) findPlanAccess(plan models.ServicePlanFields) PlanAccess {
   244  	if plan.Public {
   245  		return All
   246  	} else if len(plan.OrgNames) > 0 {
   247  		return Limited
   248  	} else {
   249  		return None
   250  	}
   251  }