github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/apptemplate/resolver.go (about) 1 package apptemplate 2 3 import ( 4 "context" 5 "crypto/sha256" 6 "encoding/json" 7 "fmt" 8 "regexp" 9 "strings" 10 11 "github.com/kyma-incubator/compass/components/director/internal/domain/scenarioassignment" 12 13 "github.com/kyma-incubator/compass/components/director/internal/domain/tenant" 14 15 "github.com/kyma-incubator/compass/components/director/pkg/consumer" 16 17 "github.com/kyma-incubator/compass/components/director/internal/labelfilter" 18 "github.com/kyma-incubator/compass/components/director/internal/selfregmanager" 19 "github.com/kyma-incubator/compass/components/director/pkg/resource" 20 21 "github.com/kyma-incubator/compass/components/director/pkg/str" 22 23 "github.com/kyma-incubator/compass/components/director/pkg/inputvalidation" 24 25 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 26 27 "github.com/kyma-incubator/compass/components/director/internal/model" 28 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 29 "github.com/kyma-incubator/compass/components/director/pkg/persistence" 30 31 "github.com/kyma-incubator/compass/components/director/pkg/log" 32 "github.com/pkg/errors" 33 ) 34 35 const ( 36 globalSubaccountIDLabelKey = "global_subaccount_id" 37 sapProviderName = "SAP" 38 displayNameLabelKey = "displayName" 39 ) 40 41 // ApplicationTemplateService missing godoc 42 // 43 //go:generate mockery --name=ApplicationTemplateService --output=automock --outpkg=automock --case=underscore --disable-version-string 44 type ApplicationTemplateService interface { 45 Create(ctx context.Context, in model.ApplicationTemplateInput) (string, error) 46 CreateWithLabels(ctx context.Context, in model.ApplicationTemplateInput, labels map[string]interface{}) (string, error) 47 Get(ctx context.Context, id string) (*model.ApplicationTemplate, error) 48 GetByFilters(ctx context.Context, filter []*labelfilter.LabelFilter) (*model.ApplicationTemplate, error) 49 GetByNameAndRegion(ctx context.Context, name string, region interface{}) (*model.ApplicationTemplate, error) 50 List(ctx context.Context, filter []*labelfilter.LabelFilter, pageSize int, cursor string) (model.ApplicationTemplatePage, error) 51 ListByName(ctx context.Context, name string) ([]*model.ApplicationTemplate, error) 52 ListByFilters(ctx context.Context, filter []*labelfilter.LabelFilter) ([]*model.ApplicationTemplate, error) 53 Update(ctx context.Context, id string, in model.ApplicationTemplateUpdateInput) error 54 Delete(ctx context.Context, id string) error 55 PrepareApplicationCreateInputJSON(appTemplate *model.ApplicationTemplate, values model.ApplicationFromTemplateInputValues) (string, error) 56 ListLabels(ctx context.Context, appTemplateID string) (map[string]*model.Label, error) 57 GetLabel(ctx context.Context, appTemplateID string, key string) (*model.Label, error) 58 } 59 60 // ApplicationTemplateConverter missing godoc 61 // 62 //go:generate mockery --name=ApplicationTemplateConverter --output=automock --outpkg=automock --case=underscore --disable-version-string 63 type ApplicationTemplateConverter interface { 64 ToGraphQL(in *model.ApplicationTemplate) (*graphql.ApplicationTemplate, error) 65 MultipleToGraphQL(in []*model.ApplicationTemplate) ([]*graphql.ApplicationTemplate, error) 66 InputFromGraphQL(in graphql.ApplicationTemplateInput) (model.ApplicationTemplateInput, error) 67 UpdateInputFromGraphQL(in graphql.ApplicationTemplateUpdateInput) (model.ApplicationTemplateUpdateInput, error) 68 ApplicationFromTemplateInputFromGraphQL(appTemplate *model.ApplicationTemplate, in graphql.ApplicationFromTemplateInput) (model.ApplicationFromTemplateInput, error) 69 } 70 71 // ApplicationConverter missing godoc 72 // 73 //go:generate mockery --name=ApplicationConverter --output=automock --outpkg=automock --case=underscore --disable-version-string 74 type ApplicationConverter interface { 75 ToGraphQL(in *model.Application) *graphql.Application 76 CreateRegisterInputJSONToGQL(in string) (graphql.ApplicationRegisterInput, error) 77 CreateInputFromGraphQL(ctx context.Context, in graphql.ApplicationRegisterInput) (model.ApplicationRegisterInput, error) 78 } 79 80 // ApplicationService missing godoc 81 // 82 //go:generate mockery --name=ApplicationService --output=automock --outpkg=automock --case=underscore --disable-version-string 83 type ApplicationService interface { 84 Create(ctx context.Context, in model.ApplicationRegisterInput) (string, error) 85 CreateFromTemplate(ctx context.Context, in model.ApplicationRegisterInput, appTemplateID *string) (string, error) 86 Get(ctx context.Context, id string) (*model.Application, error) 87 } 88 89 // WebhookService missing godoc 90 // 91 //go:generate mockery --name=WebhookService --output=automock --outpkg=automock --case=underscore --disable-version-string 92 type WebhookService interface { 93 ListForApplicationTemplate(ctx context.Context, applicationTemplateID string) ([]*model.Webhook, error) 94 EnrichWebhooksWithTenantMappingWebhooks(in []*graphql.WebhookInput) ([]*graphql.WebhookInput, error) 95 } 96 97 // WebhookConverter missing godoc 98 // 99 //go:generate mockery --name=WebhookConverter --output=automock --outpkg=automock --case=underscore --disable-version-string 100 type WebhookConverter interface { 101 MultipleToGraphQL(in []*model.Webhook) ([]*graphql.Webhook, error) 102 MultipleInputFromGraphQL(in []*graphql.WebhookInput) ([]*model.WebhookInput, error) 103 } 104 105 // SelfRegisterManager missing godoc 106 // 107 //go:generate mockery --name=SelfRegisterManager --output=automock --outpkg=automock --case=underscore --disable-version-string 108 type SelfRegisterManager interface { 109 IsSelfRegistrationFlow(ctx context.Context, labels map[string]interface{}) (bool, error) 110 PrepareForSelfRegistration(ctx context.Context, resourceType resource.Type, labels map[string]interface{}, id string, validate func() error) (map[string]interface{}, error) 111 CleanupSelfRegistration(ctx context.Context, selfRegisterLabelValue, region string) error 112 GetSelfRegDistinguishingLabelKey() string 113 } 114 115 // Resolver missing godoc 116 type Resolver struct { 117 transact persistence.Transactioner 118 119 appSvc ApplicationService 120 appConverter ApplicationConverter 121 appTemplateSvc ApplicationTemplateService 122 appTemplateConverter ApplicationTemplateConverter 123 webhookSvc WebhookService 124 webhookConverter WebhookConverter 125 selfRegManager SelfRegisterManager 126 uidService UIDService 127 appTemplateProductLabel string 128 } 129 130 // NewResolver missing godoc 131 func NewResolver(transact persistence.Transactioner, appSvc ApplicationService, appConverter ApplicationConverter, appTemplateSvc ApplicationTemplateService, appTemplateConverter ApplicationTemplateConverter, webhookService WebhookService, webhookConverter WebhookConverter, selfRegisterManager SelfRegisterManager, uidService UIDService, appTemplateProductLabel string) *Resolver { 132 return &Resolver{ 133 transact: transact, 134 appSvc: appSvc, 135 appConverter: appConverter, 136 appTemplateSvc: appTemplateSvc, 137 appTemplateConverter: appTemplateConverter, 138 webhookSvc: webhookService, 139 webhookConverter: webhookConverter, 140 selfRegManager: selfRegisterManager, 141 uidService: uidService, 142 appTemplateProductLabel: appTemplateProductLabel, 143 } 144 } 145 146 // ApplicationTemplate missing godoc 147 func (r *Resolver) ApplicationTemplate(ctx context.Context, id string) (*graphql.ApplicationTemplate, error) { 148 tx, err := r.transact.Begin() 149 if err != nil { 150 return nil, err 151 } 152 defer r.transact.RollbackUnlessCommitted(ctx, tx) 153 154 ctx = persistence.SaveToContext(ctx, tx) 155 156 appTemplate, err := r.appTemplateSvc.Get(ctx, id) 157 if err != nil { 158 if apperrors.IsNotFoundError(err) { 159 return nil, tx.Commit() 160 } 161 return nil, err 162 } 163 164 err = tx.Commit() 165 if err != nil { 166 return nil, err 167 } 168 169 out, err := r.appTemplateConverter.ToGraphQL(appTemplate) 170 if err != nil { 171 return nil, errors.Wrapf(err, "while converting application template to graphql") 172 } 173 174 return out, nil 175 } 176 177 // ApplicationTemplates missing godoc 178 func (r *Resolver) ApplicationTemplates(ctx context.Context, filter []*graphql.LabelFilter, first *int, after *graphql.PageCursor) (*graphql.ApplicationTemplatePage, error) { 179 labelFilter := labelfilter.MultipleFromGraphQL(filter) 180 var cursor string 181 if after != nil { 182 cursor = string(*after) 183 } 184 if first == nil { 185 return nil, apperrors.NewInvalidDataError("missing required parameter 'first'") 186 } 187 188 tx, err := r.transact.Begin() 189 if err != nil { 190 return nil, err 191 } 192 defer r.transact.RollbackUnlessCommitted(ctx, tx) 193 194 ctx = persistence.SaveToContext(ctx, tx) 195 196 appTemplatePage, err := r.appTemplateSvc.List(ctx, labelFilter, *first, cursor) 197 if err != nil { 198 return nil, err 199 } 200 201 err = tx.Commit() 202 if err != nil { 203 return nil, err 204 } 205 206 gqlAppTemplate, err := r.appTemplateConverter.MultipleToGraphQL(appTemplatePage.Data) 207 if err != nil { 208 return nil, errors.Wrapf(err, "while converting application templates to graphql") 209 } 210 211 return &graphql.ApplicationTemplatePage{ 212 Data: gqlAppTemplate, 213 TotalCount: appTemplatePage.TotalCount, 214 PageInfo: &graphql.PageInfo{ 215 StartCursor: graphql.PageCursor(appTemplatePage.PageInfo.StartCursor), 216 EndCursor: graphql.PageCursor(appTemplatePage.PageInfo.EndCursor), 217 HasNextPage: appTemplatePage.PageInfo.HasNextPage, 218 }, 219 }, nil 220 } 221 222 // CreateApplicationTemplate missing godoc 223 func (r *Resolver) CreateApplicationTemplate(ctx context.Context, in graphql.ApplicationTemplateInput) (*graphql.ApplicationTemplate, error) { 224 if err := in.Validate(); err != nil { 225 return nil, err 226 } 227 228 if err := validateAppTemplateNameBasedOnProvider(in.Name, in.ApplicationInput); err != nil { 229 return nil, err 230 } 231 232 webhooks, err := r.webhookSvc.EnrichWebhooksWithTenantMappingWebhooks(in.Webhooks) 233 if err != nil { 234 return nil, err 235 } 236 237 if in.Webhooks != nil { 238 in.Webhooks = webhooks 239 } 240 convertedIn, err := r.appTemplateConverter.InputFromGraphQL(in) 241 242 if err != nil { 243 return nil, err 244 } 245 246 if convertedIn.Labels == nil { 247 convertedIn.Labels = make(map[string]interface{}) 248 } 249 250 selfRegID := r.uidService.Generate() 251 convertedIn.ID = &selfRegID 252 253 consumerInfo, err := consumer.LoadFromContext(ctx) 254 if err != nil { 255 return nil, errors.Wrapf(err, "while loading consumer") 256 } 257 258 labels := convertedIn.Labels 259 if _, err := tenant.LoadFromContext(ctx); err == nil && consumerInfo.Flow.IsCertFlow() { 260 isSelfReg, selfRegFlowErr := r.isSelfRegFlow(labels) 261 if selfRegFlowErr != nil { 262 return nil, selfRegFlowErr 263 } 264 265 if isSelfReg { 266 validate := func() error { 267 return validateAppTemplateForSelfReg(in.ApplicationInput) 268 } 269 labels, err = r.selfRegManager.PrepareForSelfRegistration(ctx, resource.ApplicationTemplate, convertedIn.Labels, selfRegID, validate) 270 if err != nil { 271 return nil, err 272 } 273 } 274 275 labels[scenarioassignment.SubaccountIDKey] = consumerInfo.ConsumerID 276 } 277 278 tx, err := r.transact.Begin() 279 if err != nil { 280 return nil, err 281 } 282 283 defer func() { 284 didRollback := r.transact.RollbackUnlessCommitted(ctx, tx) 285 if didRollback { 286 labelVal := str.CastOrEmpty(convertedIn.Labels[r.selfRegManager.GetSelfRegDistinguishingLabelKey()]) 287 if labelVal != "" { 288 label, ok := labels[selfregmanager.RegionLabel].(string) 289 if !ok { 290 log.C(ctx).Errorf("An error occurred while casting region label value to string") 291 } else { 292 r.cleanupAndLogOnError(ctx, selfRegID, label) 293 } 294 } 295 } 296 }() 297 298 ctx = persistence.SaveToContext(ctx, tx) 299 300 if err := r.checkProviderAppTemplateExistence(ctx, labels); err != nil { 301 return nil, err 302 } 303 304 log.C(ctx).Infof("Creating an Application Template with name %s", convertedIn.Name) 305 id, err := r.appTemplateSvc.CreateWithLabels(ctx, convertedIn, labels) 306 if err != nil { 307 return nil, err 308 } 309 log.C(ctx).Infof("Successfully created an Application Template with name %s and id %s", convertedIn.Name, id) 310 311 appTemplate, err := r.appTemplateSvc.Get(ctx, id) 312 if err != nil { 313 return nil, err 314 } 315 316 err = tx.Commit() 317 if err != nil { 318 return nil, err 319 } 320 321 gqlAppTemplate, err := r.appTemplateConverter.ToGraphQL(appTemplate) 322 if err != nil { 323 return nil, errors.Wrapf(err, "while converting Application Template with id %s to GraphQL", id) 324 } 325 326 return gqlAppTemplate, nil 327 } 328 329 // Labels retrieve all labels for application template 330 func (r *Resolver) Labels(ctx context.Context, obj *graphql.ApplicationTemplate, key *string) (graphql.Labels, error) { 331 if obj == nil { 332 return nil, apperrors.NewInternalError("Application Template cannot be empty") 333 } 334 335 tx, err := r.transact.Begin() 336 if err != nil { 337 return nil, err 338 } 339 defer r.transact.RollbackUnlessCommitted(ctx, tx) 340 341 ctx = persistence.SaveToContext(ctx, tx) 342 343 itemMap, err := r.appTemplateSvc.ListLabels(ctx, obj.ID) 344 if err != nil { 345 if strings.Contains(err.Error(), "doesn't exist") { 346 return nil, tx.Commit() 347 } 348 return nil, err 349 } 350 351 err = tx.Commit() 352 if err != nil { 353 return nil, err 354 } 355 356 resultLabels := make(map[string]interface{}) 357 358 for _, label := range itemMap { 359 if key == nil || label.Key == *key { 360 resultLabels[label.Key] = label.Value 361 } 362 } 363 364 var gqlLabels graphql.Labels = resultLabels 365 return gqlLabels, nil 366 } 367 368 // RegisterApplicationFromTemplate registers an Application using Application Template 369 func (r *Resolver) RegisterApplicationFromTemplate(ctx context.Context, in graphql.ApplicationFromTemplateInput) (*graphql.Application, error) { 370 consumerInfo, err := consumer.LoadFromContext(ctx) 371 if err != nil { 372 return nil, errors.Wrapf(err, "while fetching consumer info from context") 373 } 374 375 tx, err := r.transact.Begin() 376 if err != nil { 377 return nil, err 378 } 379 defer r.transact.RollbackUnlessCommitted(ctx, tx) 380 381 ctx = persistence.SaveToContext(ctx, tx) 382 383 log.C(ctx).Debugf("Extracting Application Template with name %q and consumer id REDACTED_%x from GraphQL input", in.TemplateName, sha256.Sum256([]byte(consumerInfo.ConsumerID))) 384 appTemplate, err := r.retrieveAppTemplate(ctx, in.TemplateName, consumerInfo.ConsumerID, in.ID) 385 if err != nil { 386 return nil, err 387 } 388 389 log.C(ctx).Infof("Registering an Application from Application Template with name %s", in.TemplateName) 390 convertedIn, err := r.appTemplateConverter.ApplicationFromTemplateInputFromGraphQL(appTemplate, in) 391 if err != nil { 392 return nil, err 393 } 394 395 log.C(ctx).Debugf("Preparing ApplicationCreateInput JSON from Application Template with name %s", in.TemplateName) 396 appCreateInputJSON, err := r.appTemplateSvc.PrepareApplicationCreateInputJSON(appTemplate, convertedIn.Values) 397 if err != nil { 398 return nil, errors.Wrapf(err, "while preparing ApplicationCreateInput JSON from Application Template with name %s", in.TemplateName) 399 } 400 401 log.C(ctx).Debugf("Converting ApplicationCreateInput JSON to GraphQL ApplicationRegistrationInput from Application Template with name %s", in.TemplateName) 402 appCreateInputGQL, err := r.appConverter.CreateRegisterInputJSONToGQL(appCreateInputJSON) 403 if err != nil { 404 return nil, errors.Wrapf(err, "while converting ApplicationCreateInput JSON to GraphQL ApplicationRegistrationInput from Application Template with name %s", in.TemplateName) 405 } 406 407 log.C(ctx).Infof("Validating GraphQL ApplicationRegistrationInput from Application Template with name %s", convertedIn.TemplateName) 408 if err := inputvalidation.Validate(appCreateInputGQL); err != nil { 409 return nil, errors.Wrapf(err, "while validating application input from Application Template with name %s", convertedIn.TemplateName) 410 } 411 412 appCreateInputModel, err := r.appConverter.CreateInputFromGraphQL(ctx, appCreateInputGQL) 413 if err != nil { 414 return nil, errors.Wrap(err, "while converting ApplicationFromTemplate input") 415 } 416 417 if appCreateInputModel.Labels == nil { 418 appCreateInputModel.Labels = make(map[string]interface{}) 419 } 420 appCreateInputModel.Labels["managed"] = "false" 421 422 if convertedIn.Labels != nil { 423 for k, v := range in.Labels { 424 appCreateInputModel.Labels[k] = v 425 } 426 } 427 428 applicationName, err := extractApplicationNameFromTemplateInput(appCreateInputJSON) 429 if err != nil { 430 return nil, err 431 } 432 log.C(ctx).Infof("Creating an Application with name %s from Application Template with name %s", applicationName, in.TemplateName) 433 id, err := r.appSvc.CreateFromTemplate(ctx, appCreateInputModel, &appTemplate.ID) 434 if err != nil { 435 return nil, errors.Wrapf(err, "while creating an Application with name %s from Application Template with name %s", applicationName, in.TemplateName) 436 } 437 log.C(ctx).Infof("Application with name %s and id %s successfully created from Application Template with name %s", applicationName, id, in.TemplateName) 438 439 app, err := r.appSvc.Get(ctx, id) 440 if err != nil { 441 return nil, err 442 } 443 444 err = tx.Commit() 445 if err != nil { 446 return nil, err 447 } 448 449 gqlApp := r.appConverter.ToGraphQL(app) 450 return gqlApp, nil 451 } 452 453 // UpdateApplicationTemplate missing godoc 454 func (r *Resolver) UpdateApplicationTemplate(ctx context.Context, id string, in graphql.ApplicationTemplateUpdateInput) (*graphql.ApplicationTemplate, error) { 455 tx, err := r.transact.Begin() 456 if err != nil { 457 return nil, err 458 } 459 defer r.transact.RollbackUnlessCommitted(ctx, tx) 460 461 ctx = persistence.SaveToContext(ctx, tx) 462 463 if err := in.Validate(); err != nil { 464 return nil, err 465 } 466 467 if err := validateAppTemplateNameBasedOnProvider(in.Name, in.ApplicationInput); err != nil { 468 return nil, err 469 } 470 471 webhooks, err := r.webhookSvc.EnrichWebhooksWithTenantMappingWebhooks(in.Webhooks) 472 if err != nil { 473 return nil, err 474 } 475 476 if in.Webhooks != nil { 477 in.Webhooks = webhooks 478 } 479 480 convertedIn, err := r.appTemplateConverter.UpdateInputFromGraphQL(in) 481 if err != nil { 482 return nil, err 483 } 484 485 labels, err := r.appTemplateSvc.ListLabels(ctx, id) 486 if err != nil { 487 return nil, err 488 } 489 490 resultLabels := make(map[string]interface{}, len(labels)) 491 for _, label := range labels { 492 resultLabels[label.Key] = label.Value 493 } 494 495 isSelfRegFlow, err := r.selfRegManager.IsSelfRegistrationFlow(ctx, resultLabels) 496 if err != nil { 497 return nil, err 498 } 499 if isSelfRegFlow { 500 if err := validateAppTemplateForSelfReg(in.ApplicationInput); err != nil { 501 return nil, err 502 } 503 } 504 505 log.C(ctx).Infof("Updating an Application Template with id %q", id) 506 err = r.appTemplateSvc.Update(ctx, id, convertedIn) 507 if err != nil { 508 return nil, err 509 } 510 511 appTemplate, err := r.appTemplateSvc.Get(ctx, id) 512 if err != nil { 513 return nil, err 514 } 515 516 err = tx.Commit() 517 if err != nil { 518 return nil, err 519 } 520 521 gqlAppTemplate, err := r.appTemplateConverter.ToGraphQL(appTemplate) 522 if err != nil { 523 return nil, errors.Wrapf(err, "while converting application template to graphql") 524 } 525 526 return gqlAppTemplate, nil 527 } 528 529 // DeleteApplicationTemplate missing godoc 530 func (r *Resolver) DeleteApplicationTemplate(ctx context.Context, id string) (*graphql.ApplicationTemplate, error) { 531 tx, err := r.transact.Begin() 532 if err != nil { 533 return nil, err 534 } 535 defer r.transact.RollbackUnlessCommitted(ctx, tx) 536 537 ctx = persistence.SaveToContext(ctx, tx) 538 539 appTemplate, err := r.appTemplateSvc.Get(ctx, id) 540 if err != nil { 541 return nil, err 542 } 543 544 _, err = r.appTemplateSvc.GetLabel(ctx, id, r.selfRegManager.GetSelfRegDistinguishingLabelKey()) 545 if err != nil { 546 if !apperrors.IsNotFoundError(err) { 547 return nil, errors.Wrapf(err, "while getting self register label") 548 } 549 } else { 550 regionLabel, err := r.appTemplateSvc.GetLabel(ctx, id, selfregmanager.RegionLabel) 551 if err != nil { 552 return nil, errors.Wrapf(err, "while getting region label") 553 } 554 555 // Committing transaction as the cleanup sends request to external service 556 if err = tx.Commit(); err != nil { 557 return nil, err 558 } 559 560 regionValue, ok := regionLabel.Value.(string) 561 if !ok { 562 return nil, errors.Wrap(err, "while casting region label value to string") 563 } 564 565 log.C(ctx).Infof("Executing clean-up for self-registered app template with id %q", id) 566 if err := r.selfRegManager.CleanupSelfRegistration(ctx, id, regionValue); err != nil { 567 return nil, errors.Wrap(err, "An error occurred during cleanup of self-registered app template: ") 568 } 569 570 tx, err = r.transact.Begin() 571 if err != nil { 572 return nil, err 573 } 574 ctx = persistence.SaveToContext(ctx, tx) 575 } 576 577 log.C(ctx).Infof("Deleting an Application Template with id %q", id) 578 err = r.appTemplateSvc.Delete(ctx, id) 579 if err != nil { 580 return nil, err 581 } 582 583 err = tx.Commit() 584 if err != nil { 585 return nil, err 586 } 587 588 deletedAppTemplate, err := r.appTemplateConverter.ToGraphQL(appTemplate) 589 if err != nil { 590 return nil, errors.Wrapf(err, "while converting application template to graphql") 591 } 592 593 return deletedAppTemplate, nil 594 } 595 596 // Webhooks missing godoc 597 func (r *Resolver) Webhooks(ctx context.Context, obj *graphql.ApplicationTemplate) ([]*graphql.Webhook, error) { 598 tx, err := r.transact.Begin() 599 if err != nil { 600 return nil, err 601 } 602 defer r.transact.RollbackUnlessCommitted(ctx, tx) 603 604 ctx = persistence.SaveToContext(ctx, tx) 605 606 webhooks, err := r.webhookSvc.ListForApplicationTemplate(ctx, obj.ID) 607 if err != nil { 608 return nil, err 609 } 610 611 if err := tx.Commit(); err != nil { 612 return nil, err 613 } 614 615 return r.webhookConverter.MultipleToGraphQL(webhooks) 616 } 617 618 func extractApplicationNameFromTemplateInput(applicationInputJSON string) (string, error) { 619 b := []byte(applicationInputJSON) 620 data := make(map[string]interface{}) 621 622 err := json.Unmarshal(b, &data) 623 if err != nil { 624 return "", errors.Wrap(err, "while unmarshalling application input JSON") 625 } 626 627 return data["name"].(string), nil 628 } 629 630 func (r *Resolver) cleanupAndLogOnError(ctx context.Context, id, region string) { 631 if err := r.selfRegManager.CleanupSelfRegistration(ctx, id, region); err != nil { 632 log.C(ctx).Errorf("An error occurred during cleanup of self-registered app template: %v", err) 633 } 634 } 635 636 func (r *Resolver) retrieveAppTemplate(ctx context.Context, 637 appTemplateName, consumerID string, appTemplateID *string) (*model.ApplicationTemplate, error) { 638 filters := []*labelfilter.LabelFilter{ 639 labelfilter.NewForKeyWithQuery(globalSubaccountIDLabelKey, fmt.Sprintf("\"%s\"", consumerID)), 640 } 641 appTemplates, err := r.appTemplateSvc.ListByFilters(ctx, filters) 642 if err != nil { 643 return nil, err 644 } 645 646 for _, appTemplate := range appTemplates { 647 if (appTemplateID == nil && appTemplate.Name == appTemplateName) || 648 (appTemplateID != nil && *appTemplateID == appTemplate.ID) { 649 return appTemplate, nil 650 } 651 } 652 653 appTemplates, err = r.appTemplateSvc.ListByName(ctx, appTemplateName) 654 if err != nil { 655 return nil, err 656 } 657 templates := make([]*model.ApplicationTemplate, 0, len(appTemplates)) 658 for _, appTemplate := range appTemplates { 659 _, err := r.appTemplateSvc.GetLabel(ctx, appTemplate.ID, globalSubaccountIDLabelKey) 660 if err != nil && !apperrors.IsNotFoundError(err) { 661 return nil, errors.Wrapf(err, "while getting %q label", globalSubaccountIDLabelKey) 662 } 663 if err != nil && apperrors.IsNotFoundError(err) { 664 templates = append(templates, appTemplate) 665 } 666 } 667 668 if appTemplateID != nil { 669 log.C(ctx).Infof("searching for application template with ID: %s", *appTemplateID) 670 for _, appTemplate := range appTemplates { 671 if appTemplate.ID == *appTemplateID { 672 log.C(ctx).Infof("found application template with ID: %s", *appTemplateID) 673 return appTemplate, nil 674 } 675 } 676 return nil, errors.Errorf("application template with id %s and consumer id %q not found", *appTemplateID, consumerID) 677 } 678 if len(templates) < 1 { 679 return nil, errors.Errorf("application template with name %q and consumer id %q not found", appTemplateName, consumerID) 680 } 681 if len(templates) > 1 { 682 return nil, errors.Errorf("unexpected number of application templates. found %d", len(appTemplates)) 683 } 684 return templates[0], nil 685 } 686 687 func validateAppTemplateForSelfReg(applicationInput *graphql.ApplicationJSONInput) error { 688 appNameExists := applicationInput.Name != "" 689 var appDisplayNameLabelExists bool 690 691 if displayName, ok := applicationInput.Labels[displayNameLabelKey]; ok { 692 displayNameValue, ok := displayName.(string) 693 if !ok { 694 return fmt.Errorf("%q label value must be string", displayNameLabelKey) 695 } 696 appDisplayNameLabelExists = displayNameValue != "" 697 } 698 699 if !appNameExists || !appDisplayNameLabelExists { 700 return errors.Errorf("applicationInputJSON name property or applicationInputJSON displayName label is missing. They must be present in order to proceed.") 701 } 702 703 return nil 704 } 705 706 func validateAppTemplateNameBasedOnProvider(name string, appInput *graphql.ApplicationJSONInput) error { 707 if appInput == nil || appInput.ProviderName == nil || str.PtrStrToStr(appInput.ProviderName) != sapProviderName { 708 return nil 709 } 710 711 // Matches the following pattern - "SAP <product name>" 712 r := regexp.MustCompile(`(^SAP\s)([A-Za-z0-9()_\- ]*)`) 713 matches := r.FindStringSubmatch(name) 714 if len(matches) == 0 { 715 return errors.Errorf("application template name %q does not comply with the following naming convention: %q", name, "SAP <product name>") 716 } 717 718 return nil 719 } 720 721 func (r *Resolver) checkProviderAppTemplateExistence(ctx context.Context, labels map[string]interface{}) error { 722 selfRegisterDistinguishLabelKey := r.selfRegManager.GetSelfRegDistinguishingLabelKey() 723 regionLabelKey := selfregmanager.RegionLabel 724 region, regionExists := labels[regionLabelKey] 725 726 distinguishLabelKeys := []string{selfRegisterDistinguishLabelKey, r.appTemplateProductLabel} 727 appTemplateDistinguishLabels := make(map[string]interface{}, len(distinguishLabelKeys)) 728 729 for _, key := range distinguishLabelKeys { 730 if value, exists := labels[key]; exists { 731 appTemplateDistinguishLabels[key] = value 732 } 733 } 734 735 for labelKey, labelValue := range appTemplateDistinguishLabels { 736 msg := fmt.Sprintf("%q: %q", labelKey, labelValue) 737 738 filters := []*labelfilter.LabelFilter{ 739 labelfilter.NewForKeyWithQuery(labelKey, fmt.Sprintf("\"%s\"", labelValue)), 740 } 741 742 if regionExists { 743 if _, ok := region.(string); !ok { 744 return errors.Errorf("%s label should be string", regionLabelKey) 745 } 746 filters = append(filters, labelfilter.NewForKeyWithQuery(regionLabelKey, fmt.Sprintf("\"%s\"", region))) 747 msg += fmt.Sprintf(" and %q: %q", regionLabelKey, region) 748 } 749 750 log.C(ctx).Infof("Getting application template for labels %s", msg) 751 appTemplate, err := r.appTemplateSvc.GetByFilters(ctx, filters) 752 if err != nil && !apperrors.IsNotFoundError(err) { 753 return errors.Wrap(err, fmt.Sprintf("Failed to get application template for labels %s", msg)) 754 } 755 756 if appTemplate != nil { 757 errMsg := fmt.Sprintf("Cannot have more than one application template with labels %s", msg) 758 log.C(ctx).Error(errMsg) 759 return errors.New(errMsg) 760 } 761 } 762 return nil 763 } 764 765 func (r *Resolver) isSelfRegFlow(labels map[string]interface{}) (bool, error) { 766 selfRegLabelKey := r.selfRegManager.GetSelfRegDistinguishingLabelKey() 767 _, distinguishLabelExists := labels[selfRegLabelKey] 768 _, productLabelExists := labels[r.appTemplateProductLabel] 769 if !distinguishLabelExists && !productLabelExists { 770 return false, errors.Errorf("missing %q or %q label", selfRegLabelKey, r.appTemplateProductLabel) 771 } 772 773 if distinguishLabelExists && productLabelExists { 774 return false, errors.Errorf("should provide either %q or %q label - providing both at the same time is not allowed", selfRegLabelKey, r.appTemplateProductLabel) 775 } 776 777 if distinguishLabelExists { 778 return true, nil 779 } 780 781 return false, nil 782 }