Upgrade E2 manager spec to version 2019-08-08 64/664/3
authorLott, Christopher (cl778h) <cl778h@att.com>
Thu, 8 Aug 2019 13:10:28 +0000 (09:10 -0400)
committerLott, Christopher (cl778h) <cl778h@att.com>
Thu, 8 Aug 2019 16:02:30 +0000 (12:02 -0400)
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) <cl778h@att.com>
docs/release-notes.rst
e2-mgr-client/pom.xml
e2-mgr-client/src/main/resources/E2M_API_2019-08-08.yaml [moved from e2-mgr-client/src/main/resources/E2M_API_2019-07-03.yaml with 88% similarity]
webapp-backend/pom.xml
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/E2ManagerController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/portalapi/PortalAuthManager.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/E2ManagerControllerTest.java
webapp-frontend/src/app/ran-control/ran-control.component.ts
webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.ts

index cfe16ac..e29b613 100644 (file)
@@ -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
 --------------------------
index 0ae645e..3898380 100644 (file)
@@ -31,7 +31,7 @@ limitations under the License.
        <groupId>org.o-ran-sc.ric.plt.e2mgr.client</groupId>
        <artifactId>e2-mgr-client</artifactId>
        <name>RIC E2 Manager client</name>
-       <version>20190703-SNAPSHOT</version>
+       <version>20190808-SNAPSHOT</version>
        <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -102,7 +102,7 @@ limitations under the License.
                                                        <goal>generate</goal>
                                                </goals>
                                                <configuration>
-                                                       <inputSpec>${project.basedir}/src/main/resources/E2M_API_2019-07-03.yaml</inputSpec>
+                                                       <inputSpec>${project.basedir}/src/main/resources/E2M_API_2019-08-08.yaml</inputSpec>
                                                        <language>java</language>
                                                        <packageName>${client.base.package.name}</packageName>
                                                        <modelPackage>${client.base.package.name}.model</modelPackage>
@@ -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
index b0d8032..4f006c1 100644 (file)
@@ -62,7 +62,7 @@ limitations under the License.
                <dependency>
                        <groupId>org.o-ran-sc.ric.plt.e2mgr.client</groupId>
                        <artifactId>e2-mgr-client</artifactId>
-                       <version>20190703-SNAPSHOT</version>
+                       <version>20190808-SNAPSHOT</version>
                </dependency>
                <dependency>
                        <groupId>org.onap.portal.sdk</groupId>
@@ -169,6 +169,8 @@ limitations under the License.
                <dependency>
                        <groupId>org.junit.platform</groupId>
                        <artifactId>junit-platform-launcher</artifactId>
+                       <!-- Override Spring-Boot choice for Eclipse -->
+                       <version>1.4.2</version>
                        <scope>test</scope>
                </dependency>
        </dependencies>
index 6dc6563..3477ab0 100644 (file)
@@ -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;
index b200c9a..f020d8e 100644 (file)
@@ -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());
+       }
+
 }
index e471447..4515390 100644 (file)
@@ -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();
        }
 
        /**
index d338526..520da74 100644 (file)
@@ -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);
index d65f2b4..33fb47d 100644 (file)
@@ -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<Void> 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<Void> 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<ResetRequest> entity = new HttpEntity<>(reset);
+               ResponseEntity<Void> voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.PUT, entity,
+                               Void.class);
+               logger.debug("resetTest: response {}", voidResponse);
+               Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
+       }
+
 }
index f5ef36c..af7709d 100644 (file)
@@ -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<Object>) => {
-              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);
-            })
+            }
           );
         }
       });
index 3f586fb..dfee7e1 100644 (file)
@@ -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<HttpResponse<Object>> {
-    return this.httpClient.delete((this.basePath + 'nodeb'), { observe: 'response' });
+  nodebPut(): Observable<any> {
+    return this.httpClient.put((this.basePath + 'nodeb'), { observe: 'body' });
   }
 
 }