Upgrade E2 to version 20190626 14/414/9
authorLott, Christopher (cl778h) <cl778h@att.com>
Wed, 26 Jun 2019 14:41:26 +0000 (10:41 -0400)
committerLott, Christopher (cl778h) <cl778h@att.com>
Fri, 28 Jun 2019 16:07:00 +0000 (12:07 -0400)
E2 added a method to get the RAN identities, which answers
a list of names that can be used to query the RAN status
endpoint.  Extend FE and BE to use the new information.
Drop the mock behavior for tracking connection requests;
add a mock behavior for RAN names to support R1 testing.

Change-Id: I669f1e0537676c8b2ea09e5b53080396d91d9868
Signed-off-by: Lott, Christopher (cl778h) <cl778h@att.com>
18 files changed:
docs/release-notes.rst
e2-mgr-client/pom.xml
e2-mgr-client/src/main/resources/E2_Manager_API_2019-06-26.yaml [moved from e2-mgr-client/src/main/resources/E2_Manager_API_2019-06-20.yaml with 96% similarity]
webapp-backend/pom.xml
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AnrXappMockConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/E2ManagerController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/E2SetupResponse.java [deleted file]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RanDetailsTransport.java [new file with mode: 0644]
webapp-backend/src/main/resources/application.properties
webapp-frontend/src/app/interfaces/e2-mgr.types.ts
webapp-frontend/src/app/ran-control/ran-connection-dialog.component.css
webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html
webapp-frontend/src/app/ran-control/ran-control.component.html
webapp-frontend/src/app/ran-control/ran-control.component.scss
webapp-frontend/src/app/ran-control/ran-control.component.ts
webapp-frontend/src/app/ran-control/ran-control.datasource.ts
webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.ts

index d98aa0b..ff4e6b9 100644 (file)
 RIC Dashboard Release Notes
 ===========================
 
-Version 1.0.5, 30 June 2019
+Version 1.0.5, 28 June 2019
 ---------------------------
 * Upgrade to Angular version 8
 * Upgrade to Spring-Boot 2.1.6.RELEASE
 * Fixed AC xApp policy page title is not aligned
+* Update E2 manager client to spec version 20190626
+* Add configuration-driven mock of E2 getNodebIdList
 
 Version 1.0.4, 27 June 2019
 ---------------------------
@@ -45,9 +47,15 @@ Version 1.0.4, 27 June 2019
 * Add build number to dashboard version string
 * Move mock admin screen user data to backend
 * Update App manager client to spec version 0.1.5
+* Move RAN connection feature to control screen
 * Rework admin table
+<<<<<<< HEAD
 * Update the notification service
 * Remove the RAN connection invocation link from left menu and move it to control screen
+=======
+* Update the notification service 
+* Move RAN connection feature to control screen
+>>>>>>> Upgrade E2 to version 20190626
 * Repair deploy-app feature and use icon instead of text button
 
 Version 1.0.3, 28 May 2019
index 50d521e..a467665 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>20190620-SNAPSHOT</version>
+       <version>20190626-SNAPSHOT</version>
        <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -104,7 +104,7 @@ limitations under the License.
                                                        <goal>generate</goal>
                                                </goals>
                                                <configuration>
-                                                       <inputSpec>${project.basedir}/src/main/resources/E2_Manager_API_2019-06-20.yaml</inputSpec>
+                                                       <inputSpec>${project.basedir}/src/main/resources/E2_Manager_API_2019-06-26.yaml</inputSpec>
                                                        <language>java</language>
                                                        <packageName>${client.base.package.name}</packageName>
                                                        <modelPackage>${client.base.package.name}.model</modelPackage>
@@ -117,12 +117,14 @@ paths:
           content:
             application/problem+json:
               schema:
-                $ref: '#/components/schemas/ErrorResponse'  
-  '/nodeb':
+                $ref: '#/components/schemas/ErrorResponse'
+  /nodeb:
     delete:
       tags:
         - nodeb
-      summary: Close all connections to the RANs and delete the data from the nodeb-rnib DB
+      summary: >-
+        Close all connections to the RANs and delete the data from the
+        nodeb-rnib DB
       responses:
         '204':
           description: Successful operation
@@ -131,7 +133,28 @@ paths:
           content:
             application/problem+json:
               schema:
-                $ref: '#/components/schemas/ErrorResponse'  
+                $ref: '#/components/schemas/ErrorResponse'
+  /nodeb/ids:
+    get:
+      tags:
+        - nodeb
+      summary: Get RANs identities list
+      operationId: getNodebIdList
+      responses:
+        '200':
+          description: Successful operation
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/NodebIdentity'
+        '500':
+          description: Internal Error
+          content:
+            application/problem+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponse'
   /health:
     get:
       tags:
