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

     1  package provisioning
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/kyma-project/kyma-environment-broker/internal"
    10  	"github.com/kyma-project/kyma-environment-broker/internal/broker"
    11  	"github.com/kyma-project/kyma-environment-broker/internal/edp"
    12  	kebError "github.com/kyma-project/kyma-environment-broker/internal/error"
    13  	"github.com/kyma-project/kyma-environment-broker/internal/process"
    14  	"github.com/kyma-project/kyma-environment-broker/internal/storage"
    15  
    16  	"github.com/sirupsen/logrus"
    17  )
    18  
    19  //go:generate mockery --name=EDPClient --output=automock --outpkg=automock --case=underscore
    20  type EDPClient interface {
    21  	CreateDataTenant(data edp.DataTenantPayload) error
    22  	CreateMetadataTenant(name, env string, data edp.MetadataTenantPayload) error
    23  
    24  	DeleteDataTenant(name, env string) error
    25  	DeleteMetadataTenant(name, env, key string) error
    26  }
    27  
    28  type EDPRegistrationStep struct {
    29  	operationManager *process.OperationManager
    30  	client           EDPClient
    31  	config           edp.Config
    32  }
    33  
    34  func NewEDPRegistrationStep(os storage.Operations, client EDPClient, config edp.Config) *EDPRegistrationStep {
    35  	return &EDPRegistrationStep{
    36  		operationManager: process.NewOperationManager(os),
    37  		client:           client,
    38  		config:           config,
    39  	}
    40  }
    41  
    42  func (s *EDPRegistrationStep) Name() string {
    43  	return "EDP_Registration"
    44  }
    45  
    46  func (s *EDPRegistrationStep) Run(operation internal.Operation, log logrus.FieldLogger) (internal.Operation, time.Duration, error) {
    47  	if operation.EDPCreated {
    48  		return operation, 0, nil
    49  	}
    50  	subAccountID := strings.ToLower(operation.ProvisioningParameters.ErsContext.SubAccountID)
    51  
    52  	log.Infof("Create DataTenant for %s subaccount (env=%s)", subAccountID, s.config.Environment)
    53  	err := s.client.CreateDataTenant(edp.DataTenantPayload{
    54  		Name:        subAccountID,
    55  		Environment: s.config.Environment,
    56  		Secret:      s.generateSecret(subAccountID, s.config.Environment),
    57  	})
    58  	if err != nil {
    59  		if edp.IsConflictError(err) {
    60  			log.Warnf("Data Tenant already exists, deleting")
    61  			return s.handleConflict(operation, log)
    62  		}
    63  		return s.handleError(operation, err, log, "cannot create DataTenant")
    64  	}
    65  
    66  	log.Infof("Create DataTenant metadata for %s subaccount", subAccountID)
    67  	for key, value := range map[string]string{
    68  		edp.MaasConsumerEnvironmentKey: s.selectEnvironmentKey(operation.ProvisioningParameters.PlatformRegion, log),
    69  		edp.MaasConsumerRegionKey:      operation.ProvisioningParameters.PlatformRegion,
    70  		edp.MaasConsumerSubAccountKey:  subAccountID,
    71  		edp.MaasConsumerServicePlan:    s.selectServicePlan(operation.ProvisioningParameters.PlanID),
    72  	} {
    73  		payload := edp.MetadataTenantPayload{
    74  			Key:   key,
    75  			Value: value,
    76  		}
    77  		log.Infof("Sending metadata %s: %s", payload.Key, payload.Value)
    78  		err = s.client.CreateMetadataTenant(subAccountID, s.config.Environment, payload)
    79  		if err != nil {
    80  			if edp.IsConflictError(err) {
    81  				log.Warnf("Metadata already exists, deleting")
    82  				return s.handleConflict(operation, log)
    83  			}
    84  			return s.handleError(operation, err, log, fmt.Sprintf("cannot create DataTenant metadata %s", key))
    85  		}
    86  	}
    87  
    88  	newOp, repeat, _ := s.operationManager.UpdateOperation(operation, func(op *internal.Operation) {
    89  		op.EDPCreated = true
    90  	}, log)
    91  	if repeat != 0 {
    92  		log.Errorf("cannot save operation")
    93  		return newOp, 5 * time.Second, nil
    94  	}
    95  
    96  	return newOp, 0, nil
    97  }
    98  
    99  func (s *EDPRegistrationStep) handleError(operation internal.Operation, err error, log logrus.FieldLogger, msg string) (internal.Operation, time.Duration, error) {
   100  	log.Errorf("%s: %s", msg, err)
   101  
   102  	if kebError.IsTemporaryError(err) {
   103  		since := time.Since(operation.UpdatedAt)
   104  		if since < time.Minute*30 {
   105  			log.Errorf("request to EDP failed: %s. Retry...", err)
   106  			return operation, 10 * time.Second, nil
   107  		}
   108  	}
   109  
   110  	if !s.config.Required {
   111  		log.Errorf("Step %s failed. Step is not required. Skip step.", s.Name())
   112  		return operation, 0, nil
   113  	}
   114  
   115  	return s.operationManager.OperationFailed(operation, msg, err, log)
   116  }
   117  
   118  func (s *EDPRegistrationStep) selectEnvironmentKey(region string, log logrus.FieldLogger) string {
   119  	parts := strings.Split(region, "-")
   120  	switch parts[0] {
   121  	case "cf":
   122  		return "CF"
   123  	case "k8s":
   124  		return "KUBERNETES"
   125  	case "neo":
   126  		return "NEO"
   127  	default:
   128  		log.Warnf("region %s does not fit any of the options, default CF is used", region)
   129  		return "CF"
   130  	}
   131  }
   132  
   133  func (s *EDPRegistrationStep) selectServicePlan(planID string) string {
   134  	switch planID {
   135  	case broker.FreemiumPlanID:
   136  		return "free"
   137  	case broker.AzureLitePlanID:
   138  		return "tdd"
   139  	default:
   140  		return "standard"
   141  	}
   142  }
   143  
   144  // generateSecret generates secret during dataTenant creation, at this moment the secret is not needed
   145  // except required parameter
   146  func (s *EDPRegistrationStep) generateSecret(name, env string) string {
   147  	return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s%s", name, env)))
   148  }
   149  
   150  func (s *EDPRegistrationStep) handleConflict(operation internal.Operation, log logrus.FieldLogger) (internal.Operation, time.Duration, error) {
   151  	for _, key := range []string{
   152  		edp.MaasConsumerEnvironmentKey,
   153  		edp.MaasConsumerRegionKey,
   154  		edp.MaasConsumerSubAccountKey,
   155  		edp.MaasConsumerServicePlan,
   156  	} {
   157  		log.Infof("Deleting DataTenant metadata %s (%s): %s", operation.SubAccountID, s.config.Environment, key)
   158  		err := s.client.DeleteMetadataTenant(operation.SubAccountID, s.config.Environment, key)
   159  		if err != nil {
   160  			return s.handleError(operation, err, log, fmt.Sprintf("cannot remove DataTenant metadata with key: %s", key))
   161  		}
   162  	}
   163  
   164  	log.Infof("Deleting DataTenant %s (%s)", operation.SubAccountID, s.config.Environment)
   165  	err := s.client.DeleteDataTenant(operation.SubAccountID, s.config.Environment)
   166  	if err != nil {
   167  		return s.handleError(operation, err, log, "cannot remove DataTenant")
   168  	}
   169  
   170  	log.Infof("Retrying...")
   171  	return operation, time.Second, nil
   172  }