ebdfa9a217e784236df0ee82b3f2a83fa3f24cf3
[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         "fmt"
25         "net/http"
26         "path"
27         "sync"
28
29         echo "github.com/labstack/echo/v4"
30         log "github.com/sirupsen/logrus"
31
32         "oransc.org/nonrtric/capifcore/internal/common29122"
33         provapi "oransc.org/nonrtric/capifcore/internal/providermanagementapi"
34 )
35
36 //go:generate mockery --name ServiceRegister
37 type ServiceRegister interface {
38         IsFunctionRegistered(functionId string) bool
39         GetAefsForPublisher(apfId string) []string
40         IsPublishingFunctionRegistered(apiProvFuncId string) bool
41 }
42
43 type ProviderManager struct {
44         registeredProviders map[string]provapi.APIProviderEnrolmentDetails
45         lock                sync.Mutex
46 }
47
48 func NewProviderManager() *ProviderManager {
49         return &ProviderManager{
50                 registeredProviders: make(map[string]provapi.APIProviderEnrolmentDetails),
51         }
52 }
53
54 func (pm *ProviderManager) IsFunctionRegistered(functionId string) bool {
55         for _, provider := range pm.registeredProviders {
56                 if provider.IsFunctionRegistered(functionId) {
57                         return true
58                 }
59         }
60         return false
61 }
62
63 func (pm *ProviderManager) GetAefsForPublisher(apfId string) []string {
64         for _, provider := range pm.registeredProviders {
65                 if aefs := provider.GetExposingFunctionIdsForPublisher(apfId); aefs != nil {
66                         return aefs
67                 }
68         }
69         return nil
70 }
71
72 func (pm *ProviderManager) IsPublishingFunctionRegistered(apiProvFuncId string) bool {
73         for _, provider := range pm.registeredProviders {
74                 if provider.IsPublishingFunctionRegistered(apiProvFuncId) {
75                         return true
76                 }
77         }
78         return false
79 }
80
81 func (pm *ProviderManager) PostRegistrations(ctx echo.Context) error {
82         var newProvider provapi.APIProviderEnrolmentDetails
83         errMsg := "Unable to register provider due to %s"
84         if err := ctx.Bind(&newProvider); err != nil {
85                 return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, "invalid format for provider"))
86         }
87
88         if err := pm.isProviderRegistered(newProvider); err != nil {
89                 return sendCoreError(ctx, http.StatusForbidden, fmt.Sprintf(errMsg, err))
90         }
91
92         if err := newProvider.Validate(); err != nil {
93                 return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err))
94         }
95
96         pm.prepareNewProvider(&newProvider)
97
98         uri := ctx.Request().Host + ctx.Request().URL.String()
99         ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, *newProvider.ApiProvDomId))
100         if err := ctx.JSON(http.StatusCreated, newProvider); err != nil {
101                 // Something really bad happened, tell Echo that our handler failed
102                 return err
103         }
104         return nil
105 }
106
107 func (pm *ProviderManager) isProviderRegistered(newProvider provapi.APIProviderEnrolmentDetails) error {
108         for _, prov := range pm.registeredProviders {
109                 if err := prov.ValidateAlreadyRegistered(newProvider); err != nil {
110                         return err
111                 }
112         }
113         return nil
114 }
115
116 func (pm *ProviderManager) prepareNewProvider(newProvider *provapi.APIProviderEnrolmentDetails) {
117         pm.lock.Lock()
118         defer pm.lock.Unlock()
119
120         newProvider.PrepareNewProvider()
121         pm.registeredProviders[*newProvider.ApiProvDomId] = *newProvider
122 }
123
124 func (pm *ProviderManager) DeleteRegistrationsRegistrationId(ctx echo.Context, registrationId string) error {
125         log.Debug(pm.registeredProviders)
126         if _, ok := pm.registeredProviders[registrationId]; ok {
127                 pm.deleteProvider(registrationId)
128         }
129         return ctx.NoContent(http.StatusNoContent)
130 }
131
132 func (pm *ProviderManager) deleteProvider(registrationId string) {
133         log.Debug("Deleting provider", registrationId)
134         pm.lock.Lock()
135         defer pm.lock.Unlock()
136         delete(pm.registeredProviders, registrationId)
137 }
138
139 func (pm *ProviderManager) PutRegistrationsRegistrationId(ctx echo.Context, registrationId string) error {
140         errMsg := "Unable to update provider due to %s."
141         registeredProvider, err := pm.checkIfProviderIsRegistered(registrationId, ctx)
142         if err != nil {
143                 return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err))
144         }
145
146         updatedProvider, err := getProviderFromRequest(ctx)
147         if err != nil {
148                 return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err))
149         }
150
151         if updatedProvider.Validate() != nil {
152                 return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err))
153         }
154
155         // Additional validation for PUT
156         if (updatedProvider.ApiProvDomId == nil) || (*updatedProvider.ApiProvDomId != registrationId) {
157                 errDetail := "APIProviderEnrolmentDetails ApiProvDomId doesn't match path parameter"
158                 return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, errDetail))
159         }
160
161         if err = pm.updateProvider(updatedProvider, registeredProvider); err != nil {
162                 return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err))
163         }
164
165         if err = ctx.JSON(http.StatusOK, updatedProvider); err != nil {
166                 // Something really bad happened, tell Echo that our handler failed
167                 return err
168         }
169         return nil
170 }
171
172 func (pm *ProviderManager) ModifyIndApiProviderEnrolment(ctx echo.Context, registrationId string) error {
173         return ctx.NoContent(http.StatusNotImplemented)
174 }
175
176 func (pm *ProviderManager) checkIfProviderIsRegistered(registrationId string, ctx echo.Context) (*provapi.APIProviderEnrolmentDetails, error) {
177         registeredProvider, ok := pm.registeredProviders[registrationId]
178         if !ok {
179                 return nil, fmt.Errorf("provider not onboarded")
180         }
181         return &registeredProvider, nil
182 }
183
184 func getProviderFromRequest(ctx echo.Context) (provapi.APIProviderEnrolmentDetails, error) {
185         var updatedProvider provapi.APIProviderEnrolmentDetails
186         err := ctx.Bind(&updatedProvider)
187         if err != nil {
188                 return provapi.APIProviderEnrolmentDetails{}, fmt.Errorf("invalid format for provider")
189         }
190         return updatedProvider, nil
191 }
192
193 func (pm *ProviderManager) updateProvider(updatedProvider provapi.APIProviderEnrolmentDetails, registeredProvider *provapi.APIProviderEnrolmentDetails) error {
194         pm.lock.Lock()
195         defer pm.lock.Unlock()
196
197         if err := updatedProvider.UpdateFuncs(*registeredProvider); err == nil {
198                 pm.registeredProviders[*updatedProvider.ApiProvDomId] = updatedProvider
199                 return nil
200         } else {
201                 return err
202         }
203 }
204
205 // This function wraps sending of an error in the Error format, and
206 // handling the failure to marshal that.
207 func sendCoreError(ctx echo.Context, code int, message string) error {
208         pd := common29122.ProblemDetails{
209                 Cause:  &message,
210                 Status: &code,
211         }
212         err := ctx.JSON(code, pd)
213         return err
214 }