b9579611e5ecf9b4484a949b0a4d9733926aee3f
[nonrtric/plt/sme.git] / capifcore / internal / providermanagement / providermanagement.go
1 // -
2 //   ========================LICENSE_START=================================
3 //   O-RAN-SC
4 //   %%
5 //   Copyright (C) 2022: Nordix Foundation
6 //   %%
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
10 //
11 //        http://www.apache.org/licenses/LICENSE-2.0
12 //
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===================================
19 //
20
21 package providermanagement
22
23 import (
24         "net/http"
25         "path"
26         "strings"
27         "sync"
28
29         "github.com/labstack/echo/v4"
30
31         "oransc.org/nonrtric/capifcore/internal/common29122"
32         provapi "oransc.org/nonrtric/capifcore/internal/providermanagementapi"
33
34         log "github.com/sirupsen/logrus"
35 )
36
37 //go:generate mockery --name ServiceRegister
38 type ServiceRegister interface {
39         IsFunctionRegistered(aefId string) bool
40 }
41
42 type ProviderManager struct {
43         onboardedProviders map[string]provapi.APIProviderEnrolmentDetails
44         lock               sync.Mutex
45 }
46
47 func NewProviderManager() *ProviderManager {
48         return &ProviderManager{
49                 onboardedProviders: make(map[string]provapi.APIProviderEnrolmentDetails),
50         }
51 }
52
53 func (pm *ProviderManager) IsFunctionRegistered(aefId string) bool {
54         registered := false
55 out:
56         for _, provider := range pm.onboardedProviders {
57                 for _, registeredFunc := range *provider.ApiProvFuncs {
58                         if *registeredFunc.ApiProvFuncId == aefId {
59                                 registered = true
60                                 break out
61                         }
62                 }
63         }
64
65         return registered
66 }
67
68 func (pm *ProviderManager) PostRegistrations(ctx echo.Context) error {
69         var newProvider provapi.APIProviderEnrolmentDetails
70         err := ctx.Bind(&newProvider)
71         if err != nil {
72                 return sendCoreError(ctx, http.StatusBadRequest, "Invalid format for provider")
73         }
74
75         if newProvider.ApiProvDomInfo == nil || *newProvider.ApiProvDomInfo == "" {
76                 return sendCoreError(ctx, http.StatusBadRequest, "Provider missing required ApiProvDomInfo")
77         }
78
79         pm.lock.Lock()
80         defer pm.lock.Unlock()
81
82         newProvider.ApiProvDomId = pm.getDomainId(newProvider.ApiProvDomInfo)
83
84         pm.registerFunctions(newProvider.ApiProvFuncs)
85         pm.onboardedProviders[*newProvider.ApiProvDomId] = newProvider
86
87         uri := ctx.Request().Host + ctx.Request().URL.String()
88         ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, *newProvider.ApiProvDomId))
89         err = ctx.JSON(http.StatusCreated, newProvider)
90         if err != nil {
91                 // Something really bad happened, tell Echo that our handler failed
92                 return err
93         }
94
95         return nil
96 }
97
98 func (pm *ProviderManager) DeleteRegistrationsRegistrationId(ctx echo.Context, registrationId string) error {
99         pm.lock.Lock()
100         defer pm.lock.Unlock()
101
102         log.Debug(pm.onboardedProviders)
103         if _, ok := pm.onboardedProviders[registrationId]; ok {
104                 log.Debug("Deleting provider", registrationId)
105                 delete(pm.onboardedProviders, registrationId)
106         }
107
108         return ctx.NoContent(http.StatusNoContent)
109 }
110
111 func (pm *ProviderManager) PutRegistrationsRegistrationId(ctx echo.Context, registrationId string) error {
112         registeredProvider, ok := pm.onboardedProviders[registrationId]
113         if !ok {
114                 return sendCoreError(ctx, http.StatusBadRequest, "Provider must be onboarded before updating it")
115
116         }
117
118         var updatedProvider provapi.APIProviderEnrolmentDetails
119         err := ctx.Bind(&updatedProvider)
120         if err != nil {
121                 return sendCoreError(ctx, http.StatusBadRequest, "Invalid format for provider")
122         }
123
124         pm.lock.Lock()
125         defer pm.lock.Unlock()
126
127         for _, function := range *updatedProvider.ApiProvFuncs {
128                 if function.ApiProvFuncId == nil {
129                         function.ApiProvFuncId = pm.getFuncId(function.ApiProvFuncRole, function.ApiProvFuncInfo)
130                         registeredFuncs := *registeredProvider.ApiProvFuncs
131                         newFuncs := append(registeredFuncs, function)
132                         registeredProvider.ApiProvFuncs = &newFuncs
133                         pm.onboardedProviders[*registeredProvider.ApiProvDomId] = registeredProvider
134                 }
135         }
136
137         err = ctx.JSON(http.StatusOK, registeredProvider)
138         if err != nil {
139                 // Something really bad happened, tell Echo that our handler failed
140                 return err
141         }
142
143         return nil
144 }
145
146 func (pm *ProviderManager) ModifyIndApiProviderEnrolment(ctx echo.Context, registrationId string) error {
147         return ctx.NoContent(http.StatusNotImplemented)
148 }
149
150 func (pm *ProviderManager) registerFunctions(provFuncs *[]provapi.APIProviderFunctionDetails) {
151         if provFuncs == nil {
152                 return
153         }
154         for i, provFunc := range *provFuncs {
155                 (*provFuncs)[i].ApiProvFuncId = pm.getFuncId(provFunc.ApiProvFuncRole, provFunc.ApiProvFuncInfo)
156         }
157 }
158
159 func (pm *ProviderManager) getDomainId(domainInfo *string) *string {
160         idAsString := "domain_id_" + strings.ReplaceAll(*domainInfo, " ", "_")
161         return &idAsString
162 }
163
164 func (pm *ProviderManager) getFuncId(role provapi.ApiProviderFuncRole, funcInfo *string) *string {
165         var idPrefix string
166         switch role {
167         case provapi.ApiProviderFuncRoleAPF:
168                 idPrefix = "APF_id_"
169         case provapi.ApiProviderFuncRoleAMF:
170                 idPrefix = "AMF_id_"
171         case provapi.ApiProviderFuncRoleAEF:
172                 idPrefix = "AEF_id_"
173         default:
174                 idPrefix = "function_id_"
175         }
176         idAsString := idPrefix + strings.ReplaceAll(*funcInfo, " ", "_")
177         return &idAsString
178 }
179
180 // This function wraps sending of an error in the Error format, and
181 // handling the failure to marshal that.
182 func sendCoreError(ctx echo.Context, code int, message string) error {
183         pd := common29122.ProblemDetails{
184                 Cause:  &message,
185                 Status: &code,
186         }
187         err := ctx.JSON(code, pd)
188         return err
189 }