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

     1  package bundleinstanceauth
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/kyma-incubator/compass/components/director/pkg/consumer"
     7  	"github.com/kyma-incubator/compass/components/director/pkg/log"
     8  
     9  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    10  
    11  	"github.com/kyma-incubator/compass/components/director/internal/domain/tenant"
    12  	"github.com/kyma-incubator/compass/components/director/internal/model"
    13  	"github.com/kyma-incubator/compass/components/director/internal/timestamp"
    14  	"github.com/kyma-incubator/compass/components/director/pkg/jsonschema"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  // Repository missing godoc
    19  //go:generate mockery --name=Repository --output=automock --outpkg=automock --case=underscore --disable-version-string
    20  type Repository interface {
    21  	Create(ctx context.Context, item *model.BundleInstanceAuth) error
    22  	GetByID(ctx context.Context, tenantID string, id string) (*model.BundleInstanceAuth, error)
    23  	GetForBundle(ctx context.Context, tenant string, id string, bundleID string) (*model.BundleInstanceAuth, error)
    24  	ListByBundleID(ctx context.Context, tenantID string, bundleID string) ([]*model.BundleInstanceAuth, error)
    25  	ListByRuntimeID(ctx context.Context, tenantID string, runtimeID string) ([]*model.BundleInstanceAuth, error)
    26  	Update(ctx context.Context, tenant string, item *model.BundleInstanceAuth) error
    27  	Delete(ctx context.Context, tenantID string, id string) error
    28  }
    29  
    30  // UIDService missing godoc
    31  //go:generate mockery --name=UIDService --output=automock --outpkg=automock --case=underscore --disable-version-string
    32  type UIDService interface {
    33  	Generate() string
    34  }
    35  
    36  type service struct {
    37  	repo         Repository
    38  	uidService   UIDService
    39  	timestampGen timestamp.Generator
    40  }
    41  
    42  // NewService missing godoc
    43  func NewService(repo Repository, uidService UIDService) *service {
    44  	return &service{
    45  		repo:         repo,
    46  		uidService:   uidService,
    47  		timestampGen: timestamp.DefaultGenerator,
    48  	}
    49  }
    50  
    51  // Create missing godoc
    52  func (s *service) Create(ctx context.Context, bundleID string, in model.BundleInstanceAuthRequestInput, defaultAuth *model.Auth, requestInputSchema *string) (string, error) {
    53  	tnt, err := tenant.LoadFromContext(ctx)
    54  	if err != nil {
    55  		return "", err
    56  	}
    57  
    58  	log.C(ctx).Debugf("Validating BundleInstanceAuth request input for Bundle with id %s", bundleID)
    59  	if err = validateInputParamsAgainstSchema(in.InputParams, requestInputSchema); err != nil {
    60  		return "", errors.Wrapf(err, "while validating BundleInstanceAuth request input for Bundle with id %s", bundleID)
    61  	}
    62  
    63  	con, err := consumer.LoadFromContext(ctx)
    64  	if err != nil {
    65  		return "", err
    66  	}
    67  
    68  	var runtimeID *string
    69  	if con.ConsumerType == consumer.Runtime || con.ConsumerType == consumer.ExternalCertificate {
    70  		runtimeID = &con.ConsumerID
    71  	}
    72  
    73  	id := s.uidService.Generate()
    74  	log.C(ctx).Debugf("ID %s generated for BundleInstanceAuth for Bundle with id %s", id, bundleID)
    75  	bndlInstAuth := in.ToBundleInstanceAuth(id, bundleID, tnt, defaultAuth, nil, runtimeID, nil)
    76  
    77  	err = s.setCreationStatusFromAuth(ctx, &bndlInstAuth, defaultAuth)
    78  	if err != nil {
    79  		return "", errors.Wrapf(err, "while setting creation status for BundleInstanceAuth with id %s", id)
    80  	}
    81  
    82  	err = s.repo.Create(ctx, &bndlInstAuth)
    83  	if err != nil {
    84  		return "", errors.Wrapf(err, "while creating BundleInstanceAuth with id %s for Bundle with id %s", id, bundleID)
    85  	}
    86  
    87  	return id, nil
    88  }
    89  
    90  // CreateBundleInstanceAuth creates a BundleInstanceAuth for a Bundle with id - bundleID from a given input
    91  func (s *service) CreateBundleInstanceAuth(ctx context.Context, bundleID string, in model.BundleInstanceAuthCreateInput, requestInputSchema *string) (string, error) {
    92  	tnt, err := tenant.LoadFromContext(ctx)
    93  	if err != nil {
    94  		return "", err
    95  	}
    96  
    97  	log.C(ctx).Debugf("Validating BundleInstanceAuth request input for Bundle with id %q", bundleID)
    98  	if err = validateInputParamsAgainstSchema(in.InputParams, requestInputSchema); err != nil {
    99  		return "", errors.Wrapf(err, "while validating BundleInstanceAuth request input for Bundle with id %q", bundleID)
   100  	}
   101  
   102  	id := s.uidService.Generate()
   103  	log.C(ctx).Debugf("ID %q generated for BundleInstanceAuth for Bundle with id %q", id, bundleID)
   104  	bndlInstAuth := in.ToBundleInstanceAuth(id, bundleID, tnt, nil)
   105  
   106  	//  Always create bundle instance auth with status SUCCEEDED
   107  	if err = bndlInstAuth.SetDefaultStatus(model.BundleInstanceAuthStatusConditionSucceeded, s.timestampGen()); err != nil {
   108  		return "", err
   109  	}
   110  
   111  	if err = s.repo.Create(ctx, &bndlInstAuth); err != nil {
   112  		return "", errors.Wrapf(err, "while creating BundleInstanceAuth with id %s for Bundle with id %s", id, bundleID)
   113  	}
   114  
   115  	return id, nil
   116  }
   117  
   118  // Get missing godoc
   119  func (s *service) Get(ctx context.Context, id string) (*model.BundleInstanceAuth, error) {
   120  	tnt, err := tenant.LoadFromContext(ctx)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	instanceAuth, err := s.repo.GetByID(ctx, tnt, id)
   126  	if err != nil {
   127  		return nil, errors.Wrapf(err, "while getting BundleInstanceAuth with id %s", id)
   128  	}
   129  
   130  	return instanceAuth, nil
   131  }
   132  
   133  // GetForBundle missing godoc
   134  func (s *service) GetForBundle(ctx context.Context, id string, bundleID string) (*model.BundleInstanceAuth, error) {
   135  	tnt, err := tenant.LoadFromContext(ctx)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  
   140  	bndl, err := s.repo.GetForBundle(ctx, tnt, id, bundleID)
   141  	if err != nil {
   142  		return nil, errors.Wrapf(err, "while getting Bundle Instance Auth with ID: [%s]", id)
   143  	}
   144  
   145  	return bndl, nil
   146  }
   147  
   148  // List missing godoc
   149  func (s *service) List(ctx context.Context, bundleID string) ([]*model.BundleInstanceAuth, error) {
   150  	tnt, err := tenant.LoadFromContext(ctx)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	bndlInstanceAuths, err := s.repo.ListByBundleID(ctx, tnt, bundleID)
   156  	if err != nil {
   157  		return nil, errors.Wrap(err, "while listing Bundle Instance Auths")
   158  	}
   159  
   160  	return bndlInstanceAuths, nil
   161  }
   162  
   163  // ListByRuntimeID missing godoc
   164  func (s *service) ListByRuntimeID(ctx context.Context, runtimeID string) ([]*model.BundleInstanceAuth, error) {
   165  	tnt, err := tenant.LoadFromContext(ctx)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	bndlInstanceAuths, err := s.repo.ListByRuntimeID(ctx, tnt, runtimeID)
   171  	if err != nil {
   172  		return nil, errors.Wrap(err, "while listing Bundle Instance Auths")
   173  	}
   174  
   175  	return bndlInstanceAuths, nil
   176  }
   177  
   178  // Update missing godoc
   179  func (s *service) Update(ctx context.Context, instanceAuth *model.BundleInstanceAuth) error {
   180  	tnt, err := tenant.LoadFromContext(ctx)
   181  	if err != nil {
   182  		return err
   183  	}
   184  
   185  	if err = s.repo.Update(ctx, tnt, instanceAuth); err != nil {
   186  		return errors.Wrap(err, "while updating Bundle Instance Auths")
   187  	}
   188  
   189  	return nil
   190  }
   191  
   192  // SetAuth missing godoc
   193  func (s *service) SetAuth(ctx context.Context, id string, in model.BundleInstanceAuthSetInput) error {
   194  	tnt, err := tenant.LoadFromContext(ctx)
   195  	if err != nil {
   196  		return err
   197  	}
   198  
   199  	instanceAuth, err := s.repo.GetByID(ctx, tnt, id)
   200  	if err != nil {
   201  		return errors.Wrapf(err, "while getting BundleInstanceAuth with id %s", id)
   202  	}
   203  	if instanceAuth == nil {
   204  		return errors.Errorf("BundleInstanceAuth with id %s not found", id)
   205  	}
   206  
   207  	if instanceAuth.Status == nil || instanceAuth.Status.Condition != model.BundleInstanceAuthStatusConditionPending {
   208  		return apperrors.NewInvalidOperationError("auth can be set only on BundleInstanceAuths in PENDING state")
   209  	}
   210  
   211  	err = s.setUpdateAuthAndStatus(ctx, instanceAuth, in)
   212  	if err != nil {
   213  		return err
   214  	}
   215  
   216  	if err = s.repo.Update(ctx, tnt, instanceAuth); err != nil {
   217  		return errors.Wrapf(err, "while updating BundleInstanceAuth with ID %s", id)
   218  	}
   219  	return nil
   220  }
   221  
   222  // RequestDeletion missing godoc
   223  func (s *service) RequestDeletion(ctx context.Context, instanceAuth *model.BundleInstanceAuth, defaultBundleInstanceAuth *model.Auth) (bool, error) {
   224  	tnt, err := tenant.LoadFromContext(ctx)
   225  	if err != nil {
   226  		return false, err
   227  	}
   228  	if instanceAuth == nil {
   229  		return false, apperrors.NewInternalError("BundleInstanceAuth is required to request its deletion")
   230  	}
   231  
   232  	if defaultBundleInstanceAuth == nil {
   233  		log.C(ctx).Debugf("Default credentials for BundleInstanceAuth with id %s are not provided.", instanceAuth.ID)
   234  
   235  		err := instanceAuth.SetDefaultStatus(model.BundleInstanceAuthStatusConditionUnused, s.timestampGen())
   236  		if err != nil {
   237  			return false, errors.Wrapf(err, "while setting status of BundleInstanceAuth with id %s to '%s'", instanceAuth.ID, model.BundleInstanceAuthStatusConditionUnused)
   238  		}
   239  		log.C(ctx).Infof("Status for BundleInstanceAuth with id %s set to '%s'. Credentials are ready for being deleted by Application or Integration System.", instanceAuth.ID, model.BundleInstanceAuthStatusConditionUnused)
   240  
   241  		if err = s.repo.Update(ctx, tnt, instanceAuth); err != nil {
   242  			return false, errors.Wrapf(err, "while updating BundleInstanceAuth with id %s", instanceAuth.ID)
   243  		}
   244  
   245  		return false, nil
   246  	}
   247  
   248  	log.C(ctx).Debugf("Default credentials for BundleInstanceAuth with id %s are provided.", instanceAuth.ID)
   249  	if err = s.Delete(ctx, instanceAuth.ID); err != nil {
   250  		return false, err
   251  	}
   252  
   253  	return true, nil
   254  }
   255  
   256  // Delete missing godoc
   257  func (s *service) Delete(ctx context.Context, id string) error {
   258  	tnt, err := tenant.LoadFromContext(ctx)
   259  	if err != nil {
   260  		return err
   261  	}
   262  
   263  	log.C(ctx).Debugf("Deleting BundleInstanceAuth entity with id %s in db", id)
   264  	err = s.repo.Delete(ctx, tnt, id)
   265  
   266  	return errors.Wrapf(err, "while deleting BundleInstanceAuth with id %s", id)
   267  }
   268  
   269  func (s *service) setUpdateAuthAndStatus(ctx context.Context, instanceAuth *model.BundleInstanceAuth, in model.BundleInstanceAuthSetInput) error {
   270  	if instanceAuth == nil {
   271  		return nil
   272  	}
   273  
   274  	ts := s.timestampGen()
   275  
   276  	instanceAuth.Auth = in.Auth.ToAuth()
   277  	instanceAuth.Status = in.Status.ToBundleInstanceAuthStatus(ts)
   278  
   279  	// Input validation ensures that status can be nil only when auth was provided, so we can assume SUCCEEDED status
   280  	if instanceAuth.Status == nil {
   281  		log.C(ctx).Infof("Updating the status of BundleInstanceAuth with id %s to '%s'", instanceAuth.ID, model.BundleInstanceAuthStatusConditionSucceeded)
   282  		err := instanceAuth.SetDefaultStatus(model.BundleInstanceAuthStatusConditionSucceeded, ts)
   283  		if err != nil {
   284  			return errors.Wrapf(err, "while setting status '%s' to BundleInstanceAuth with id %s", model.BundleInstanceAuthStatusConditionSucceeded, instanceAuth.ID)
   285  		}
   286  	}
   287  
   288  	return nil
   289  }
   290  
   291  func (s *service) setCreationStatusFromAuth(ctx context.Context, instanceAuth *model.BundleInstanceAuth, defaultAuth *model.Auth) error {
   292  	if instanceAuth == nil {
   293  		return nil
   294  	}
   295  
   296  	var condition model.BundleInstanceAuthStatusCondition
   297  	if defaultAuth != nil {
   298  		log.C(ctx).Infof("Default credentials for BundleInstanceAuth with id %s from Bundle with id %s are provided. Setting creation status to '%s'", instanceAuth.ID, instanceAuth.BundleID, model.BundleInstanceAuthStatusConditionSucceeded)
   299  		condition = model.BundleInstanceAuthStatusConditionSucceeded
   300  	} else {
   301  		log.C(ctx).Infof("Default credentials for BundleInstanceAuth with id %s from Bundle with id %s are not provided. Setting creation status to '%s'", instanceAuth.ID, instanceAuth.BundleID, model.BundleInstanceAuthStatusConditionPending)
   302  		condition = model.BundleInstanceAuthStatusConditionPending
   303  	}
   304  
   305  	err := instanceAuth.SetDefaultStatus(condition, s.timestampGen())
   306  	return errors.Wrapf(err, "while setting default status for BundleInstanceAuth with id %s", instanceAuth.ID)
   307  }
   308  
   309  func validateInputParamsAgainstSchema(inputParams *string, schema *string) error {
   310  	if schema == nil {
   311  		return nil
   312  	}
   313  	if inputParams == nil {
   314  		return apperrors.NewInvalidDataError("json schema for input parameters was defined for the bundle but no input parameters were provided")
   315  	}
   316  
   317  	validator, err := jsonschema.NewValidatorFromStringSchema(*schema)
   318  	if err != nil {
   319  		return errors.Wrapf(err, "while creating JSON Schema validator for schema %+s", *schema)
   320  	}
   321  
   322  	result, err := validator.ValidateString(*inputParams)
   323  	if err != nil {
   324  		return errors.Wrapf(err, "while validating value %s against JSON Schema: %s", *inputParams, *schema)
   325  	}
   326  	if !result.Valid {
   327  		return errors.Wrapf(result.Error, "while validating value %s against JSON Schema: %s", *inputParams, *schema)
   328  	}
   329  
   330  	return nil
   331  }