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 KongControlPlanePort common29122.Port;
40 KongControlPlaneIPv4 common29122.Ipv4Addr;
41 KongDataPlaneIPv4 common29122.Ipv4Addr;
42 KongDataPlanePort common29122.Port;
44 CapifIPv4 common29122.Ipv4Addr;
45 CapifPort common29122.Port;
48 // Creates a service that implements both the PublishRegister and the publishserviceapi.ServerInterface interfaces.
49 func NewPublishService(
52 kongControlPlaneIPv4 common29122.Ipv4Addr,
53 kongControlPlanePort common29122.Port,
54 kongDataPlaneIPv4 common29122.Ipv4Addr,
55 kongDataPlanePort common29122.Port,
57 capifIPv4 common29122.Ipv4Addr,
58 capifPort common29122.Port) *PublishService {
59 return &PublishService{
60 KongDomain : kongDomain,
61 KongProtocol : kongProtocol,
62 KongControlPlaneIPv4 : kongControlPlaneIPv4,
63 KongControlPlanePort : kongControlPlanePort,
64 KongDataPlaneIPv4 : kongDataPlaneIPv4,
65 KongDataPlanePort : kongDataPlanePort,
66 CapifProtocol : capifProtocol,
67 CapifIPv4 : capifIPv4,
68 CapifPort : capifPort,
73 func (ps *PublishService) PostApfIdServiceApis(ctx echo.Context, apfId string) error {
74 log.Tracef("entering PostApfIdServiceApis apfId %s", apfId)
75 log.Debugf("PostApfIdServiceApis KongControlPlaneIPv4 %s", ps.KongControlPlaneIPv4)
76 log.Debugf("PostApfIdServiceApis KongDataPlaneIPv4 %s", ps.KongDataPlaneIPv4)
78 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
79 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
85 ctxHandler context.Context
86 cancel context.CancelFunc
88 ctxHandler, cancel = context.WithCancel(context.Background())
91 newServiceAPIDescription, err := getServiceFromRequest(ctx)
96 newServiceAPIDescription.PrepareNewService()
98 statusCode, err := newServiceAPIDescription.RegisterKong(
101 ps.KongControlPlaneIPv4,
102 ps.KongControlPlanePort,
103 ps.KongDataPlaneIPv4,
104 ps.KongDataPlanePort,
106 if (err != nil) || (statusCode != http.StatusCreated) {
107 // We can return with http.StatusForbidden if there is a http.StatusConflict detected by Kong
109 log.Errorf("error on RegisterKong %s", msg)
110 return sendCoreError(ctx, statusCode, msg)
113 bodyServiceAPIDescription := publishapi.PostApfIdServiceApisJSONRequestBody(newServiceAPIDescription)
114 var rsp *publishapi.PostApfIdServiceApisResponse
116 log.Trace("calling PostApfIdServiceApisWithResponse")
117 rsp, err = client.PostApfIdServiceApisWithResponse(ctxHandler, apfId, bodyServiceAPIDescription)
121 log.Errorf("error on PostApfIdServiceApisWithResponse %s", msg)
122 return sendCoreError(ctx, http.StatusInternalServerError, msg)
125 if rsp.StatusCode() != http.StatusCreated {
126 msg := string(rsp.Body)
127 log.Debugf("PostApfIdServiceApisWithResponse status code %d", rsp.StatusCode())
128 log.Debugf("PostApfIdServiceApisWithResponse error %s", msg)
129 if rsp.StatusCode() == http.StatusForbidden || rsp.StatusCode() == http.StatusBadRequest {
130 newServiceAPIDescription.UnregisterKong(ps.KongDomain, ps.KongProtocol, ps.KongControlPlaneIPv4, ps.KongControlPlanePort)
132 return sendCoreError(ctx, rsp.StatusCode(), msg)
135 rspServiceAPIDescription := *rsp.JSON201
136 apiId := *rspServiceAPIDescription.ApiId
138 uri := ctx.Request().Host + ctx.Request().URL.String()
139 ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, apiId))
141 err = ctx.JSON(http.StatusCreated, rspServiceAPIDescription)
143 return err // Tell Echo that our handler failed
150 // Unpublish a published service API.
151 func (ps *PublishService) DeleteApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error {
152 log.Tracef("entering DeleteApfIdServiceApisServiceApiId apfId %s serviceApiId %s", apfId, serviceApiId)
154 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
155 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
161 ctxHandler context.Context
162 cancel context.CancelFunc
164 ctxHandler, cancel = context.WithCancel(context.Background())
167 log.Debugf("call GetApfIdServiceApisServiceApiIdWithResponse before delete apfId %s serviceApiId %s", apfId, serviceApiId)
168 var rsp *publishapi.GetApfIdServiceApisServiceApiIdResponse
169 rsp, err = client.GetApfIdServiceApisServiceApiIdWithResponse(ctxHandler, apfId, serviceApiId)
173 log.Errorf("error on GetApfIdServiceApisServiceApiIdWithResponse %s", msg)
174 return sendCoreError(ctx, http.StatusInternalServerError, msg)
177 statusCode := rsp.StatusCode()
178 if statusCode != http.StatusOK {
179 log.Debugf("GetApfIdServiceApisServiceApiIdWithResponse status %d", statusCode)
180 return ctx.NoContent(statusCode)
183 rspServiceAPIDescription := *rsp.JSON200
185 statusCode, err = rspServiceAPIDescription.UnregisterKong(ps.KongDomain, ps.KongProtocol, ps.KongControlPlaneIPv4, ps.KongControlPlanePort)
186 if (err != nil) || (statusCode != http.StatusNoContent) {
188 log.Errorf("error on UnregisterKong %s", msg)
189 return sendCoreError(ctx, statusCode, msg)
192 log.Trace("call DeleteApfIdServiceApisServiceApiIdWithResponse")
193 _, err = client.DeleteApfIdServiceApisServiceApiIdWithResponse(ctxHandler, apfId, serviceApiId)
197 log.Errorf("error on DeleteApfIdServiceApisServiceApiIdWithResponse %s", msg)
198 return sendCoreError(ctx, http.StatusInternalServerError, msg)
201 return ctx.NoContent(http.StatusNoContent)
204 // Retrieve all published APIs.
205 func (ps *PublishService) GetApfIdServiceApis(ctx echo.Context, apfId string) error {
206 log.Tracef("entering GetApfIdServiceApis apfId %s", apfId)
208 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
209 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
215 ctxHandler context.Context
216 cancel context.CancelFunc
218 ctxHandler, cancel = context.WithCancel(context.Background())
221 var rsp *publishapi.GetApfIdServiceApisResponse
222 rsp, err = client.GetApfIdServiceApisWithResponse(ctxHandler, apfId)
226 log.Errorf("error on GetApfIdServiceApisWithResponse %s", msg)
227 return sendCoreError(ctx, http.StatusInternalServerError, msg)
230 if rsp.StatusCode() != http.StatusOK {
231 msg := string(rsp.Body)
232 log.Errorf("GetApfIdServiceApisWithResponse status %d", rsp.StatusCode())
233 log.Errorf("GetApfIdServiceApisWithResponse error %s", msg)
234 return sendCoreError(ctx, rsp.StatusCode(), msg)
237 rspServiceAPIDescriptions := *rsp.JSON200
238 err = ctx.JSON(rsp.StatusCode(), rspServiceAPIDescriptions)
240 return err // tell Echo that our handler failed
245 // Retrieve a published service API.
246 func (ps *PublishService) GetApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error {
247 log.Tracef("entering GetApfIdServiceApisServiceApiId apfId %s", apfId)
249 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
250 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
256 ctxHandler context.Context
257 cancel context.CancelFunc
259 ctxHandler, cancel = context.WithCancel(context.Background())
262 var rsp *publishapi.GetApfIdServiceApisServiceApiIdResponse
263 rsp, err = client.GetApfIdServiceApisServiceApiIdWithResponse(ctxHandler, apfId, serviceApiId)
267 log.Errorf("error on GetApfIdServiceApisServiceApiIdWithResponse %s", msg)
268 return sendCoreError(ctx, http.StatusInternalServerError, msg)
271 statusCode := rsp.StatusCode()
272 if statusCode != http.StatusOK {
273 return ctx.NoContent(statusCode)
276 rspServiceAPIDescription := *rsp.JSON200
278 err = ctx.JSON(http.StatusOK, rspServiceAPIDescription)
280 return err // tell Echo that our handler failed
285 // Modify an existing published service API.
286 func (ps *PublishService) ModifyIndAPFPubAPI(ctx echo.Context, apfId string, serviceApiId string) error {
287 return ctx.NoContent(http.StatusNotImplemented)
290 // Update a published service API.
291 func (ps *PublishService) PutApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error {
292 log.Tracef("entering PutApfIdServiceApisServiceApiId apfId %s", apfId)
294 capifcoreUrl := fmt.Sprintf("%s://%s:%d/published-apis/v1/", ps.CapifProtocol, ps.CapifIPv4, ps.CapifPort)
295 client, err := publishapi.NewClientWithResponses(capifcoreUrl)
301 ctxHandler context.Context
302 cancel context.CancelFunc
304 ctxHandler, cancel = context.WithCancel(context.Background())
307 updatedServiceDescription, err := getServiceFromRequest(ctx)
312 var rsp *publishapi.PutApfIdServiceApisServiceApiIdResponse
313 bodyServiceAPIDescription := publishapi.PutApfIdServiceApisServiceApiIdJSONRequestBody(updatedServiceDescription)
315 rsp, err = client.PutApfIdServiceApisServiceApiIdWithResponse(ctxHandler, apfId, serviceApiId, bodyServiceAPIDescription)
319 log.Errorf("error on PutApfIdServiceApisServiceApiIdWithResponse %s", msg)
320 return sendCoreError(ctx, http.StatusInternalServerError, msg)
323 if rsp.StatusCode() != http.StatusOK {
324 log.Errorf("PutApfIdServiceApisServiceApiIdWithResponse status code %d", rsp.StatusCode())
325 if rsp.StatusCode() == http.StatusBadRequest {
326 updatedServiceDescription.UnregisterKong(ps.KongDomain, ps.KongProtocol,ps.KongControlPlaneIPv4, ps.KongControlPlanePort)
328 msg := string(rsp.Body)
329 return sendCoreError(ctx, rsp.StatusCode(), msg)
332 rspServiceAPIDescription := *rsp.JSON200
333 apiId := *rspServiceAPIDescription.ApiId
335 uri := ctx.Request().Host + ctx.Request().URL.String()
336 ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, apiId))
338 err = ctx.JSON(http.StatusOK, rspServiceAPIDescription)
340 return err // Tell Echo that our handler failed
346 func getServiceFromRequest(ctx echo.Context) (publishapi.ServiceAPIDescription, error) {
347 var updatedServiceDescription publishapi.ServiceAPIDescription
348 err := ctx.Bind(&updatedServiceDescription)
350 return publishapi.ServiceAPIDescription{}, fmt.Errorf("invalid format for service")
352 return updatedServiceDescription, nil
355 // This function wraps sending of an error in the Error format, and
356 // handling the failure to marshal that.
357 func sendCoreError(ctx echo.Context, code int, message string) error {
358 pd := common29122.ProblemDetails{
362 err := ctx.JSON(code, pd)