github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+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 }