// - // ========================LICENSE_START================================= // O-RAN-SC // %% // Copyright (C) 2022: Nordix Foundation // %% // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========================LICENSE_END=================================== // package providermanagement import ( "net/http" "path" "strings" "sync" "github.com/labstack/echo/v4" "oransc.org/nonrtric/sme/internal/common29122" provapi "oransc.org/nonrtric/sme/internal/providermanagementapi" log "github.com/sirupsen/logrus" ) //go:generate mockery --name ServiceRegister type ServiceRegister interface { IsFunctionRegistered(aefId string) bool } type ProviderManager struct { onboardedProviders map[string]provapi.APIProviderEnrolmentDetails lock sync.Mutex } func NewProviderManager() *ProviderManager { return &ProviderManager{ onboardedProviders: make(map[string]provapi.APIProviderEnrolmentDetails), } } func (pm *ProviderManager) IsFunctionRegistered(aefId string) bool { registered := false out: for _, provider := range pm.onboardedProviders { for _, registeredFunc := range *provider.ApiProvFuncs { if *registeredFunc.ApiProvFuncId == aefId { registered = true break out } } } return registered } func (pm *ProviderManager) PostRegistrations(ctx echo.Context) error { var newProvider provapi.APIProviderEnrolmentDetails err := ctx.Bind(&newProvider) if err != nil { return sendCoreError(ctx, http.StatusBadRequest, "Invalid format for provider") } if newProvider.ApiProvDomInfo == nil || *newProvider.ApiProvDomInfo == "" { return sendCoreError(ctx, http.StatusBadRequest, "Provider missing required ApiProvDomInfo") } pm.lock.Lock() defer pm.lock.Unlock() newProvider.ApiProvDomId = pm.getDomainId(newProvider.ApiProvDomInfo) pm.registerFunctions(newProvider.ApiProvFuncs) pm.onboardedProviders[*newProvider.ApiProvDomId] = newProvider uri := ctx.Request().Host + ctx.Request().URL.String() ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, *newProvider.ApiProvDomId)) err = ctx.JSON(http.StatusCreated, newProvider) if err != nil { // Something really bad happened, tell Echo that our handler failed return err } return nil } func (pm *ProviderManager) DeleteRegistrationsRegistrationId(ctx echo.Context, registrationId string) error { pm.lock.Lock() defer pm.lock.Unlock() log.Debug(pm.onboardedProviders) if _, ok := pm.onboardedProviders[registrationId]; ok { log.Debug("Deleting provider", registrationId) delete(pm.onboardedProviders, registrationId) } return ctx.NoContent(http.StatusNoContent) } func (pm *ProviderManager) PutRegistrationsRegistrationId(ctx echo.Context, registrationId string) error { registeredProvider, ok := pm.onboardedProviders[registrationId] if !ok { return sendCoreError(ctx, http.StatusBadRequest, "Provider must be onboarded before updating it") } var updatedProvider provapi.APIProviderEnrolmentDetails err := ctx.Bind(&updatedProvider) if err != nil { return sendCoreError(ctx, http.StatusBadRequest, "Invalid format for provider") } for _, function := range *updatedProvider.ApiProvFuncs { if function.ApiProvFuncId == nil { function.ApiProvFuncId = pm.getFuncId(function.ApiProvFuncRole, function.ApiProvFuncInfo) registeredFuncs := *registeredProvider.ApiProvFuncs newFuncs := append(registeredFuncs, function) registeredProvider.ApiProvFuncs = &newFuncs pm.onboardedProviders[*registeredProvider.ApiProvDomId] = registeredProvider } } err = ctx.JSON(http.StatusOK, registeredProvider) if err != nil { // Something really bad happened, tell Echo that our handler failed return err } return nil } func (pm *ProviderManager) ModifyIndApiProviderEnrolment(ctx echo.Context, registrationId string) error { return ctx.NoContent(http.StatusNotImplemented) } func (pm *ProviderManager) registerFunctions(provFuncs *[]provapi.APIProviderFunctionDetails) { if provFuncs == nil { return } for i, provFunc := range *provFuncs { (*provFuncs)[i].ApiProvFuncId = pm.getFuncId(provFunc.ApiProvFuncRole, provFunc.ApiProvFuncInfo) } } func (pm *ProviderManager) getDomainId(domainInfo *string) *string { idAsString := "domain_id_" + strings.ReplaceAll(*domainInfo, " ", "_") return &idAsString } func (pm *ProviderManager) getFuncId(role provapi.ApiProviderFuncRole, funcInfo *string) *string { var idPrefix string switch role { case provapi.ApiProviderFuncRoleAPF: idPrefix = "APF_id_" case provapi.ApiProviderFuncRoleAMF: idPrefix = "AMF_id_" case provapi.ApiProviderFuncRoleAEF: idPrefix = "AEF_id_" default: idPrefix = "function_id_" } idAsString := idPrefix + strings.ReplaceAll(*funcInfo, " ", "_") return &idAsString } // This function wraps sending of an error in the Error format, and // handling the failure to marshal that. func sendCoreError(ctx echo.Context, code int, message string) error { pd := common29122.ProblemDetails{ Cause: &message, Status: &code, } err := ctx.JSON(code, pd) return err }