blob: 89430ee815b2f5b082f5358fc9393fced264eae4 [file] [log] [blame]
// -
// ========================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
}