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  }