2 // ========================LICENSE_START=================================
5 // Copyright (C) 2022: Nordix Foundation
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 // ========================LICENSE_END===================================
21 package providermanagement
30 "github.com/labstack/echo/v4"
32 "oransc.org/nonrtric/capifcore/internal/common29122"
33 provapi "oransc.org/nonrtric/capifcore/internal/providermanagementapi"
35 log "github.com/sirupsen/logrus"
38 //go:generate mockery --name ServiceRegister
39 type ServiceRegister interface {
40 IsFunctionRegistered(functionId string) bool
41 GetAefsForPublisher(apfId string) []string
44 type ProviderManager struct {
45 onboardedProviders map[string]provapi.APIProviderEnrolmentDetails
49 func NewProviderManager() *ProviderManager {
50 return &ProviderManager{
51 onboardedProviders: make(map[string]provapi.APIProviderEnrolmentDetails),
55 func (pm *ProviderManager) IsFunctionRegistered(functionId string) bool {
58 for _, provider := range pm.onboardedProviders {
59 for _, registeredFunc := range *provider.ApiProvFuncs {
60 if *registeredFunc.ApiProvFuncId == functionId {
70 func (pm *ProviderManager) GetAefsForPublisher(apfId string) []string {
71 for _, provider := range pm.onboardedProviders {
72 for _, registeredFunc := range *provider.ApiProvFuncs {
73 if *registeredFunc.ApiProvFuncId == apfId && registeredFunc.ApiProvFuncRole == provapi.ApiProviderFuncRoleAPF {
74 return getExposedFuncs(provider.ApiProvFuncs)
81 func getExposedFuncs(providerFuncs *[]provapi.APIProviderFunctionDetails) []string {
82 exposedFuncs := []string{}
83 for _, registeredFunc := range *providerFuncs {
84 if registeredFunc.ApiProvFuncRole == provapi.ApiProviderFuncRoleAEF {
85 exposedFuncs = append(exposedFuncs, *registeredFunc.ApiProvFuncId)
91 func (pm *ProviderManager) PostRegistrations(ctx echo.Context) error {
92 var newProvider provapi.APIProviderEnrolmentDetails
93 err := ctx.Bind(&newProvider)
95 return sendCoreError(ctx, http.StatusBadRequest, "Invalid format for provider")
98 if newProvider.ApiProvDomInfo == nil || *newProvider.ApiProvDomInfo == "" {
99 return sendCoreError(ctx, http.StatusBadRequest, "Provider missing required ApiProvDomInfo")
103 defer pm.lock.Unlock()
105 newProvider.ApiProvDomId = pm.getDomainId(newProvider.ApiProvDomInfo)
107 pm.registerFunctions(newProvider.ApiProvFuncs)
108 pm.onboardedProviders[*newProvider.ApiProvDomId] = newProvider
110 uri := ctx.Request().Host + ctx.Request().URL.String()
111 ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, *newProvider.ApiProvDomId))
112 err = ctx.JSON(http.StatusCreated, newProvider)
114 // Something really bad happened, tell Echo that our handler failed
121 func (pm *ProviderManager) DeleteRegistrationsRegistrationId(ctx echo.Context, registrationId string) error {
123 defer pm.lock.Unlock()
125 log.Debug(pm.onboardedProviders)
126 if _, ok := pm.onboardedProviders[registrationId]; ok {
127 log.Debug("Deleting provider", registrationId)
128 delete(pm.onboardedProviders, registrationId)
131 return ctx.NoContent(http.StatusNoContent)
134 func (pm *ProviderManager) PutRegistrationsRegistrationId(ctx echo.Context, registrationId string) error {
136 defer pm.lock.Unlock()
138 registeredProvider, shouldReturn, returnValue := pm.checkIfProviderIsRegistered(registrationId, ctx)
143 updatedProvider, shouldReturn1, returnValue1 := getProviderFromRequest(ctx)
148 if updatedProvider.ApiProvDomInfo != nil {
149 registeredProvider.ApiProvDomInfo = updatedProvider.ApiProvDomInfo
152 shouldReturn, returnValue = pm.updateFunctions(updatedProvider, registeredProvider, ctx)
157 err := ctx.JSON(http.StatusOK, pm.onboardedProviders[registrationId])
159 // Something really bad happened, tell Echo that our handler failed
166 func (pm *ProviderManager) checkIfProviderIsRegistered(registrationId string, ctx echo.Context) (provapi.APIProviderEnrolmentDetails, bool, error) {
167 registeredProvider, ok := pm.onboardedProviders[registrationId]
169 return provapi.APIProviderEnrolmentDetails{}, true, sendCoreError(ctx, http.StatusBadRequest, "Provider must be onboarded before updating it")
171 return registeredProvider, false, nil
174 func getProviderFromRequest(ctx echo.Context) (provapi.APIProviderEnrolmentDetails, bool, error) {
175 var updatedProvider provapi.APIProviderEnrolmentDetails
176 err := ctx.Bind(&updatedProvider)
178 return provapi.APIProviderEnrolmentDetails{}, true, sendCoreError(ctx, http.StatusBadRequest, "Invalid format for provider")
180 return updatedProvider, false, nil
183 func (pm *ProviderManager) updateFunctions(updatedProvider provapi.APIProviderEnrolmentDetails, registeredProvider provapi.APIProviderEnrolmentDetails, ctx echo.Context) (bool, error) {
184 for _, function := range *updatedProvider.ApiProvFuncs {
185 if function.ApiProvFuncId == nil {
186 pm.addFunction(function, registeredProvider)
188 shouldReturn, returnValue := pm.updateFunction(function, registeredProvider, ctx)
190 return true, returnValue
197 func (pm *ProviderManager) addFunction(function provapi.APIProviderFunctionDetails, registeredProvider provapi.APIProviderEnrolmentDetails) {
198 function.ApiProvFuncId = pm.getFuncId(function.ApiProvFuncRole, function.ApiProvFuncInfo)
199 registeredFuncs := *registeredProvider.ApiProvFuncs
200 newFuncs := append(registeredFuncs, function)
201 registeredProvider.ApiProvFuncs = &newFuncs
202 pm.onboardedProviders[*registeredProvider.ApiProvDomId] = registeredProvider
205 func (*ProviderManager) updateFunction(function provapi.APIProviderFunctionDetails, registeredProvider provapi.APIProviderEnrolmentDetails, ctx echo.Context) (bool, error) {
206 pos, registeredFunction, err := getApiFunc(*function.ApiProvFuncId, registeredProvider.ApiProvFuncs)
208 return true, sendCoreError(ctx, http.StatusBadRequest, "Unable to update provider due to: "+err.Error())
210 if function.ApiProvFuncInfo != nil {
211 registeredFunction.ApiProvFuncInfo = function.ApiProvFuncInfo
212 (*registeredProvider.ApiProvFuncs)[pos] = registeredFunction
217 func getApiFunc(funcId string, apiFunctions *[]provapi.APIProviderFunctionDetails) (int, provapi.APIProviderFunctionDetails, error) {
218 for pos, function := range *apiFunctions {
219 if *function.ApiProvFuncId == funcId {
220 return pos, function, nil
223 return 0, provapi.APIProviderFunctionDetails{}, fmt.Errorf("function with ID %s is not registered for the provider", funcId)
226 func (pm *ProviderManager) ModifyIndApiProviderEnrolment(ctx echo.Context, registrationId string) error {
227 return ctx.NoContent(http.StatusNotImplemented)
230 func (pm *ProviderManager) registerFunctions(provFuncs *[]provapi.APIProviderFunctionDetails) {
231 if provFuncs == nil {
234 for i, provFunc := range *provFuncs {
235 (*provFuncs)[i].ApiProvFuncId = pm.getFuncId(provFunc.ApiProvFuncRole, provFunc.ApiProvFuncInfo)
239 func (pm *ProviderManager) getDomainId(domainInfo *string) *string {
240 idAsString := "domain_id_" + strings.ReplaceAll(*domainInfo, " ", "_")
244 func (pm *ProviderManager) getFuncId(role provapi.ApiProviderFuncRole, funcInfo *string) *string {
247 case provapi.ApiProviderFuncRoleAPF:
249 case provapi.ApiProviderFuncRoleAMF:
251 case provapi.ApiProviderFuncRoleAEF:
254 idPrefix = "function_id_"
256 idAsString := idPrefix + strings.ReplaceAll(*funcInfo, " ", "_")
260 // This function wraps sending of an error in the Error format, and
261 // handling the failure to marshal that.
262 func sendCoreError(ctx echo.Context, code int, message string) error {
263 pd := common29122.ProblemDetails{
267 err := ctx.JSON(code, pd)