From: Lott, Christopher (cl778h) Date: Thu, 8 Aug 2019 13:10:28 +0000 (-0400) Subject: Upgrade E2 manager spec to version 2019-08-08 X-Git-Tag: R2~47 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=2ab4c976427eb13105d8dd03dda3f040a94a1ec1;p=portal%2Fric-dashboard.git Upgrade E2 manager spec to version 2019-08-08 This changes the drop-all-connections endpoint to use method PUT (formerly used method DELETE). Adds back-end controller method to handle RESET, but the front end does not yet expose a control for this. Change-Id: Iade4ce48291844893bfb832c144cf75a2e0d3595 Signed-off-by: Lott, Christopher (cl778h) --- diff --git a/docs/release-notes.rst b/docs/release-notes.rst index cfe16ace..e29b6138 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -24,7 +24,7 @@ Version 1.2.1, ? Aug 2019 ------------------------- * Add EPSDK-FW user management and Portal security -Version 1.2.0, 7 Aug 2019 +Version 1.2.0, 8 Aug 2019 ------------------------- * Split URL properties into prefix/suffix parts * Add jacoco plugin to back-end for code coverage @@ -35,6 +35,7 @@ Version 1.2.0, 7 Aug 2019 * Move mock configuration classes into test area * Update A1 mediator client to spec version 0.10.0 * Update App manager client to spec version 0.1.7 +* Update E2 manager client to spec version 20190808 Version 1.0.5, 5 July 2019 -------------------------- diff --git a/e2-mgr-client/pom.xml b/e2-mgr-client/pom.xml index 0ae645e5..3898380b 100644 --- a/e2-mgr-client/pom.xml +++ b/e2-mgr-client/pom.xml @@ -31,7 +31,7 @@ limitations under the License. org.o-ran-sc.ric.plt.e2mgr.client e2-mgr-client RIC E2 Manager client - 20190703-SNAPSHOT + 20190808-SNAPSHOT UTF-8 UTF-8 @@ -102,7 +102,7 @@ limitations under the License. generate - ${project.basedir}/src/main/resources/E2M_API_2019-07-03.yaml + ${project.basedir}/src/main/resources/E2M_API_2019-08-08.yaml java ${client.base.package.name} ${client.base.package.name}.model diff --git a/e2-mgr-client/src/main/resources/E2M_API_2019-07-03.yaml b/e2-mgr-client/src/main/resources/E2M_API_2019-08-08.yaml similarity index 88% rename from e2-mgr-client/src/main/resources/E2M_API_2019-07-03.yaml rename to e2-mgr-client/src/main/resources/E2M_API_2019-08-08.yaml index 42ede314..2bd99a2d 100644 --- a/e2-mgr-client/src/main/resources/E2M_API_2019-07-03.yaml +++ b/e2-mgr-client/src/main/resources/E2M_API_2019-08-08.yaml @@ -119,7 +119,7 @@ paths: schema: $ref: '#/components/schemas/ErrorResponse' /nodeb: - delete: + put: tags: - nodeb summary: >- @@ -155,6 +155,48 @@ paths: application/problem+json: schema: $ref: '#/components/schemas/ErrorResponse' + /nodeb/{ranName}/reset: + put: + tags: + - nodeb + summary: >- + Upon receipt of this message, 'ranName' shall abort any other ongoing procedures over X2 between the RIC and the RAN. The RAN shall delete all the context information related to the RIC, except the application level configuration data exchanged during the X2 Setup or eNB Configuration Update procedures, and release the corresponding resource. + operationId: reset + parameters: + - name: ranName + in: path + required: true + description: Name of RAN to return + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ResetRequest' + required: false + responses: + '204': + description: Successful operation + '400': + description: Invalid input (invalid cause, RAN in wrong state) + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: A RAN with the specified name was not found + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Internal Error + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /health: get: tags: @@ -179,6 +221,77 @@ components: format: uint16 ranName: type: string + ResetRequest: + type: object + required: + - cause + properties: + cause: + type: string + enum: [misc:control-processing-overload, +misc:hardware-failure, +misc:om-intervention, +misc:not-enough-user-plane-processing-resources, +misc:unspecified, +protocol:transfer-syntax-error, +protocol:abstract-syntax-error-reject, +protocol:abstract-syntax-error-ignore-and-notify, +protocol:message-not-compatible-with-receiver-state, +protocol:semantic-error, +protocol:unspecified, +protocol:abstract-syntax-error-falsely-constructed-message, +transport:transport-resource-unavailable, +radioNetwork:handover-desirable-for-radio-reasons, +radioNetwork:time-critical-handover, +radioNetwork:resource-optimisation-handover, +radioNetwork:reduce-load-in-serving-cell, +radioNetwork:partial-handover, +radioNetwork:unknown-new-eNB-UE-X2AP-ID, +radioNetwork:unknown-old-eNB-UE-X2AP-ID, +radioNetwork:unknown-pair-of-UE-X2AP-ID, +radioNetwork:ho-target-not-allowed, +radioNetwork:tx2relocoverall-expiry, +radioNetwork:trelocprep-expiry, +radioNetwork:cell-not-available, +radioNetwork:no-radio-resources-available-in-target-cell, +radioNetwork:invalid-MME-GroupID, +radioNetwork:unknown-MME-Code, +radioNetwork:encryption-and-or-integrity-protection-algorithms-not-supported, +radioNetwork:reportCharacteristicsEmpty, +radioNetwork:noReportPeriodicity, +radioNetwork:existingMeasurementID, +radioNetwork:unknown-eNB-Measurement-ID, +radioNetwork:measurement-temporarily-not-available, +radioNetwork:unspecified, +radioNetwork:load-balancing, +radioNetwork:handover-optimisation, +radioNetwork:value-out-of-allowed-range, +radioNetwork:multiple-E-RAB-ID-instances, +radioNetwork:switch-off-ongoing, +radioNetwork:not-supported-QCI-value, +radioNetwork:measurement-not-supported-for-the-object, +radioNetwork:tDCoverall-expiry, +radioNetwork:tDCprep-expiry, +radioNetwork:action-desirable-for-radio-reasons, +radioNetwork:reduce-load, +radioNetwork:resource-optimisation, +radioNetwork:time-critical-action, +radioNetwork:target-not-allowed, +radioNetwork:no-radio-resources-available, +radioNetwork:invalid-QoS-combination, +radioNetwork:encryption-algorithms-not-aupported, +radioNetwork:procedure-cancelled, +radioNetwork:rRM-purpose, +radioNetwork:improve-user-bit-rate, +radioNetwork:user-inactivity, +radioNetwork:radio-connection-with-UE-lost, +radioNetwork:failure-in-the-radio-interface-procedure, +radioNetwork:bearer-option-not-supported, +radioNetwork:mCG-Mobility, +radioNetwork:sCG-Mobility, +radioNetwork:count-reaches-max-value, +radioNetwork:unknown-old-en-gNB-UE-X2AP-ID, +radioNetwork:pDCP-Overload] NodebIdentity: properties: globalNbId: @@ -801,7 +914,7 @@ components: properties: errorCode: type: string - description: '401 - corrupted json, 402 - validation error, 501 - internal problem' + description: '401 - corrupted json, 402 - validation error, 403 - RAN in wrong state, 500 - RNIB error, 501 - internal problem, 502 - RMR error' errorMessage: type: string description: Human readable text diff --git a/webapp-backend/pom.xml b/webapp-backend/pom.xml index b0d80327..4f006c17 100644 --- a/webapp-backend/pom.xml +++ b/webapp-backend/pom.xml @@ -62,7 +62,7 @@ limitations under the License. org.o-ran-sc.ric.plt.e2mgr.client e2-mgr-client - 20190703-SNAPSHOT + 20190808-SNAPSHOT org.onap.portal.sdk @@ -169,6 +169,8 @@ limitations under the License. org.junit.platform junit-platform-launcher + + 1.4.2 test diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java index 6dc65633..3477ab0a 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java @@ -21,6 +21,7 @@ package org.oransc.ric.portal.dashboard.config; import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.lang.reflect.InvocationTargetException; import org.onap.portalsdk.core.onboarding.crossapi.PortalRestAPIProxy; import org.onap.portalsdk.core.onboarding.util.PortalApiConstants; @@ -112,7 +113,8 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Bean public PortalAuthManager portalAuthManagerBean() - throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { + throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { return new PortalAuthManager(appName, userName, password, decryptor, userCookie); } @@ -131,7 +133,8 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { * correctly. */ public PortalAuthenticationFilter portalAuthenticationFilterBean() - throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { + throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, + IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { PortalAuthenticationFilter portalAuthenticationFilter = new PortalAuthenticationFilter(portalAuthManagerBean(), dashboardUserManagerBean()); return portalAuthenticationFilter; diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/E2ManagerController.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/E2ManagerController.java index b200c9a8..f020d8e0 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/E2ManagerController.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/E2ManagerController.java @@ -29,6 +29,7 @@ import org.oransc.ric.e2mgr.client.api.HealthCheckApi; import org.oransc.ric.e2mgr.client.api.NodebApi; import org.oransc.ric.e2mgr.client.model.GetNodebResponse; import org.oransc.ric.e2mgr.client.model.NodebIdentity; +import org.oransc.ric.e2mgr.client.model.ResetRequest; import org.oransc.ric.e2mgr.client.model.SetupRequest; import org.oransc.ric.portal.dashboard.DashboardApplication; import org.oransc.ric.portal.dashboard.DashboardConstants; @@ -41,10 +42,10 @@ import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.security.access.annotation.Secured; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -72,6 +73,7 @@ public class E2ManagerController { public static final String NODEB_METHOD = "/nodeb"; public static final String NODEB_LIST_METHOD = "/nodeb-ids"; public static final String RAN_METHOD = "/ran"; + public static final String RESET_METHOD = "/reset"; public static final String ENDC_SETUP_METHOD = "/endcSetup"; public static final String X2_SETUP_METHOD = "/x2Setup"; public static final String VERSION_METHOD = DashboardConstants.VERSION_METHOD; @@ -145,15 +147,6 @@ public class E2ManagerController { return e2NodebApi.getNb(ranName); } - @ApiOperation(value = "Close all connections to the RANs and delete the data from the nodeb-rnib DB.") - @DeleteMapping(NODEB_METHOD) - @Secured({ DashboardConstants.ROLE_ADMIN }) - public void nodebDelete(HttpServletResponse response) { - logger.debug("nodebDelete"); - e2NodebApi.nodebDelete(); - response.setStatus(e2NodebApi.getApiClient().getStatusCode().value()); - } - @ApiOperation(value = "Sets up an EN-DC RAN connection via the E2 manager.") @PostMapping(ENDC_SETUP_METHOD) @Secured({ DashboardConstants.ROLE_ADMIN }) @@ -172,4 +165,23 @@ public class E2ManagerController { response.setStatus(e2NodebApi.getApiClient().getStatusCode().value()); } + @ApiOperation(value = "Close all connections to the RANs and delete the data from the nodeb-rnib DB.") + @PutMapping(NODEB_METHOD) + @Secured({ DashboardConstants.ROLE_ADMIN }) + public void nodebPut(HttpServletResponse response) { + logger.debug("nodebPut"); + e2NodebApi.nodebPut(); + response.setStatus(e2NodebApi.getApiClient().getStatusCode().value()); + } + + @ApiOperation(value = "Abort any other ongoing procedures over X2 between the RIC and the RAN.") + @PutMapping(RESET_METHOD + "/{" + PP_RANNAME + "}") + @Secured({ DashboardConstants.ROLE_ADMIN }) + public void reset(@PathVariable(PP_RANNAME) String ranName, @RequestBody ResetRequest resetRequest, + HttpServletResponse response) { + logger.debug("reset"); + e2NodebApi.reset(ranName, resetRequest); + response.setStatus(e2NodebApi.getApiClient().getStatusCode().value()); + } + } diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthManager.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthManager.java index e4714473..45153900 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthManager.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthManager.java @@ -20,6 +20,7 @@ package org.oransc.ric.portal.dashboard.portalapi; import java.lang.invoke.MethodHandles; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; @@ -44,7 +45,8 @@ public class PortalAuthManager { public PortalAuthManager(final String appName, final String username, final String password, final String decryptorClassName, final String userCookie) - throws ClassNotFoundException, InstantiationException, IllegalAccessException { + throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException, NoSuchMethodException, SecurityException { credentialsMap = new HashMap<>(); // The map keys are hardcoded in EPSDK-FW, no constants are defined :( credentialsMap.put("appName", appName); @@ -54,7 +56,7 @@ public class PortalAuthManager { // Instantiate here so configuration errors are detected at app-start time logger.debug("ctor: using decryptor class {}", decryptorClassName); Class decryptorClass = Class.forName(decryptorClassName); - portalSdkDecryptor = (IPortalSdkDecryptor) decryptorClass.newInstance(); + portalSdkDecryptor = (IPortalSdkDecryptor) decryptorClass.getDeclaredConstructor().newInstance(); } /** diff --git a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java index d3385267..520da742 100644 --- a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java +++ b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java @@ -34,6 +34,7 @@ import org.oransc.ric.e2mgr.client.invoker.ApiClient; import org.oransc.ric.e2mgr.client.model.GetNodebResponse; import org.oransc.ric.e2mgr.client.model.NodebIdentity; import org.oransc.ric.e2mgr.client.model.NodebIdentityGlobalNbId; +import org.oransc.ric.e2mgr.client.model.ResetRequest; import org.oransc.ric.e2mgr.client.model.SetupRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,7 +98,14 @@ public class E2ManagerMockConfiguration { Thread.sleep(delayMs); } return null; - }).when(mockApi).nodebDelete(); + }).when(mockApi).nodebPut(); + doAnswer(inv -> { + if (delayMs > 0) { + logger.debug("reset sleeping {}", delayMs); + Thread.sleep(delayMs); + } + return null; + }).when(mockApi).reset(any(String.class), any(ResetRequest.class)); doAnswer(inv -> { if (delayMs > 0) { logger.debug("getNb sleeping {}", delayMs); diff --git a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/E2ManagerControllerTest.java b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/E2ManagerControllerTest.java index d65f2b47..33fb47d4 100644 --- a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/E2ManagerControllerTest.java +++ b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/E2ManagerControllerTest.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.oransc.ric.e2mgr.client.model.GetNodebResponse; import org.oransc.ric.e2mgr.client.model.NodebIdentity; +import org.oransc.ric.e2mgr.client.model.ResetRequest; import org.oransc.ric.e2mgr.client.model.SetupRequest; import org.oransc.ric.portal.dashboard.model.RanDetailsTransport; import org.oransc.ric.portal.dashboard.model.SuccessTransport; @@ -85,15 +86,6 @@ public class E2ManagerControllerTest extends AbstractControllerTest { Assertions.assertNotNull(response.getRanName()); } - @Test - public void bigRedButtonTest() { - URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.NODEB_METHOD); - logger.info("Invoking {}", uri); - ResponseEntity voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.DELETE, null, - Void.class); - Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful()); - } - @Test public void endcSetupTest() { URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.ENDC_SETUP_METHOD); @@ -116,4 +108,26 @@ public class E2ManagerControllerTest extends AbstractControllerTest { Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful()); } + // Aka big--button test + @Test + public void nodebPutTest() { + URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.NODEB_METHOD); + logger.info("Invoking {}", uri); + ResponseEntity voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.PUT, null, Void.class); + logger.debug("nodebPutTest: response {}", voidResponse); + Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful()); + } + + @Test + public void resetTest() { + URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.RESET_METHOD, "ranName"); + logger.info("Invoking {}", uri); + ResetRequest reset = new ResetRequest(); + HttpEntity entity = new HttpEntity<>(reset); + ResponseEntity voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.PUT, entity, + Void.class); + logger.debug("resetTest: response {}", voidResponse); + Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful()); + } + } diff --git a/webapp-frontend/src/app/ran-control/ran-control.component.ts b/webapp-frontend/src/app/ran-control/ran-control.component.ts index f5ef36ca..af7709d8 100644 --- a/webapp-frontend/src/app/ran-control/ran-control.component.ts +++ b/webapp-frontend/src/app/ran-control/ran-control.component.ts @@ -63,21 +63,19 @@ export class RanControlComponent implements OnInit { this.confirmDialogService.openConfirmDialog('Are you sure you want to disconnect all RAN connections?') .afterClosed().subscribe( (res: boolean) => { if (res) { - this.e2MgrSvc.nodebDelete().subscribe( - ( response: HttpResponse) => { - if (response.status === 200) { - this.notificationService.success('Disconnect succeeded!'); - this.dataSource.loadTable(); - } + this.e2MgrSvc.nodebPut().subscribe( + ( body: any ) => { + this.notificationService.success('Disconnect succeeded!'); + this.dataSource.loadTable(); }, - ( (her: HttpErrorResponse) => { + (her: HttpErrorResponse) => { // the error field should have an ErrorTransport object let msg = her.message; if (her.error && her.error.message) { msg = her.error.message; } this.errorDialogService.displayError('Disconnect failed: ' + msg); - }) + } ); } }); diff --git a/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.ts b/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.ts index 3f586fb3..dfee7e15 100644 --- a/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.ts +++ b/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.ts @@ -74,10 +74,10 @@ export class E2ManagerService { /** * Sends a request to drop all RAN connections - * @returns Observable. Response code indicates result. + * @returns Observable with body. */ - nodebDelete(): Observable> { - return this.httpClient.delete((this.basePath + 'nodeb'), { observe: 'response' }); + nodebPut(): Observable { + return this.httpClient.put((this.basePath + 'nodeb'), { observe: 'body' }); } }