2 // ========================LICENSE_START=================================
5 // Copyright (C) 2023-2024: OpenInfra Foundation Europe
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 publishservice
29 echo "github.com/labstack/echo/v4"
30 log "github.com/sirupsen/logrus"
32 "oransc.org/nonrtric/servicemanager/internal/common29122"
33 publishapi "oransc.org/nonrtric/servicemanager/internal/publishserviceapi"
36 type PublishService struct {
39 KongIPv4 common29122.Ipv4Addr;
40 KongDataPlanePort common29122.Port;
41 KongControlPlanePort common29122.Port;
43 CapifIPv4 common29122.Ipv4Addr;
44 CapifPort common29122.Port;
47 // Creates a service that implements both the PublishRegister and the publishserviceapi.ServerInterface interfaces.
48 func NewPublishService(kongDomain string, kongProtocol string, kongIPv4 common29122.Ipv4Addr, kongDataPlanePort common29122.Port, kongControlPlanePort common29122.Port, capifProtocol string, capifIPv4 common29122.Ipv4Addr, capifPort common29122.Port) *PublishService {
49 return &PublishService{
50 KongDomain : kongDomain,
51 KongProtocol : kongProtocol,
53 KongDataPlanePort : kongDataPlanePort,
54 KongControlPlanePort : kongControlPlanePort,
55 CapifProtocol : capifProtocol,
56 CapifIPv4 : capifIPv4,
57 CapifPort : capifPort,
62 func (ps *PublishService) PostApfIdServiceApis(ctx echo.Context, apfId string) error {
63 log.Tracef("entering PostApfIdServiceApis apfId %s", apfId)
65 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
66 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
72 ctxHandler context.Context
73 cancel context.CancelFunc
75 ctxHandler, cancel = context.WithCancel(context.Background())
78 newServiceAPIDescription, err := getServiceFromRequest(ctx)
83 newServiceAPIDescription.PrepareNewService()
85 statusCode, err := newServiceAPIDescription.RegisterKong(ps.KongDomain, ps.KongProtocol, ps.KongIPv4, ps.KongDataPlanePort, ps.KongControlPlanePort)
86 if (err != nil) || (statusCode != http.StatusCreated) {
87 // We can return with http.StatusForbidden if there is a http.StatusConflict detected by Kong
89 log.Errorf("error on RegisterKong %s", msg)
90 return sendCoreError(ctx, statusCode, msg)
93 bodyServiceAPIDescription := publishapi.PostApfIdServiceApisJSONRequestBody(newServiceAPIDescription)
94 var rsp *publishapi.PostApfIdServiceApisResponse
96 log.Trace("calling PostApfIdServiceApisWithResponse")
97 rsp, err = client.PostApfIdServiceApisWithResponse(ctxHandler, apfId, bodyServiceAPIDescription)
101 log.Errorf("error on PostApfIdServiceApisWithResponse %s", msg)
102 return sendCoreError(ctx, http.StatusInternalServerError, msg)
105 if rsp.StatusCode() != http.StatusCreated {
106 msg := string(rsp.Body)
107 log.Debugf("PostApfIdServiceApisWithResponse status code %d", rsp.StatusCode())
108 log.Debugf("PostApfIdServiceApisWithResponse error %s", msg)
109 if rsp.StatusCode() == http.StatusForbidden || rsp.StatusCode() == http.StatusBadRequest {
110 newServiceAPIDescription.UnregisterKong(ps.KongDomain, ps.KongProtocol, ps.KongIPv4, ps.KongDataPlanePort, ps.KongControlPlanePort)
112 return sendCoreError(ctx, rsp.StatusCode(), msg)
115 rspServiceAPIDescription := *rsp.JSON201
116 apiId := *rspServiceAPIDescription.ApiId
118 uri := ctx.Request().Host + ctx.Request().URL.String()
119 ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, apiId))
121 err = ctx.JSON(http.StatusCreated, rspServiceAPIDescription)
123 return err // Tell Echo that our handler failed
130 // Unpublish a published service API.
131 func (ps *PublishService) DeleteApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error {
132 log.Tracef("entering DeleteApfIdServiceApisServiceApiId apfId %s serviceApiId %s", apfId, serviceApiId)
134 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
135 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
141 ctxHandler context.Context
142 cancel context.CancelFunc
144 ctxHandler, cancel = context.WithCancel(context.Background())
147 log.Debugf("call GetApfIdServiceApisServiceApiIdWithResponse before delete apfId %s serviceApiId %s", apfId, serviceApiId)
148 var rsp *publishapi.GetApfIdServiceApisServiceApiIdResponse
149 rsp, err = client.GetApfIdServiceApisServiceApiIdWithResponse(ctxHandler, apfId, serviceApiId)
153 log.Errorf("error on GetApfIdServiceApisServiceApiIdWithResponse %s", msg)
154 return sendCoreError(ctx, http.StatusInternalServerError, msg)
157 statusCode := rsp.StatusCode()
158 if statusCode != http.StatusOK {
159 log.Debugf("GetApfIdServiceApisServiceApiIdWithResponse status %d", statusCode)
160 return ctx.NoContent(statusCode)
163 rspServiceAPIDescription := *rsp.JSON200
164 statusCode, err = rspServiceAPIDescription.UnregisterKong(ps.KongDomain, ps.KongProtocol, ps.KongIPv4, ps.KongDataPlanePort, ps.KongControlPlanePort)
165 if (err != nil) || (statusCode != http.StatusNoContent) {
167 log.Errorf("error on UnregisterKong %s", msg)
168 return sendCoreError(ctx, statusCode, msg)
171 log.Trace("call DeleteApfIdServiceApisServiceApiIdWithResponse")
172 _, err = client.DeleteApfIdServiceApisServiceApiIdWithResponse(ctxHandler, apfId, serviceApiId)
176 log.Errorf("error on DeleteApfIdServiceApisServiceApiIdWithResponse %s", msg)
177 return sendCoreError(ctx, http.StatusInternalServerError, msg)
180 return ctx.NoContent(http.StatusNoContent)
183 // Retrieve all published APIs.
184 func (ps *PublishService) GetApfIdServiceApis(ctx echo.Context, apfId string) error {
185 log.Tracef("entering GetApfIdServiceApis apfId %s", apfId)
187 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
188 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
194 ctxHandler context.Context
195 cancel context.CancelFunc
197 ctxHandler, cancel = context.WithCancel(context.Background())
200 var rsp *publishapi.GetApfIdServiceApisResponse
201 rsp, err = client.GetApfIdServiceApisWithResponse(ctxHandler, apfId)
205 log.Errorf("error on GetApfIdServiceApisWithResponse %s", msg)
206 return sendCoreError(ctx, http.StatusInternalServerError, msg)
209 if rsp.StatusCode() != http.StatusOK {
210 msg := string(rsp.Body)
211 log.Errorf("GetApfIdServiceApisWithResponse status %d", rsp.StatusCode())
212 log.Errorf("GetApfIdServiceApisWithResponse error %s", msg)
213 return sendCoreError(ctx, rsp.StatusCode(), msg)
216 rspServiceAPIDescriptions := *rsp.JSON200
217 err = ctx.JSON(rsp.StatusCode(), rspServiceAPIDescriptions)
219 return err // tell Echo that our handler failed
224 // Retrieve a published service API.
225 func (ps *PublishService) GetApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error {
226 log.Tracef("entering GetApfIdServiceApisServiceApiId apfId %s", apfId)
228 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
229 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
235 ctxHandler context.Context
236 cancel context.CancelFunc
238 ctxHandler, cancel = context.WithCancel(context.Background())
241 var rsp *publishapi.GetApfIdServiceApisServiceApiIdResponse
242 rsp, err = client.GetApfIdServiceApisServiceApiIdWithResponse(ctxHandler, apfId, serviceApiId)
246 log.Errorf("error on GetApfIdServiceApisServiceApiIdWithResponse %s", msg)
247 return sendCoreError(ctx, http.StatusInternalServerError, msg)
250 statusCode := rsp.StatusCode()
251 if statusCode != http.StatusOK {
252 return ctx.NoContent(statusCode)
255 rspServiceAPIDescription := *rsp.JSON200
257 err = ctx.JSON(http.StatusOK, rspServiceAPIDescription)
259 return err // tell Echo that our handler failed
264 // Modify an existing published service API.
265 func (ps *PublishService) ModifyIndAPFPubAPI(ctx echo.Context, apfId string, serviceApiId string) error {
266 return ctx.NoContent(http.StatusNotImplemented)
269 // Update a published service API.
270 func (ps *PublishService) PutApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error {
271 log.Tracef("entering PutApfIdServiceApisServiceApiId apfId %s", apfId)
273 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
274 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
280 ctxHandler context.Context
281 cancel context.CancelFunc
283 ctxHandler, cancel = context.WithCancel(context.Background())
286 updatedServiceDescription, err := getServiceFromRequest(ctx)
291 var rsp *publishapi.PutApfIdServiceApisServiceApiIdResponse
292 bodyServiceAPIDescription := publishapi.PutApfIdServiceApisServiceApiIdJSONRequestBody(updatedServiceDescription)
294 rsp, err = client.PutApfIdServiceApisServiceApiIdWithResponse(ctxHandler, apfId, serviceApiId, bodyServiceAPIDescription)
298 log.Errorf("error on PutApfIdServiceApisServiceApiIdWithResponse %s", msg)
299 return sendCoreError(ctx, http.StatusInternalServerError, msg)
302 if rsp.StatusCode() != http.StatusOK {
303 log.Errorf("PutApfIdServiceApisServiceApiIdWithResponse status code %d", rsp.StatusCode())
304 if rsp.StatusCode() == http.StatusBadRequest {
305 updatedServiceDescription.UnregisterKong(ps.KongDomain, ps.KongProtocol, ps.KongIPv4, ps.KongDataPlanePort, ps.KongControlPlanePort)
307 msg := string(rsp.Body)
308 return sendCoreError(ctx, rsp.StatusCode(), msg)
311 rspServiceAPIDescription := *rsp.JSON200
312 apiId := *rspServiceAPIDescription.ApiId
314 uri := ctx.Request().Host + ctx.Request().URL.String()
315 ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, apiId))
317 err = ctx.JSON(http.StatusOK, rspServiceAPIDescription)
319 return err // Tell Echo that our handler failed
325 func getServiceFromRequest(ctx echo.Context) (publishapi.ServiceAPIDescription, error) {
326 var updatedServiceDescription publishapi.ServiceAPIDescription
327 err := ctx.Bind(&updatedServiceDescription)
329 return publishapi.ServiceAPIDescription{}, fmt.Errorf("invalid format for service")
331 return updatedServiceDescription, nil
334 // This function wraps sending of an error in the Error format, and
335 // handling the failure to marshal that.
336 func sendCoreError(ctx echo.Context, code int, message string) error {
337 pd := common29122.ProblemDetails{
341 err := ctx.JSON(code, pd)