@@ -156,6 +179,18 @@ components:
           format: uint16
         ranName:
           type: string
+    NodebIdentity:
+      properties:
+        globalNbId:
+          properties:
+            nbId:
+              type: string
+            plmnId:
+              type: string
+          type: object
+        inventoryName:
+          type: string
+      type: object
     GetNodebResponse:
       properties:
         connectionStatus:
index 26326fe..1107a48 100644 (file)
@@ -56,7 +56,7 @@ limitations under the License.
                <dependency>
                        <groupId>org.o-ran-sc.ric.plt.e2mgr.client</groupId>
                        <artifactId>e2-mgr-client</artifactId>
-                       <version>20190620-SNAPSHOT</version>
+                       <version>20190626-SNAPSHOT</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
index 340036a..b33aa04 100644 (file)
@@ -54,9 +54,9 @@ public class AnrXappMockConfiguration {
        private final NeighborCellRelationTable ncrt, ncrtNodeB1, ncrtNodeB2, ncrtNodeB3;
        private final GgNodeBTable gNodebTable;
 
-       private static final String gnodeb1 = "GNB:001EF5:0045FE50";
-       private static final String gnodeb2 = "GNB:001EF6:0045FE51";
-       private static final String gnodeb3 = "GNB:001EF7:0045FE52";
+       private static final String gnodeb1 = "001EF5:0045FE50";
+       private static final String gnodeb2 = "001EF6:0045FE51";
+       private static final String gnodeb3 = "001EF7:0045FE52";
 
        public AnrXappMockConfiguration() {
 
index a03b33e..ddec4ae 100644 (file)
@@ -25,11 +25,15 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.oransc.ric.e2mgr.client.api.HealthCheckApi;
 import org.oransc.ric.e2mgr.client.api.NodebApi;
 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.SetupRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,8 +43,7 @@ import org.springframework.context.annotation.Profile;
 import org.springframework.http.HttpStatus;
 
 /**
- * Creates a mock implementation of the E2 manager client API. This version
- * answers only status codes, no data, so the mock implementations are trivial.
+ * Creates a mock implementation of the E2 Manager client API.
  */
 @Profile("mock")
 @Configuration
@@ -48,11 +51,17 @@ public class E2ManagerMockConfiguration {
 
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
+       private final List<NodebIdentity> nodebIdList;
        private final GetNodebResponse nodebResponse;
 
        public E2ManagerMockConfiguration() {
                logger.info("Configuring mock E2 Manager");
-               nodebResponse = new GetNodebResponse().ip("1.2.3.4").port(123).ranName("myRan");
+               NodebIdentityGlobalNbId globalNbId = new NodebIdentityGlobalNbId().nbId("mockNbId").plmnId("mockPlmId");
+               NodebIdentity nbid = new NodebIdentity().inventoryName("mockInvName").globalNbId(globalNbId);
+               nodebIdList = new ArrayList<>();
+               nodebIdList.add(nbid);
+               nodebResponse = new GetNodebResponse().connectionStatus("mockConnectionStatus").failureType("mockFailureType")
+                               .ip("1.2.3.4").nodeType("mockNodeType").port(123).ranName("mockRanName");
        }
 
        private ApiClient apiClient() {
@@ -90,6 +99,10 @@ public class E2ManagerMockConfiguration {
                        return nodebResponse;
                }).when(mockApi).getNb(any(String.class));
 
+               doAnswer(i -> {
+                       return nodebIdList;
+               }).when(mockApi).getNodebIdList();
+
                doAnswer(i -> {
                        return null;
                }).when(mockApi).endcSetup(any(SetupRequest.class));
index a088af3..6b621f4 100644 (file)
 package org.oransc.ric.portal.dashboard.controller;
 
 import java.lang.invoke.MethodHandles;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.servlet.http.HttpServletResponse;
 
 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.NodebIdentityGlobalNbId;
 import org.oransc.ric.e2mgr.client.model.SetupRequest;
 import org.oransc.ric.portal.dashboard.DashboardApplication;
 import org.oransc.ric.portal.dashboard.DashboardConstants;
-import org.oransc.ric.portal.dashboard.model.E2SetupRequestType;
-import org.oransc.ric.portal.dashboard.model.E2SetupResponse;
+import org.oransc.ric.portal.dashboard.model.ErrorTransport;
+import org.oransc.ric.portal.dashboard.model.RanDetailsTransport;
 import org.oransc.ric.portal.dashboard.model.SuccessTransport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.util.Assert;
@@ -52,11 +56,12 @@ import io.swagger.annotations.ApiOperation;
 
 /**
  * Proxies calls from the front end to the E2 Manager API. All methods answer
- * 502 on failure: <blockquote>HTTP server received an invalid response from a
- * server it consulted when acting as a proxy or gateway.</blockquote>
+ * 502 on failure and wrap the remote details: <blockquote>HTTP server received
+ * an invalid response from a server it consulted when acting as a proxy or
+ * gateway.</blockquote>
  * 
- * As of this writing the E2 interface does not support get-all, so this class
- * mocks up some of that functionality.
+ * In R1 the E2 interface does not yet implement the get-ID-list method, so this
+ * class mocks up some functionality.
  */
 @Configuration
 @RestController
@@ -65,6 +70,8 @@ public class E2ManagerController {
 
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
+       private final List<NodebIdentity> mockNodebIdList;
+
        // Path parameters
        private static final String PP_RANNAME = "ranName";
 
@@ -72,27 +79,21 @@ public class E2ManagerController {
        private final HealthCheckApi e2HealthCheckApi;
        private final NodebApi e2NodebApi;
 
-       // Stores the requests and results.
-       // TODO remove when the E2 manager is extended.
-       private Set<E2SetupResponse> responses = new HashSet<>();
-
        @Autowired
-       public E2ManagerController(final HealthCheckApi e2HealthCheckApi, final NodebApi e2NodebApi) {
+       public E2ManagerController(final HealthCheckApi e2HealthCheckApi, final NodebApi e2NodebApi,
+                       @Value("${e2mgr.mock.rannames:#{null}}") final String mockRanNames) {
                Assert.notNull(e2HealthCheckApi, "API must not be null");
                Assert.notNull(e2NodebApi, "API must not be null");
                this.e2HealthCheckApi = e2HealthCheckApi;
                this.e2NodebApi = e2NodebApi;
-       }
-
-       private void assertNotNull(Object o) {
-               if (o == null)
-                       throw new IllegalArgumentException("Null not permitted");
-       }
-
-       private void assertNotEmpty(String s) {
-               assertNotNull(s);
-               if (s.isEmpty())
-                       throw new IllegalArgumentException("Empty not permitted");
+               mockNodebIdList = new ArrayList<>();
+               if (mockRanNames != null) {
+                       logger.debug("ctor: Mocking RAN names: {}", mockRanNames);
+                       for (String id : mockRanNames.split(",")) {
+                               NodebIdentityGlobalNbId globalNbId = new NodebIdentityGlobalNbId().nbId("mockNbId").plmnId("mockPlmId");
+                               mockNodebIdList.add(new NodebIdentity().globalNbId(globalNbId).inventoryName(id.trim()));
+                       }
+               }
        }
 
        @ApiOperation(value = "Gets the E2 manager client library MANIFEST.MF property Implementation-Version.", response = SuccessTransport.class)
@@ -111,16 +112,52 @@ public class E2ManagerController {
                        return null;
                } catch (HttpStatusCodeException ex) {
                        logger.warn("healthGet failed: {}", ex.toString());
-                       return ResponseEntity.status(HttpServletResponse.SC_BAD_GATEWAY).body(ex.getResponseBodyAsString());
+                       return new ResponseEntity<ErrorTransport>(new ErrorTransport(ex.getRawStatusCode(), ex.toString()),
+                                       HttpStatus.BAD_GATEWAY);
+               }
+       }
+
+       // This calls other methods to simplify the task of the front-end.
+       @ApiOperation(value = "Gets all RAN identities and statuses from the E2 manager.", response = RanDetailsTransport.class, responseContainer = "List")
+       @RequestMapping(value = "/ran", method = RequestMethod.GET)
+       public Object getRanDetails() {
+               logger.debug("getRanDetails");
+               List<NodebIdentity> nodebIdList = null;
+               try {
+                       // TODO: remove mock when e2mgr delivers the getNodebIdList() method
+                       nodebIdList = mockNodebIdList.isEmpty() ? e2NodebApi.getNodebIdList() : mockNodebIdList;
+               } catch (HttpStatusCodeException ex) {
+                       logger.warn("getRanDetails: getNodebIdList failed: {}", ex.toString());
+                       return new ResponseEntity<ErrorTransport>(new ErrorTransport(ex.getRawStatusCode(), ex.toString()),
+                                       HttpStatus.BAD_GATEWAY);
+               }
+               List<RanDetailsTransport> details = new ArrayList<>();
+               for (NodebIdentity nbid : nodebIdList) {
+                       GetNodebResponse nbResp = null;
+                       try {
+                               // Keep looping despite failures
+                               nbResp = e2NodebApi.getNb(nbid.getInventoryName());
+                       } catch (HttpStatusCodeException ex) {
+                               logger.warn("getRanDetails failed for name {}: {}", nbid.getInventoryName(), ex.toString());
+                               nbResp = new GetNodebResponse().connectionStatus("UNKNOWN").ip("UNKNOWN").port(-1)
+                                               .ranName(nbid.getInventoryName());
+                       }
+                       details.add(new RanDetailsTransport(nbid, nbResp));
                }
+               return details;
        }
 
-       // TODO replace with actual functionality
-       @ApiOperation(value = "Gets the unique requests submitted to the E2 manager.", response = E2SetupResponse.class, responseContainer = "List")
-       @RequestMapping(value = "/setup", method = RequestMethod.GET)
-       public Iterable<E2SetupResponse> getRequests() {
-               logger.debug("getRequests");
-               return responses;
+       @ApiOperation(value = "Get RAN identities list.", response = NodebIdentity.class, responseContainer = "List")
+       @RequestMapping(value = "/nodeb/id", method = RequestMethod.GET)
+       public Object getNodebIdList() {
+               logger.debug("getNodebIdList");
+               try {
+                       return e2NodebApi.getNodebIdList();
+               } catch (HttpStatusCodeException ex) {
+                       logger.warn("getNodebIdList failed: {}", ex.toString());
+                       return new ResponseEntity<ErrorTransport>(new ErrorTransport(ex.getRawStatusCode(), ex.toString()),
+                                       HttpStatus.BAD_GATEWAY);
+               }
        }
 
        @ApiOperation(value = "Get RAN by name.", response = GetNodebResponse.class)
@@ -131,62 +168,53 @@ public class E2ManagerController {
                        return e2NodebApi.getNb(ranName);
                } catch (HttpStatusCodeException ex) {
                        logger.warn("getNb failed: {}", ex.toString());
-                       return ResponseEntity.status(HttpServletResponse.SC_BAD_GATEWAY).body(ex.getResponseBodyAsString());
+                       return new ResponseEntity<ErrorTransport>(new ErrorTransport(ex.getRawStatusCode(), ex.toString()),
+                                       HttpStatus.BAD_GATEWAY);
                }
        }
 
        @ApiOperation(value = "Close all connections to the RANs and delete the data from the nodeb-rnib DB.")
        @RequestMapping(value = "/nodeb", method = RequestMethod.DELETE)
-       public void nodebDelete() {
+       public Object nodebDelete(HttpServletResponse response) {
                logger.debug("nodebDelete");
-               e2NodebApi.nodebDelete();
-               // TODO: remove this mock functionality
-               responses.clear();
+               try {
+                       e2NodebApi.nodebDelete();
+                       response.setStatus(e2NodebApi.getApiClient().getStatusCode().value());
+                       return null;
+               } catch (HttpStatusCodeException ex) {
+                       logger.warn("nodebDelete failed: {}", ex.toString());
+                       return new ResponseEntity<ErrorTransport>(new ErrorTransport(ex.getRawStatusCode(), ex.toString()),
+                                       HttpStatus.BAD_GATEWAY);
+               }
        }
 
-       @ApiOperation(value = "Sets up an EN-DC RAN connection via the E2 manager.", response = E2SetupResponse.class)
+       @ApiOperation(value = "Sets up an EN-DC RAN connection via the E2 manager.")
        @RequestMapping(value = "/endcSetup", method = RequestMethod.POST)
-       public Object endcSetup(@RequestBody SetupRequest setupRequest) {
+       public Object endcSetup(@RequestBody SetupRequest setupRequest, HttpServletResponse response) {
                logger.debug("endcSetup {}", setupRequest);
-               try {
-                       assertNotEmpty(setupRequest.getRanIp());
-                       assertNotEmpty(setupRequest.getRanName());
-                       assertNotNull(setupRequest.getRanPort());
-               } catch (Exception ex) {
-                       return new E2SetupResponse(E2SetupRequestType.ENDC, setupRequest, HttpServletResponse.SC_BAD_REQUEST);
-               }
                try {
                        e2NodebApi.endcSetup(setupRequest);
-                       E2SetupResponse r = new E2SetupResponse(E2SetupRequestType.ENDC, setupRequest,
-                                       e2NodebApi.getApiClient().getStatusCode().value());
-                       responses.add(r);
-                       return r;
+                       response.setStatus(e2NodebApi.getApiClient().getStatusCode().value());
+                       return null;
                } catch (HttpStatusCodeException ex) {
                        logger.warn("endcSetup failed: {}", ex.toString());
-                       return ResponseEntity.status(HttpServletResponse.SC_BAD_GATEWAY).body(ex.getResponseBodyAsString());
+                       return new ResponseEntity<ErrorTransport>(new ErrorTransport(ex.getRawStatusCode(), ex.toString()),
+                                       HttpStatus.BAD_GATEWAY);
                }
        }
 
-       @ApiOperation(value = "Sets up an X2 RAN connection via the E2 manager.", response = E2SetupResponse.class)
+       @ApiOperation(value = "Sets up an X2 RAN connection via the E2 manager.")
        @RequestMapping(value = "/x2Setup", method = RequestMethod.POST)
-       public Object x2Setup(@RequestBody SetupRequest setupRequest) {
+       public Object x2Setup(@RequestBody SetupRequest setupRequest, HttpServletResponse response) {
                logger.debug("x2Setup {}", setupRequest);
-               try {
-                       assertNotEmpty(setupRequest.getRanIp());
-                       assertNotEmpty(setupRequest.getRanName());
-                       assertNotNull(setupRequest.getRanPort());
-               } catch (Exception ex) {
-                       return new E2SetupResponse(E2SetupRequestType.ENDC, setupRequest, HttpServletResponse.SC_BAD_REQUEST);
-               }
                try {
                        e2NodebApi.x2Setup(setupRequest);
-                       E2SetupResponse r = new E2SetupResponse(E2SetupRequestType.X2, setupRequest,
-                                       e2NodebApi.getApiClient().getStatusCode().value());
-                       responses.add(r);
-                       return r;
+                       response.setStatus(e2NodebApi.getApiClient().getStatusCode().value());
+                       return null;
                } catch (HttpStatusCodeException ex) {
                        logger.warn("x2Setup failed: {}", ex.toString());
-                       return ResponseEntity.status(HttpServletResponse.SC_BAD_GATEWAY).body(ex.getResponseBodyAsString());
+                       return new ResponseEntity<ErrorTransport>(new ErrorTransport(ex.getRawStatusCode(), ex.toString()),
+                                       HttpStatus.BAD_GATEWAY);
                }
        }
 
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/E2SetupResponse.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/E2SetupResponse.java
deleted file mode 100644 (file)
index 15f60fa..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*-
- * ========================LICENSE_START=================================
- * O-RAN-SC
- * %%
- * Copyright (C) 2019 AT&T Intellectual Property and Nokia
- * %%
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ========================LICENSE_END===================================
- */
-package org.oransc.ric.portal.dashboard.model;
-
-import java.time.Instant;
-
-import org.oransc.ric.e2mgr.client.model.SetupRequest;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-/**
- * Response to an E2 Manager setupRequest message carries the original
- * information plus request type, timestamp and HTTP response code.
- */
-public class E2SetupResponse extends SetupRequest implements IDashboardResponse {
-
-       public E2SetupResponse() {
-       }
-
-       public E2SetupResponse(E2SetupRequestType type, SetupRequest request, int responseCode) {
-               super.ranName(request.getRanName()).ranIp(request.getRanIp()).ranPort(request.getRanPort());
-               this.requestType = type;
-               this.timeStamp = Instant.now();
-               this.responseCode = responseCode;
-       }
-
-       @JsonProperty("requestType")
-       private E2SetupRequestType requestType = null;
-
-       public SetupRequest requestType(E2SetupRequestType type) {
-               this.requestType = type;
-               return this;
-       }
-
-       /**
-        * Get requestType
-        * 
-        * @return requestType
-        **/
-       public E2SetupRequestType getRequestType() {
-               return requestType;
-       }
-
-       public void setRequestType(E2SetupRequestType type) {
-               this.requestType = type;
-       }
-
-       @JsonProperty("timeStamp")
-       private Instant timeStamp = null;
-
-       public SetupRequest timeStamp(Instant timeStamp) {
-               this.timeStamp = timeStamp;
-               return this;
-       }
-
-       /**
-        * Get timeStamp
-        * 
-        * @return timeStamp
-        **/
-       public Instant getTimeStamp() {
-               return timeStamp;
-       }
-
-       public void setTimeStamp(Instant timeStamp) {
-               this.timeStamp = timeStamp;
-       }
-
-       @JsonProperty("responseCode")
-       private Integer responseCode = null;
-
-       public SetupRequest responseCode(Integer responseCode) {
-               this.responseCode = responseCode;
-               return this;
-       }
-
-       /**
-        * Get responseCode
-        * 
-        * @return responseCode
-        **/
-       public Integer getResponseCode() {
-               return responseCode;
-       }
-
-       public void setResponseCode(Integer responseCode) {
-               this.responseCode = responseCode;
-       }
-
-}
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RanDetailsTransport.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RanDetailsTransport.java
new file mode 100644 (file)
index 0000000..3162056
--- /dev/null
@@ -0,0 +1,96 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.ric.portal.dashboard.model;
+
+import org.oransc.ric.e2mgr.client.model.GetNodebResponse;
+import org.oransc.ric.e2mgr.client.model.NodebIdentity;
+
+public class RanDetailsTransport {
+
+       private NodebIdentity nodebIdentity;
+       private GetNodebResponse nodebStatus;
+
+       public RanDetailsTransport() {
+       }
+
+       public RanDetailsTransport(NodebIdentity nodebIdentity, GetNodebResponse nodebResponse) {
+               this.nodebIdentity = nodebIdentity;
+               this.nodebStatus = nodebResponse;
+       }
+
+       public NodebIdentity getNodebIdentity() {
+               return nodebIdentity;
+       }
+
+       public void setNodebIdentity(NodebIdentity nodebIdentity) {
+               this.nodebIdentity = nodebIdentity;
+       }
+
+       public GetNodebResponse getNodebStatus() {
+               return nodebStatus;
+       }
+
+       public void setNodebStatus(GetNodebResponse nodebStatus) {
+               this.nodebStatus = nodebStatus;
+       }
+
+       public RanDetailsTransport nodebIdentity(NodebIdentity n) {
+               this.nodebIdentity = n;
+               return this;
+       }
+
+       public RanDetailsTransport nodebStatus(GetNodebResponse s) {
+               this.nodebStatus = s;
+               return this;
+       }
+
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + ((nodebIdentity == null) ? 0 : nodebIdentity.hashCode());
+               result = prime * result + ((nodebStatus == null) ? 0 : nodebStatus.hashCode());
+               return result;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               RanDetailsTransport other = (RanDetailsTransport) obj;
+               if (nodebIdentity == null) {
+                       if (other.nodebIdentity != null)
+                               return false;
+               } else if (!nodebIdentity.equals(other.nodebIdentity))
+                       return false;
+               if (nodebStatus == null) {
+                       if (other.nodebStatus != null)
+                               return false;
+               } else if (!nodebStatus.equals(other.nodebStatus))
+                       return false;
+               return true;
+       }
+
+}
index fa2d578..6911880 100644 (file)
@@ -32,6 +32,9 @@ anrxapp.url = http://jar-app-props-default-ANR-URL
 
 # E2 Manager
 e2mgr.url = http://jar-app-props-default-E2-URL
+# Supply CSV to  mock the get-list API for testing e2mgr in R1;
+# missing key or empty value disables the mock behavior
+# e2mgr.mock.rannames = RANONE, RANTWO
 
 # Xapp Manager
 xappmgr.url = http://jar-app-props-default-Xapp-Mgr-URL
index 70256d2..c007d86 100644 (file)
@@ -30,3 +30,30 @@ export interface E2ErrorResponse {
   errorCode: string;
   errorMessage: string;
 }
+
+export interface E2NodebIdentityGlobalNbId {
+  nbId: string;
+  plmnId: string;
+}
+
+export interface E2NodebIdentity {
+  inventoryName: string;
+  globalNbId: E2NodebIdentityGlobalNbId;
+}
+
+export interface E2GetNodebResponse {
+  connectionStatus: string; // actually one-of, but model as string
+  enb: object; // don't model this until needed
+  failureType: string; // actually one-of, butmodel as string
+  gnb: object; // don't model this until needed
+  ip: string;
+  nodeType: object; // actually one-of, but model as string
+  port: number; // actually integer
+  ranName: string;
+  setupFailure: object; // don't model this until needed
+}
+
+export interface E2RanDetails {
+  nodebIdentity: E2NodebIdentity;
+  nodebStatus: E2GetNodebResponse;
+}
index 500e763..1dac647 100644 (file)
   <div mat-dialog-content>
     <div name="rantype">
       <label id="request-type-radio-group-label">RAN type:</label>
-      <mat-radio-group aria-label="RAN type" formControlName="ranType">
-        <mat-radio-button value="endc">EN-DC</mat-radio-button>
-        <mat-radio-button value="x2">X2</mat-radio-button>
+      <mat-radio-group aria-label="RAN Type" formControlName="ranType">
+        <mat-radio-button class="ran-type-radio-button" value="endc">EN-DC</mat-radio-button>
+        <mat-radio-button class="ran-type-radio-button" value="x2">X2</mat-radio-button>
       </mat-radio-group>
     </div>
     <mat-form-field class="input-display-block">
-      <input matInput type="text" placeholder="eNB/gNB Name" formControlName="ranName">
+      <input matInput type="text" placeholder="RAN Name" formControlName="ranName">
       <mat-hint align="end">Example: ABCD123456</mat-hint>
       <mat-error *ngIf="validateControl('ranName') && hasError('ranName', 'required')">Name is required</mat-error>
       <mat-error *ngIf="hasError('ranName', 'length')">Valid name is required</mat-error>
index ba37728..860e137 100644 (file)
 
   <table mat-table class="ran-control-table mat-elevation-z8" [dataSource]="dataSource">
 
-    <ng-container matColumnDef="requestType">
-      <mat-header-cell *matHeaderCellDef>RAN Type</mat-header-cell>
-      <mat-cell *matCellDef="let rconnect">{{rconnect.requestType}}</mat-cell>
+    <ng-container matColumnDef="nbId">
+      <mat-header-cell *matHeaderCellDef>Nodeb ID</mat-header-cell>
+      <mat-cell *matCellDef="let ran">{{ran.nodebIdentity.globalNbId.nbId}}</mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="nodeType">
+      <mat-header-cell *matHeaderCellDef>Node Type</mat-header-cell>
+      <mat-cell *matCellDef="let ran">{{ran.nodebStatus.nodeType}}</mat-cell>
     </ng-container>
 
     <ng-container matColumnDef="ranName">
-      <mat-header-cell *matHeaderCellDef>eNodeB/gNodeB Name</mat-header-cell>
-      <mat-cell *matCellDef="let rconnect">{{rconnect.ranName}}</mat-cell>
+      <mat-header-cell *matHeaderCellDef>RAN Name</mat-header-cell>
+      <mat-cell *matCellDef="let ran">{{ran.nodebIdentity.inventoryName}}</mat-cell>
     </ng-container>
 
     <ng-container matColumnDef="ranIp">
       <mat-header-cell *matHeaderCellDef>IP</mat-header-cell>
-      <mat-cell *matCellDef="let rconnect">{{rconnect.ranIp}}</mat-cell>
+      <mat-cell *matCellDef="let ran">{{ran.nodebStatus.ip}}</mat-cell>
     </ng-container>
 
     <ng-container matColumnDef="ranPort">
       <mat-header-cell *matHeaderCellDef>Port</mat-header-cell>
-      <mat-cell *matCellDef="let rconnect">{{rconnect.ranPort}}</mat-cell>
-    </ng-container>
-
-    <ng-container matColumnDef="responseCode">
-      <mat-header-cell *matHeaderCellDef>Response</mat-header-cell>
-      <mat-cell *matCellDef="let rconnect">{{rconnect.responseCode}}</mat-cell>
+      <mat-cell *matCellDef="let ran">{{ran.nodebStatus.port}}</mat-cell>
     </ng-container>
 
-    <ng-container matColumnDef="timeStamp">
-      <mat-header-cell *matHeaderCellDef>Time Stamp</mat-header-cell>
-      <mat-cell *matCellDef="let rconnect">{{rconnect.timeStamp}}</mat-cell>
+    <ng-container matColumnDef="connectionStatus">
+      <mat-header-cell *matHeaderCellDef>Connection Status</mat-header-cell>
+      <mat-cell *matCellDef="let ran">{{ran.nodebStatus.connectionStatus}}</mat-cell>
     </ng-container>
 
     <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
index b14459d..af4629a 100644 (file)
 
 .disconnect-all-button {
     float: right;
-}
\ No newline at end of file
+}
+
+.version__text {
+    color: gray;
+    letter-spacing: 0.1rem;
+    font-size: 10px;
+}
index 6e1a2d7..262dd03 100644 (file)
@@ -33,7 +33,7 @@ import { HttpErrorResponse } from '@angular/common/http';
   styleUrls: ['./ran-control.component.scss']
 })
 export class RanControlComponent implements OnInit {
-  displayedColumns: string[] = ['requestType', 'ranName', 'ranIp', 'ranPort', 'responseCode', 'timeStamp'];
+  displayedColumns: string[] = ['nbId', 'nodeType', 'ranName', 'ranIp', 'ranPort', 'connectionStatus'];
   dataSource: RANControlDataSource;
 
   constructor(private e2MgrSvc: E2ManagerService,
index 431537f..c84ab1e 100644 (file)
@@ -23,12 +23,12 @@ import { Observable } from 'rxjs/Observable';
 import { catchError, finalize } from 'rxjs/operators';
 import { of } from 'rxjs/observable/of';
 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
-import { E2SetupRequest } from '../interfaces/e2-mgr.types';
+import { E2RanDetails, E2SetupRequest } from '../interfaces/e2-mgr.types';
 import { E2ManagerService } from '../services/e2-mgr/e2-mgr.service';
 
-export class RANControlDataSource extends DataSource<E2SetupRequest> {
+export class RANControlDataSource extends DataSource<E2RanDetails> {
 
-  private ranControlSubject = new BehaviorSubject<E2SetupRequest[]>([]);
+  private ranControlSubject = new BehaviorSubject<E2RanDetails[]>([]);
 
   private loadingSubject = new BehaviorSubject<boolean>(false);
 
@@ -40,15 +40,15 @@ export class RANControlDataSource extends DataSource<E2SetupRequest> {
 
   loadTable() {
     this.loadingSubject.next(true);
-    this.e2MgrSvcservice.getAll()
+    this.e2MgrSvcservice.getRan()
       .pipe(
         catchError(() => of([])),
         finalize(() => this.loadingSubject.next(false))
       )
-      .subscribe((ranControl: E2SetupRequest[]) => this.ranControlSubject.next(ranControl));
+      .subscribe((ranControl: E2RanDetails[]) => this.ranControlSubject.next(ranControl));
   }
 
-  connect(collectionViewer: CollectionViewer): Observable<E2SetupRequest[]> {
+  connect(collectionViewer: CollectionViewer): Observable<E2RanDetails[]> {
     return this.ranControlSubject.asObservable();
   }
 
index 55fd9d5..3f586fb 100644 (file)
  * ========================LICENSE_END===================================
  */
 import { Injectable } from '@angular/core';
-import { HttpClient } from '@angular/common/http';
-import { E2SetupRequest } from '../../interfaces/e2-mgr.types';
+import { HttpClient, HttpResponse } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { E2RanDetails, E2SetupRequest } from '../../interfaces/e2-mgr.types';
+import { DashboardSuccessTransport } from '../../interfaces/dashboard.types';
 
 @Injectable({
   providedIn: 'root'
@@ -34,42 +37,46 @@ export class E2ManagerService {
   }
 
   /**
-   * Gets E2 manager client version details
-   * @returns Observable that should yield a DashboardSuccessTransport object
+   * Gets E2 client version details
+   * @returns Observable that should yield a String
    */
-  getE2ManagerVersion() {
-    return this.httpClient.get(this.basePath + 'version');
+  getVersion(): Observable<string> {
+    const url = this.basePath + 'version';
+    return this.httpClient.get<DashboardSuccessTransport>(url).pipe(
+      // Extract the string here
+      map(res => res['data'])
+    );
   }
 
   /**
-   * Gets setup request history
+   * Gets RAN details
    * @returns Observable that should yield an array of objects
    */
-  getAll() {
-    return this.httpClient.get(this.basePath + 'setup');
+  getRan(): Observable<Array<E2RanDetails>> {
+    return this.httpClient.get<Array<E2RanDetails>>(this.basePath + 'ran');
   }
 
   /**
    * Sends a request to setup an ENDC/gNodeB connection
-   * @returns Observable
+   * @returns Observable. On success there is no data, only a code.
    */
-  endcSetup(req: E2SetupRequest) {
-    return this.httpClient.post(this.basePath + 'endcSetup', req);
+  endcSetup(req: E2SetupRequest): Observable<HttpResponse<Object>> {
+    return this.httpClient.post(this.basePath + 'endcSetup', req, { observe: 'response' });
   }
 
   /**
    * Sends a request to setup an X2/eNodeB connection
-   * @returns Observable
+   * @returns Observable. On success there is no data, only a code.
    */
-  x2Setup(req: E2SetupRequest) {
-    return this.httpClient.post(this.basePath + 'x2Setup', req);
+  x2Setup(req: E2SetupRequest): Observable<HttpResponse<Object>> {
+    return this.httpClient.post(this.basePath + 'x2Setup', req, { observe: 'response' });
   }
 
   /**
    * Sends a request to drop all RAN connections
-   * @returns Observable
+   * @returns Observable. Response code indicates result.
    */
-  nodebDelete() {
+  nodebDelete(): Observable<HttpResponse<Object>> {
     return this.httpClient.delete((this.basePath + 'nodeb'), { observe: 'response' });
   }