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

     1  package operationsmanager
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"time"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/internal/model"
     9  	"github.com/kyma-incubator/compass/components/director/pkg/log"
    10  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  const (
    15  	// OrdCreatorType specifies open resource discovery creator type
    16  	OrdCreatorType = "ORD"
    17  	// OrdAggregationOpType specifies open resource discovery operation type
    18  	OrdAggregationOpType = "ORD_AGGREGATION"
    19  )
    20  
    21  // OperationCreator is responsible for creation of different types of operations.
    22  //go:generate mockery --name=OperationCreator --output=automock --outpkg=automock --case=underscore --disable-version-string
    23  type OperationCreator interface {
    24  	Create(ctx context.Context) error
    25  }
    26  
    27  // ORDOperationCreator consists of various resource services responsible for operations creation.
    28  type ORDOperationCreator struct {
    29  	transact   persistence.Transactioner
    30  	opSvc      OperationService
    31  	webhookSvc WebhookService
    32  	appSvc     ApplicationService
    33  }
    34  
    35  // Create lists all webhooks of type "OPEN_RESOURCE_DISCOVERY" and for every application creates corresponding operation
    36  func (oc *ORDOperationCreator) Create(ctx context.Context) error {
    37  	operations, err := oc.buildOperationInputs(ctx)
    38  	if err != nil {
    39  		return errors.Wrap(err, "while building operation inputs")
    40  	}
    41  
    42  	tx, err := oc.transact.Begin()
    43  	if err != nil {
    44  		return err
    45  	}
    46  	defer oc.transact.RollbackUnlessCommitted(ctx, tx)
    47  	ctx = persistence.SaveToContext(ctx, tx)
    48  
    49  	if err := oc.opSvc.CreateMultiple(ctx, operations); err != nil {
    50  		return errors.Wrap(err, "while creating multiple operations")
    51  	}
    52  
    53  	return tx.Commit()
    54  }
    55  
    56  func (oc *ORDOperationCreator) buildOperationInputs(ctx context.Context) ([]*model.OperationInput, error) {
    57  	ordWebhooks, err := oc.getWebhooksWithOrdType(ctx)
    58  	if err != nil {
    59  		return nil, errors.Wrapf(err, "while getting webhooks of type %s", model.WebhookTypeOpenResourceDiscovery)
    60  	}
    61  
    62  	operations := make([]*model.OperationInput, 0)
    63  	for _, webhook := range ordWebhooks {
    64  		if webhook.ObjectType == model.ApplicationTemplateWebhookReference {
    65  			ops, err := oc.appTemplateWebhookToOperations(ctx, webhook)
    66  			if err != nil {
    67  				return nil, errors.Wrapf(err, "while creating operations from application template webhook")
    68  			}
    69  			operations = append(operations, ops...)
    70  		} else if webhook.ObjectType == model.ApplicationWebhookReference {
    71  			opData := NewOrdOperationData(webhook.ObjectID, "")
    72  			data, err := opData.GetData()
    73  			if err != nil {
    74  				return nil, err
    75  			}
    76  			operations = append(operations, buildORDOperationInput(data))
    77  		}
    78  	}
    79  
    80  	return operations, nil
    81  }
    82  
    83  func (oc *ORDOperationCreator) appTemplateWebhookToOperations(ctx context.Context, webhook *model.Webhook) ([]*model.OperationInput, error) {
    84  	operations := make([]*model.OperationInput, 0)
    85  	if webhook.ObjectType != model.ApplicationTemplateWebhookReference {
    86  		return operations, nil
    87  	}
    88  
    89  	apps, err := oc.getApplicationsForAppTemplate(ctx, webhook.ObjectID)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	for _, app := range apps {
    95  		opData := NewOrdOperationData(app.ID, webhook.ObjectID)
    96  		data, err := opData.GetData()
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  		operations = append(operations, buildORDOperationInput(data))
   101  	}
   102  
   103  	return operations, nil
   104  }
   105  
   106  func (oc *ORDOperationCreator) getWebhooksWithOrdType(ctx context.Context) ([]*model.Webhook, error) {
   107  	tx, err := oc.transact.Begin()
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	defer oc.transact.RollbackUnlessCommitted(ctx, tx)
   112  
   113  	ctx = persistence.SaveToContext(ctx, tx)
   114  	ordWebhooks, err := oc.webhookSvc.ListByWebhookType(ctx, model.WebhookTypeOpenResourceDiscovery)
   115  	if err != nil {
   116  		log.C(ctx).WithError(err).Errorf("error while fetching webhooks with type %s", model.WebhookTypeOpenResourceDiscovery)
   117  		return nil, err
   118  	}
   119  
   120  	if err := tx.Commit(); err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	return ordWebhooks, nil
   125  }
   126  
   127  func (oc *ORDOperationCreator) getApplicationsForAppTemplate(ctx context.Context, appTemplateID string) ([]*model.Application, error) {
   128  	tx, err := oc.transact.Begin()
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	defer oc.transact.RollbackUnlessCommitted(ctx, tx)
   133  
   134  	ctx = persistence.SaveToContext(ctx, tx)
   135  	apps, err := oc.appSvc.ListAllByApplicationTemplateID(ctx, appTemplateID)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  
   140  	if err := tx.Commit(); err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	return apps, err
   145  }
   146  
   147  func buildORDOperationInput(data string) *model.OperationInput {
   148  	now := time.Now()
   149  	return &model.OperationInput{
   150  		OpType:     OrdAggregationOpType,
   151  		Status:     scheduledOpStatus,
   152  		Data:       json.RawMessage(data),
   153  		Error:      nil,
   154  		Priority:   1,
   155  		CreatedAt:  &now,
   156  		FinishedAt: nil,
   157  	}
   158  }
   159  
   160  // NewOperationCreator creates OperationCreator based on kind
   161  func NewOperationCreator(kind string, transact persistence.Transactioner, opSvc OperationService, webhookSvc WebhookService, appSvc ApplicationService) OperationCreator {
   162  	if kind == OrdCreatorType {
   163  		return &ORDOperationCreator{
   164  			transact:   transact,
   165  			opSvc:      opSvc,
   166  			webhookSvc: webhookSvc,
   167  			appSvc:     appSvc,
   168  		}
   169  	}
   170  	return nil
   171  }