github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/tenantfetchersvc/provisioner.go (about)

     1  package tenantfetchersvc
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/internal/model"
     9  	tenantEntity "github.com/kyma-incubator/compass/components/director/pkg/tenant"
    10  )
    11  
    12  const autogeneratedTenantProvider = "autogenerated"
    13  
    14  // DirectorGraphQLClient expects graphql implementation
    15  //
    16  //go:generate mockery --name=DirectorGraphQLClient --output=automock --outpkg=automock --case=underscore --disable-version-string
    17  type DirectorGraphQLClient interface {
    18  	WriteTenants(context.Context, []graphql.BusinessTenantMappingInput) error
    19  	DeleteTenants(ctx context.Context, tenants []graphql.BusinessTenantMappingInput) error
    20  	UpdateTenant(ctx context.Context, id string, tenant graphql.BusinessTenantMappingInput) error
    21  	SubscribeTenant(ctx context.Context, providerID, subaccountID, providerSubaccountID, consumerTenantID, region, subscriptionProviderAppName, subscriptionPayload string) error
    22  	UnsubscribeTenant(ctx context.Context, providerID, subaccountID, providerSubaccountID, consumerTenantID, region string) error
    23  }
    24  
    25  // TenantConverter expects tenant converter implementation
    26  //
    27  //go:generate mockery --name=TenantConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    28  type TenantConverter interface {
    29  	MultipleInputToGraphQLInput([]model.BusinessTenantMappingInput) []graphql.BusinessTenantMappingInput
    30  	ToGraphQLInput(model.BusinessTenantMappingInput) graphql.BusinessTenantMappingInput
    31  }
    32  
    33  // TenantSubscriptionRequest represents the information provided during tenant provisioning request in Compass, which includes tenant IDs, subdomain, and region of the tenant.
    34  // The tenant which triggered the provisioning request is only one, and one of the tenant IDs in the request is its external ID, where the other tenant IDs are external IDs from its parents hierarchy.
    35  type TenantSubscriptionRequest struct {
    36  	AccountTenantID             string
    37  	SubaccountTenantID          string
    38  	CustomerTenantID            string
    39  	Subdomain                   string
    40  	Region                      string
    41  	SubscriptionProviderID      string
    42  	SubscriptionLcenseType      string
    43  	ProviderSubaccountID        string
    44  	ConsumerTenantID            string
    45  	SubscriptionProviderAppName string
    46  	SubscriptionPayload         string
    47  }
    48  
    49  // MainTenantID is used to determine the external tenant ID of the tenant for which the provisioning request was triggered.
    50  func (r *TenantSubscriptionRequest) MainTenantID() string {
    51  	if len(r.SubaccountTenantID) > 0 {
    52  		return r.SubaccountTenantID
    53  	}
    54  
    55  	return r.AccountTenantID
    56  }
    57  
    58  type provisioner struct {
    59  	gqlClient      DirectorGraphQLClient
    60  	converter      TenantConverter
    61  	tenantProvider string
    62  }
    63  
    64  // NewTenantProvisioner returns a TenantProvisioner initialized with the provided TenantService, and tenant provider.
    65  // All tenants, created by the provisioner, besides the Customer ones, will have the value of tenantProvider as a provider.
    66  func NewTenantProvisioner(directorClient DirectorGraphQLClient, tenantConverter TenantConverter, tenantProvider string) *provisioner {
    67  	return &provisioner{
    68  		gqlClient:      directorClient,
    69  		converter:      tenantConverter,
    70  		tenantProvider: tenantProvider,
    71  	}
    72  }
    73  
    74  // ProvisionTenants provisions tenants according to their type
    75  func (p *provisioner) ProvisionTenants(ctx context.Context, request *TenantSubscriptionRequest) error {
    76  	tenantsToCreateGQL := p.converter.MultipleInputToGraphQLInput(p.tenantsFromRequest(*request))
    77  	return p.gqlClient.WriteTenants(ctx, tenantsToCreateGQL)
    78  }
    79  
    80  func (p *provisioner) tenantsFromRequest(request TenantSubscriptionRequest) []model.BusinessTenantMappingInput {
    81  	tenants := make([]model.BusinessTenantMappingInput, 0, 3)
    82  	customerID := request.CustomerTenantID
    83  	accountID := request.AccountTenantID
    84  	var licenseType *string
    85  
    86  	if len(request.SubscriptionLcenseType) > 0 {
    87  		licenseType = &request.SubscriptionLcenseType
    88  	}
    89  
    90  	if len(request.CustomerTenantID) > 0 {
    91  		tenants = append(tenants, p.newCustomerTenant(request.CustomerTenantID, licenseType))
    92  	}
    93  
    94  	accountTenant := p.newAccountTenant(request.AccountTenantID, customerID, request.Subdomain, request.Region, licenseType)
    95  	if len(request.SubaccountTenantID) > 0 { // This means that the request is for Subaccount provisioning, therefore the subdomain and the region are for the subaccount and not for the GA
    96  		accountTenant.Subdomain = ""
    97  		accountTenant.Region = ""
    98  	}
    99  	tenants = append(tenants, accountTenant)
   100  
   101  	if len(request.SubaccountTenantID) > 0 {
   102  		tenants = append(tenants, p.newSubaccountTenant(request.SubaccountTenantID, accountID, request.Subdomain, request.Region, licenseType))
   103  	}
   104  	return tenants
   105  }
   106  
   107  func (p *provisioner) newCustomerTenant(tenantID string, licenseType *string) model.BusinessTenantMappingInput {
   108  	return p.newTenant(tenantID, "", "", "", autogeneratedTenantProvider, licenseType, tenantEntity.Customer)
   109  }
   110  
   111  func (p *provisioner) newAccountTenant(tenantID, parent, subdomain, region string, licenseType *string) model.BusinessTenantMappingInput {
   112  	return p.newTenant(tenantID, parent, subdomain, region, p.tenantProvider, licenseType, tenantEntity.Account)
   113  }
   114  
   115  func (p *provisioner) newSubaccountTenant(tenantID, parent, subdomain, region string, licenseType *string) model.BusinessTenantMappingInput {
   116  	return p.newTenant(tenantID, parent, subdomain, region, p.tenantProvider, licenseType, tenantEntity.Subaccount)
   117  }
   118  
   119  func (p *provisioner) newTenant(tenantID, parent, subdomain, region, provider string, licenseType *string, tenantType tenantEntity.Type) model.BusinessTenantMappingInput {
   120  	return model.BusinessTenantMappingInput{
   121  		Name:           tenantID,
   122  		ExternalTenant: tenantID,
   123  		Parent:         parent,
   124  		Subdomain:      subdomain,
   125  		Region:         region,
   126  		Type:           tenantEntity.TypeToStr(tenantType),
   127  		Provider:       provider,
   128  		LicenseType:    licenseType,
   129  	}
   130  }