github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/actor/v7action/service_instance.go (about) 1 package v7action 2 3 import ( 4 "code.cloudfoundry.org/cli/actor/actionerror" 5 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 6 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 8 "code.cloudfoundry.org/cli/resources" 9 "code.cloudfoundry.org/cli/types" 10 "code.cloudfoundry.org/cli/util/railway" 11 ) 12 13 type UpdateManagedServiceInstanceParams struct { 14 ServiceInstanceName string 15 ServicePlanName string 16 SpaceGUID string 17 Tags types.OptionalStringSlice 18 Parameters types.OptionalObject 19 } 20 21 type CreateManagedServiceInstanceParams struct { 22 ServiceOfferingName string 23 ServicePlanName string 24 ServiceInstanceName string 25 ServiceBrokerName string 26 SpaceGUID string 27 Tags types.OptionalStringSlice 28 Parameters types.OptionalObject 29 } 30 31 func (actor Actor) GetServiceInstanceByNameAndSpace(serviceInstanceName string, spaceGUID string) (resources.ServiceInstance, Warnings, error) { 32 serviceInstance, _, warnings, err := actor.getServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID) 33 return serviceInstance, Warnings(warnings), err 34 } 35 36 func (actor Actor) CreateUserProvidedServiceInstance(serviceInstance resources.ServiceInstance) (Warnings, error) { 37 serviceInstance.Type = resources.UserProvidedServiceInstance 38 _, warnings, err := actor.CloudControllerClient.CreateServiceInstance(serviceInstance) 39 return Warnings(warnings), err 40 } 41 42 func (actor Actor) UpdateUserProvidedServiceInstance(serviceInstanceName, spaceGUID string, serviceInstanceUpdates resources.ServiceInstance) (Warnings, error) { 43 var original resources.ServiceInstance 44 45 warnings, err := railway.Sequentially( 46 func() (warnings ccv3.Warnings, err error) { 47 original, _, warnings, err = actor.CloudControllerClient.GetServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID) 48 return 49 }, 50 func() (warnings ccv3.Warnings, err error) { 51 err = assertServiceInstanceType(resources.UserProvidedServiceInstance, original) 52 return 53 }, 54 func() (warnings ccv3.Warnings, err error) { 55 _, warnings, err = actor.CloudControllerClient.UpdateServiceInstance(original.GUID, serviceInstanceUpdates) 56 return 57 }, 58 ) 59 60 return Warnings(warnings), err 61 } 62 63 func (actor Actor) CreateManagedServiceInstance(params CreateManagedServiceInstanceParams) (chan PollJobEvent, Warnings, error) { 64 var ( 65 servicePlan resources.ServicePlan 66 jobURL ccv3.JobURL 67 ) 68 69 warnings, err := railway.Sequentially( 70 func() (warnings ccv3.Warnings, err error) { 71 var v7Warnings Warnings 72 servicePlan, v7Warnings, err = actor.GetServicePlanByNameOfferingAndBroker( 73 params.ServicePlanName, 74 params.ServiceOfferingName, 75 params.ServiceBrokerName, 76 ) 77 return ccv3.Warnings(v7Warnings), err 78 }, 79 func() (warnings ccv3.Warnings, err error) { 80 serviceInstance := resources.ServiceInstance{ 81 Type: resources.ManagedServiceInstance, 82 Name: params.ServiceInstanceName, 83 ServicePlanGUID: servicePlan.GUID, 84 SpaceGUID: params.SpaceGUID, 85 Tags: params.Tags, 86 Parameters: params.Parameters, 87 } 88 89 jobURL, warnings, err = actor.CloudControllerClient.CreateServiceInstance(serviceInstance) 90 return 91 }, 92 ) 93 switch e := err.(type) { 94 case nil: 95 return actor.PollJobToEventStream(jobURL), Warnings(warnings), nil 96 case actionerror.DuplicateServicePlanError: 97 return nil, Warnings(warnings), actionerror.ServiceBrokerNameRequiredError{ 98 ServiceOfferingName: e.ServiceOfferingName, 99 } 100 default: 101 return nil, Warnings(warnings), err 102 } 103 } 104 105 func (actor Actor) UpdateManagedServiceInstance(params UpdateManagedServiceInstanceParams) (chan PollJobEvent, Warnings, error) { 106 var ( 107 serviceInstance resources.ServiceInstance 108 serviceOffering resources.ServiceOffering 109 serviceBroker resources.ServiceBroker 110 newPlanGUID string 111 jobURL ccv3.JobURL 112 stream chan PollJobEvent 113 ) 114 115 planChangeRequested := params.ServicePlanName != "" 116 117 warnings, err := railway.Sequentially( 118 func() (warnings ccv3.Warnings, err error) { 119 serviceInstance, serviceOffering, serviceBroker, warnings, err = actor.getServiceInstanceForUpdate( 120 params.ServiceInstanceName, 121 params.SpaceGUID, 122 planChangeRequested, 123 ) 124 return 125 }, 126 func() (warnings ccv3.Warnings, err error) { 127 err = assertServiceInstanceType(resources.ManagedServiceInstance, serviceInstance) 128 return 129 }, 130 func() (warnings ccv3.Warnings, err error) { 131 if planChangeRequested { 132 newPlanGUID, warnings, err = actor.getPlanForInstanceUpdate(params.ServicePlanName, serviceOffering, serviceBroker) 133 } 134 return 135 }, 136 func() (warnings ccv3.Warnings, err error) { 137 jobURL, warnings, err = actor.updateManagedServiceInstance(serviceInstance, newPlanGUID, params) 138 return 139 }, 140 func() (warnings ccv3.Warnings, err error) { 141 stream = actor.PollJobToEventStream(jobURL) 142 return 143 }, 144 ) 145 146 return stream, Warnings(warnings), err 147 } 148 149 func (actor Actor) UpgradeManagedServiceInstance(serviceInstanceName string, spaceGUID string) (chan PollJobEvent, Warnings, error) { 150 var ( 151 serviceInstance resources.ServiceInstance 152 servicePlan resources.ServicePlan 153 jobURL ccv3.JobURL 154 stream chan PollJobEvent 155 ) 156 157 warnings, err := railway.Sequentially( 158 func() (warnings ccv3.Warnings, err error) { 159 serviceInstance, _, warnings, err = actor.getServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID) 160 return 161 }, 162 func() (warnings ccv3.Warnings, err error) { 163 if serviceInstance.UpgradeAvailable.Value != true { 164 err = actionerror.ServiceInstanceUpgradeNotAvailableError{} 165 } 166 return 167 }, 168 func() (warnings ccv3.Warnings, err error) { 169 servicePlan, warnings, err = actor.CloudControllerClient.GetServicePlanByGUID(serviceInstance.ServicePlanGUID) 170 return 171 }, 172 func() (warnings ccv3.Warnings, err error) { 173 jobURL, warnings, err = actor.CloudControllerClient.UpdateServiceInstance(serviceInstance.GUID, resources.ServiceInstance{ 174 MaintenanceInfoVersion: servicePlan.MaintenanceInfoVersion, 175 }) 176 return 177 }, 178 func() (warnings ccv3.Warnings, err error) { 179 stream = actor.PollJobToEventStream(jobURL) 180 return 181 }, 182 ) 183 184 return stream, Warnings(warnings), err 185 } 186 187 func (actor Actor) RenameServiceInstance(currentServiceInstanceName, spaceGUID, newServiceInstanceName string) (Warnings, error) { 188 var ( 189 serviceInstance resources.ServiceInstance 190 jobURL ccv3.JobURL 191 ) 192 193 warnings, err := railway.Sequentially( 194 func() (warnings ccv3.Warnings, err error) { 195 serviceInstance, _, warnings, err = actor.getServiceInstanceByNameAndSpace(currentServiceInstanceName, spaceGUID) 196 return 197 }, 198 func() (warnings ccv3.Warnings, err error) { 199 jobURL, warnings, err = actor.CloudControllerClient.UpdateServiceInstance( 200 serviceInstance.GUID, 201 resources.ServiceInstance{Name: newServiceInstanceName}, 202 ) 203 return 204 }, 205 func() (warnings ccv3.Warnings, err error) { 206 return actor.CloudControllerClient.PollJobForState(jobURL, constant.JobPolling) 207 }, 208 ) 209 210 return Warnings(warnings), err 211 } 212 213 func (actor Actor) DeleteServiceInstance(serviceInstanceName, spaceGUID string) (chan PollJobEvent, Warnings, error) { 214 var ( 215 serviceInstance resources.ServiceInstance 216 jobURL ccv3.JobURL 217 ) 218 219 warnings, err := railway.Sequentially( 220 func() (warnings ccv3.Warnings, err error) { 221 serviceInstance, _, warnings, err = actor.CloudControllerClient.GetServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID) 222 return 223 }, 224 func() (warnings ccv3.Warnings, err error) { 225 jobURL, warnings, err = actor.CloudControllerClient.DeleteServiceInstance(serviceInstance.GUID) 226 return 227 }, 228 ) 229 230 switch err.(type) { 231 case nil: 232 case ccerror.ServiceInstanceNotFoundError: 233 return nil, Warnings(warnings), actionerror.ServiceInstanceNotFoundError{Name: serviceInstanceName} 234 default: 235 return nil, Warnings(warnings), err 236 } 237 238 switch jobURL { 239 case "": 240 return nil, Warnings(warnings), nil 241 default: 242 return actor.PollJobToEventStream(jobURL), Warnings(warnings), nil 243 } 244 } 245 246 func (actor Actor) PurgeServiceInstance(serviceInstanceName, spaceGUID string) (Warnings, error) { 247 var serviceInstance resources.ServiceInstance 248 249 warnings, err := railway.Sequentially( 250 func() (warnings ccv3.Warnings, err error) { 251 serviceInstance, _, warnings, err = actor.CloudControllerClient.GetServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID) 252 return 253 }, 254 func() (warnings ccv3.Warnings, err error) { 255 _, warnings, err = actor.CloudControllerClient.DeleteServiceInstance( 256 serviceInstance.GUID, 257 ccv3.Query{Key: ccv3.Purge, Values: []string{"true"}}, 258 ) 259 return 260 }, 261 ) 262 263 switch err.(type) { 264 case nil: 265 return Warnings(warnings), nil 266 case ccerror.ServiceInstanceNotFoundError: 267 return Warnings(warnings), actionerror.ServiceInstanceNotFoundError{Name: serviceInstanceName} 268 default: 269 return Warnings(warnings), err 270 } 271 } 272 273 func (actor Actor) pollJob(jobURL ccv3.JobURL, wait bool) (ccv3.Warnings, error) { 274 switch { 275 case jobURL == "": 276 return ccv3.Warnings{}, nil 277 case wait: 278 return actor.CloudControllerClient.PollJob(jobURL) 279 default: 280 return actor.CloudControllerClient.PollJobForState(jobURL, constant.JobPolling) 281 } 282 } 283 284 func (actor Actor) getServiceInstanceByNameAndSpace(serviceInstanceName string, spaceGUID string, query ...ccv3.Query) (resources.ServiceInstance, ccv3.IncludedResources, ccv3.Warnings, error) { 285 serviceInstance, includedResources, warnings, err := actor.CloudControllerClient.GetServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID, query...) 286 switch e := err.(type) { 287 case ccerror.ServiceInstanceNotFoundError: 288 return serviceInstance, ccv3.IncludedResources{}, warnings, actionerror.ServiceInstanceNotFoundError{Name: e.Name} 289 default: 290 return serviceInstance, includedResources, warnings, err 291 } 292 } 293 294 func (actor Actor) getServiceInstanceForUpdate(serviceInstanceName string, spaceGUID string, includePlan bool) (resources.ServiceInstance, resources.ServiceOffering, resources.ServiceBroker, ccv3.Warnings, error) { 295 var query []ccv3.Query 296 if includePlan { 297 query = append( 298 query, 299 ccv3.Query{Key: ccv3.FieldsServicePlanServiceOffering, Values: []string{"name", "guid"}}, 300 ccv3.Query{Key: ccv3.FieldsServicePlanServiceOfferingServiceBroker, Values: []string{"name"}}, 301 ) 302 } 303 304 serviceInstance, includedResources, warnings, err := actor.getServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID, query...) 305 306 var ( 307 serviceOffering resources.ServiceOffering 308 serviceBroker resources.ServiceBroker 309 ) 310 if len(includedResources.ServiceOfferings) != 0 { 311 serviceOffering = includedResources.ServiceOfferings[0] 312 } 313 if len(includedResources.ServiceBrokers) != 0 { 314 serviceBroker = includedResources.ServiceBrokers[0] 315 } 316 317 return serviceInstance, serviceOffering, serviceBroker, warnings, err 318 } 319 320 func (actor Actor) getPlanForInstanceUpdate(planName string, serviceOffering resources.ServiceOffering, serviceBroker resources.ServiceBroker) (string, ccv3.Warnings, error) { 321 plans, warnings, err := actor.CloudControllerClient.GetServicePlans([]ccv3.Query{ 322 {Key: ccv3.ServiceOfferingGUIDsFilter, Values: []string{serviceOffering.GUID}}, 323 {Key: ccv3.NameFilter, Values: []string{planName}}, 324 }...) 325 326 switch { 327 case err != nil: 328 return "", warnings, err 329 case len(plans) == 0: 330 return "", warnings, actionerror.ServicePlanNotFoundError{ 331 PlanName: planName, 332 OfferingName: serviceOffering.Name, 333 ServiceBrokerName: serviceBroker.Name, 334 } 335 default: 336 return plans[0].GUID, warnings, nil 337 } 338 } 339 340 func (actor Actor) updateManagedServiceInstance(serviceInstance resources.ServiceInstance, newServicePlanGUID string, params UpdateManagedServiceInstanceParams) (ccv3.JobURL, ccv3.Warnings, error) { 341 if newServicePlanGUID == serviceInstance.ServicePlanGUID { 342 newServicePlanGUID = "" 343 } 344 345 update := resources.ServiceInstance{ 346 ServicePlanGUID: newServicePlanGUID, 347 Tags: params.Tags, 348 Parameters: params.Parameters, 349 } 350 351 if update.ServicePlanGUID == "" && !update.Tags.IsSet && !update.Parameters.IsSet { 352 return "", nil, actionerror.ServiceInstanceUpdateIsNoop{} 353 } 354 355 return actor.CloudControllerClient.UpdateServiceInstance(serviceInstance.GUID, update) 356 } 357 358 func assertServiceInstanceType(requiredType resources.ServiceInstanceType, instance resources.ServiceInstance) error { 359 if instance.Type != requiredType { 360 return actionerror.ServiceInstanceTypeError{ 361 Name: instance.Name, 362 RequiredType: requiredType, 363 } 364 } 365 366 return nil 367 } 368 369 func handleServiceInstanceErrors(warnings ccv3.Warnings, err error) (Warnings, error) { 370 switch e := err.(type) { 371 case nil: 372 return Warnings(warnings), nil 373 case ccerror.ServiceInstanceNotFoundError: 374 return Warnings(warnings), actionerror.ServiceInstanceNotFoundError{Name: e.Name} 375 default: 376 return Warnings(warnings), err 377 } 378 }