X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=capifcore%2Finternal%2Fpublishservice%2Fpublishservice.go;h=5cea538f1f59f76dcbefa8aad33571fea1f0b0dc;hb=f62685e5a2187fb58c7f27cdd1f14dd2c152880d;hp=2314039aeacbf5eb42c70471f1daa29ffa3b5238;hpb=0b4c4ecb52b1c04037a65644dc8c6c29981d9736;p=nonrtric%2Fplt%2Fsme.git diff --git a/capifcore/internal/publishservice/publishservice.go b/capifcore/internal/publishservice/publishservice.go index 2314039..5cea538 100644 --- a/capifcore/internal/publishservice/publishservice.go +++ b/capifcore/internal/publishservice/publishservice.go @@ -31,6 +31,7 @@ import ( "k8s.io/utils/strings/slices" "oransc.org/nonrtric/capifcore/internal/common29122" + "oransc.org/nonrtric/capifcore/internal/eventsapi" publishapi "oransc.org/nonrtric/capifcore/internal/publishserviceapi" "oransc.org/nonrtric/capifcore/internal/helmmanagement" @@ -56,15 +57,17 @@ type PublishService struct { publishedServices map[string][]publishapi.ServiceAPIDescription serviceRegister providermanagement.ServiceRegister helmManager helmmanagement.HelmManager + eventChannel chan<- eventsapi.EventNotification lock sync.Mutex } // Creates a service that implements both the PublishRegister and the publishserviceapi.ServerInterface interfaces. -func NewPublishService(serviceRegister providermanagement.ServiceRegister, hm helmmanagement.HelmManager) *PublishService { +func NewPublishService(serviceRegister providermanagement.ServiceRegister, hm helmmanagement.HelmManager, eventChannel chan<- eventsapi.EventNotification) *PublishService { return &PublishService{ helmManager: hm, publishedServices: make(map[string][]publishapi.ServiceAPIDescription), serviceRegister: serviceRegister, + eventChannel: eventChannel, } } @@ -155,18 +158,26 @@ func (ps *PublishService) GetApfIdServiceApis(ctx echo.Context, apfId string) er // Publish a new API. func (ps *PublishService) PostApfIdServiceApis(ctx echo.Context, apfId string) error { var newServiceAPIDescription publishapi.ServiceAPIDescription + errorMsg := "Unable to publish the service due to %s " err := ctx.Bind(&newServiceAPIDescription) if err != nil { - return sendCoreError(ctx, http.StatusBadRequest, "Invalid format for service "+apfId) + return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errorMsg, "invalid format for service "+apfId)) } + if ps.isServicePublished(newServiceAPIDescription) { + return sendCoreError(ctx, http.StatusForbidden, fmt.Sprintf(errorMsg, "service already published")) + } + + if err := newServiceAPIDescription.Validate(); err != nil { + return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errorMsg, err)) + } ps.lock.Lock() defer ps.lock.Unlock() registeredFuncs := ps.serviceRegister.GetAefsForPublisher(apfId) for _, profile := range *newServiceAPIDescription.AefProfiles { if !slices.Contains(registeredFuncs, profile.AefId) { - return sendCoreError(ctx, http.StatusNotFound, fmt.Sprintf("Function %s not registered", profile.AefId)) + return sendCoreError(ctx, http.StatusNotFound, fmt.Sprintf(errorMsg, fmt.Sprintf("function %s not registered", profile.AefId))) } } @@ -177,6 +188,7 @@ func (ps *PublishService) PostApfIdServiceApis(ctx echo.Context, apfId string) e if shouldReturn { return returnValue } + go ps.sendEvent(newServiceAPIDescription, eventsapi.CAPIFEventSERVICEAPIAVAILABLE) _, ok := ps.publishedServices[apfId] if ok { @@ -196,6 +208,17 @@ func (ps *PublishService) PostApfIdServiceApis(ctx echo.Context, apfId string) e return nil } +func (ps *PublishService) isServicePublished(newService publishapi.ServiceAPIDescription) bool { + for _, services := range ps.publishedServices { + for _, service := range services { + if newService.ApiName == service.ApiName { + return true + } + } + } + return false +} + func (ps *PublishService) installHelmChart(newServiceAPIDescription publishapi.ServiceAPIDescription, ctx echo.Context) (bool, error) { info := strings.Split(*newServiceAPIDescription.Description, ",") if len(info) == 5 { @@ -220,8 +243,9 @@ func (ps *PublishService) DeleteApfIdServiceApisServiceApiId(ctx echo.Context, a log.Debug("Deleted service: ", serviceApiId) } ps.lock.Lock() - defer ps.lock.Unlock() ps.publishedServices[string(apfId)] = removeServiceDescription(pos, serviceDescriptions) + ps.lock.Unlock() + go ps.sendEvent(*description, eventsapi.CAPIFEventSERVICEAPIUNAVAILABLE) } } return ctx.NoContent(http.StatusNoContent) @@ -230,9 +254,9 @@ func (ps *PublishService) DeleteApfIdServiceApisServiceApiId(ctx echo.Context, a // Retrieve a published service API. func (ps *PublishService) GetApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error { ps.lock.Lock() - defer ps.lock.Unlock() - serviceDescriptions, ok := ps.publishedServices[apfId] + ps.lock.Unlock() + if ok { _, serviceDescription := getServiceDescription(serviceApiId, serviceDescriptions) if serviceDescription == nil { @@ -272,7 +296,80 @@ func (ps *PublishService) ModifyIndAPFPubAPI(ctx echo.Context, apfId string, ser // Update a published service API. func (ps *PublishService) PutApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error { - return ctx.NoContent(http.StatusNotImplemented) + ps.lock.Lock() + defer ps.lock.Unlock() + errMsg := "Unable to update service due to %s." + pos, publishedService, err := ps.checkIfServiceIsPublished(apfId, serviceApiId, ctx) + if err != nil { + return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err)) + } + updatedServiceDescription, err := getServiceFromRequest(ctx) + if err != nil { + return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err)) + } + ps.updateDescription(pos, apfId, &updatedServiceDescription, &publishedService) + err = ps.checkProfilesRegistered(apfId, *updatedServiceDescription.AefProfiles) + if err != nil { + return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err)) + } + publishedService.AefProfiles = updatedServiceDescription.AefProfiles + ps.publishedServices[apfId][pos] = publishedService + err = ctx.JSON(http.StatusOK, publishedService) + if err != nil { + // Something really bad happened, tell Echo that our handler failed + return err + } + return nil +} +func (ps *PublishService) checkIfServiceIsPublished(apfId string, serviceApiId string, ctx echo.Context) (int, publishapi.ServiceAPIDescription, error) { + publishedServices, ok := ps.publishedServices[apfId] + if !ok { + return 0, publishapi.ServiceAPIDescription{}, fmt.Errorf("service must be published before updating it") + } else { + for pos, description := range publishedServices { + if *description.ApiId == serviceApiId { + return pos, description, nil + } + } + } + return 0, publishapi.ServiceAPIDescription{}, fmt.Errorf("service must be published before updating it") +} +func getServiceFromRequest(ctx echo.Context) (publishapi.ServiceAPIDescription, error) { + var updatedServiceDescription publishapi.ServiceAPIDescription + err := ctx.Bind(&updatedServiceDescription) + if err != nil { + return publishapi.ServiceAPIDescription{}, fmt.Errorf("invalid format for service") + } + return updatedServiceDescription, nil +} +func (ps *PublishService) updateDescription(pos int, apfId string, updatedServiceDescription, publishedService *publishapi.ServiceAPIDescription) { + if updatedServiceDescription.Description != nil { + publishedService.Description = updatedServiceDescription.Description + go ps.sendEvent(*publishedService, eventsapi.CAPIFEventSERVICEAPIUPDATE) + } +} + +func (ps *PublishService) sendEvent(service publishapi.ServiceAPIDescription, eventType eventsapi.CAPIFEvent) { + apiIds := []string{*service.ApiId} + apis := []publishapi.ServiceAPIDescription{service} + event := eventsapi.EventNotification{ + EventDetail: &eventsapi.CAPIFEventDetail{ + ApiIds: &apiIds, + ServiceAPIDescriptions: &apis, + }, + Events: eventType, + } + ps.eventChannel <- event +} + +func (ps *PublishService) checkProfilesRegistered(apfId string, updatedProfiles []publishapi.AefProfile) error { + registeredFuncs := ps.serviceRegister.GetAefsForPublisher(apfId) + for _, profile := range updatedProfiles { + if !slices.Contains(registeredFuncs, profile.AefId) { + return fmt.Errorf("function %s not registered", profile.AefId) + } + } + return nil } // This function wraps sending of an error in the Error format, and