github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/broker/instance_deprovision.go (about)

     1  package broker
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/kyma-project/kyma-environment-broker/internal"
     9  
    10  	"github.com/google/uuid"
    11  	"github.com/kyma-project/kyma-environment-broker/internal/storage"
    12  
    13  	"github.com/kyma-project/kyma-environment-broker/internal/storage/dberr"
    14  	"github.com/pivotal-cf/brokerapi/v8/domain"
    15  	"github.com/pivotal-cf/brokerapi/v8/domain/apiresponses"
    16  	"github.com/sirupsen/logrus"
    17  )
    18  
    19  type DeprovisionEndpoint struct {
    20  	log logrus.FieldLogger
    21  
    22  	instancesStorage  storage.Instances
    23  	operationsStorage storage.Deprovisioning
    24  
    25  	queue Queue
    26  }
    27  
    28  func NewDeprovision(instancesStorage storage.Instances, operationsStorage storage.Operations, q Queue, log logrus.FieldLogger) *DeprovisionEndpoint {
    29  	return &DeprovisionEndpoint{
    30  		log:               log.WithField("service", "DeprovisionEndpoint"),
    31  		instancesStorage:  instancesStorage,
    32  		operationsStorage: operationsStorage,
    33  
    34  		queue: q,
    35  	}
    36  }
    37  
    38  // Deprovision deletes an existing service instance
    39  //
    40  //	DELETE /v2/service_instances/{instance_id}
    41  func (b *DeprovisionEndpoint) Deprovision(ctx context.Context, instanceID string, details domain.DeprovisionDetails, asyncAllowed bool) (domain.DeprovisionServiceSpec, error) {
    42  	logger := b.log.WithFields(logrus.Fields{"instanceID": instanceID})
    43  	logger.Infof("Deprovisioning triggered, details: %+v", details)
    44  
    45  	instance, err := b.instancesStorage.GetByID(instanceID)
    46  	switch {
    47  	case err == nil:
    48  	case dberr.IsNotFound(err):
    49  		logger.Warn("instance does not exist")
    50  		return domain.DeprovisionServiceSpec{
    51  			IsAsync: false,
    52  		}, nil
    53  	default:
    54  		logger.Errorf("unable to get instance from a storage: %s", err)
    55  		return domain.DeprovisionServiceSpec{}, apiresponses.NewFailureResponse(fmt.Errorf("unable to get instance from the storage"), http.StatusInternalServerError, fmt.Sprintf("could not deprovision runtime, instanceID %s", instanceID))
    56  	}
    57  
    58  	logger = logger.WithFields(logrus.Fields{"runtimeID": instance.RuntimeID, "globalAccountID": instance.GlobalAccountID, "planID": instance.ServicePlanID})
    59  
    60  	// check if operation with the same instance ID is already created
    61  	existingOperation, errStorage := b.operationsStorage.GetDeprovisioningOperationByInstanceID(instanceID)
    62  	if errStorage != nil && !dberr.IsNotFound(errStorage) {
    63  		logger.Errorf("cannot get existing operation from storage %s", errStorage)
    64  		return domain.DeprovisionServiceSpec{}, fmt.Errorf("cannot get existing operation from storage")
    65  	}
    66  
    67  	// temporary deprovisioning means suspension
    68  	previousOperationIsNotTemporary := existingOperation != nil && !existingOperation.Temporary
    69  	if previousOperationIsNotTemporary {
    70  		switch {
    71  		// there is an ongoing operation
    72  		case existingOperation.State != domain.Failed && existingOperation.State != domain.Succeeded:
    73  			logger.Info("deprovision operation already ongoing - not creating a new operation")
    74  			return domain.DeprovisionServiceSpec{
    75  				IsAsync:       true,
    76  				OperationData: existingOperation.ID,
    77  			}, nil
    78  		case existingOperation.State == domain.Succeeded && len(existingOperation.ExcutedButNotCompleted) == 0:
    79  			logger.Info("no steps to retry - not creating a new operation")
    80  			return domain.DeprovisionServiceSpec{
    81  				IsAsync:       true,
    82  				OperationData: existingOperation.ID,
    83  			}, nil
    84  		}
    85  	}
    86  
    87  	// create and save new operation
    88  	operationID := uuid.New().String()
    89  	logger = logger.WithField("operationID", operationID)
    90  	operation, err := internal.NewDeprovisioningOperationWithID(operationID, instance)
    91  	if err != nil {
    92  		logger.Errorf("cannot create new operation: %s", err)
    93  		return domain.DeprovisionServiceSpec{}, fmt.Errorf("cannot create new operation")
    94  	}
    95  	if v := ctx.Value("User-Agent"); v != nil {
    96  		operation.UserAgent = v.(string)
    97  	}
    98  	err = b.operationsStorage.InsertDeprovisioningOperation(operation)
    99  	if err != nil {
   100  		logger.Errorf("cannot save operation: %s", err)
   101  		return domain.DeprovisionServiceSpec{}, fmt.Errorf("cannot save operation")
   102  	}
   103  
   104  	logger.Info("Adding operation to deprovisioning queue")
   105  	b.queue.Add(operationID)
   106  
   107  	return domain.DeprovisionServiceSpec{
   108  		IsAsync:       true,
   109  		OperationData: operationID,
   110  	}, nil
   111  }