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

     1  package cis
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/kyma-project/kyma-environment-broker/internal"
     7  	"github.com/kyma-project/kyma-environment-broker/internal/storage"
     8  
     9  	"github.com/sirupsen/logrus"
    10  )
    11  
    12  //go:generate mockery --name=CisClient --output=automock
    13  type CisClient interface {
    14  	FetchSubaccountsToDelete() ([]string, error)
    15  }
    16  
    17  //go:generate mockery --name=BrokerClient --output=automock
    18  type BrokerClient interface {
    19  	Deprovision(instance internal.Instance) (string, error)
    20  }
    21  
    22  type SubAccountCleanupService struct {
    23  	client       CisClient
    24  	brokerClient BrokerClient
    25  	storage      storage.Instances
    26  	log          logrus.FieldLogger
    27  	chunksAmount int
    28  }
    29  
    30  func NewSubAccountCleanupService(client CisClient, brokerClient BrokerClient, storage storage.Instances, log logrus.FieldLogger) *SubAccountCleanupService {
    31  	return &SubAccountCleanupService{
    32  		client:       client,
    33  		brokerClient: brokerClient,
    34  		storage:      storage,
    35  		log:          log,
    36  		chunksAmount: 50,
    37  	}
    38  }
    39  
    40  func (ac *SubAccountCleanupService) Run() error {
    41  	subaccounts, err := ac.client.FetchSubaccountsToDelete()
    42  	if err != nil {
    43  		return fmt.Errorf("while fetching subaccounts by client: %w", err)
    44  	}
    45  
    46  	subaccountsBatch := chunk(ac.chunksAmount, subaccounts)
    47  	chunks := len(subaccountsBatch)
    48  	errCh := make(chan error)
    49  	done := make(chan struct{})
    50  	var isDone bool
    51  
    52  	for _, chunk := range subaccountsBatch {
    53  		go ac.executeDeprovisioning(chunk, done, errCh)
    54  	}
    55  
    56  	for !isDone {
    57  		select {
    58  		case err := <-errCh:
    59  			ac.log.Warnf("part of deprovisioning process failed with error: %s", err)
    60  		case <-done:
    61  			chunks--
    62  			if chunks == 0 {
    63  				isDone = true
    64  			}
    65  		}
    66  	}
    67  
    68  	ac.log.Info("SubAccount cleanup process finished")
    69  	return nil
    70  }
    71  
    72  func (ac *SubAccountCleanupService) executeDeprovisioning(subaccounts []string, done chan<- struct{}, errCh chan<- error) {
    73  	instances, err := ac.storage.FindAllInstancesForSubAccounts(subaccounts)
    74  	if err != nil {
    75  		errCh <- fmt.Errorf("while finding all instances by subaccounts: %w", err)
    76  		return
    77  	}
    78  
    79  	for _, instance := range instances {
    80  		operation, err := ac.brokerClient.Deprovision(instance)
    81  		if err != nil {
    82  			errCh <- fmt.Errorf("error occurred during deprovisioning instance with ID %s: %w", instance.InstanceID, err)
    83  			continue
    84  		}
    85  		ac.log.Infof("deprovisioning for instance %s (SubAccountID: %s) was triggered, operation: %s", instance.InstanceID, instance.SubAccountID, operation)
    86  	}
    87  
    88  	done <- struct{}{}
    89  }
    90  
    91  func chunk(amount int, data []string) [][]string {
    92  	var divided [][]string
    93  
    94  	for i := 0; i < len(data); i += amount {
    95  		end := i + amount
    96  		if end > len(data) {
    97  			end = len(data)
    98  		}
    99  		divided = append(divided, data[i:end])
   100  	}
   101  
   102  	return divided
   103  }