From 5b686151904e2582ea9ce9d2f1c6abb7a400afa5 Mon Sep 17 00:00:00 2001 From: "Lott, Christopher (cl778h)" Date: Wed, 26 Jun 2019 10:41:26 -0400 Subject: [PATCH] Upgrade E2 to version 20190626 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) --- docs/release-notes.rst | 10 +- e2-mgr-client/pom.xml | 4 +- ...9-06-20.yaml => E2_Manager_API_2019-06-26.yaml} | 43 +++++- webapp-backend/pom.xml | 2 +- .../dashboard/config/AnrXappMockConfiguration.java | 6 +- .../config/E2ManagerMockConfiguration.java | 19 ++- .../dashboard/controller/E2ManagerController.java | 156 ++++++++++++--------- .../portal/dashboard/model/E2SetupResponse.java | 107 -------------- .../dashboard/model/RanDetailsTransport.java | 96 +++++++++++++ .../src/main/resources/application.properties | 3 + webapp-frontend/src/app/interfaces/e2-mgr.types.ts | 27 ++++ .../ran-connection-dialog.component.css | 4 + .../ran-connection-dialog.component.html | 8 +- .../src/app/ran-control/ran-control.component.html | 30 ++-- .../src/app/ran-control/ran-control.component.scss | 8 +- .../src/app/ran-control/ran-control.component.ts | 2 +- .../src/app/ran-control/ran-control.datasource.ts | 12 +- .../src/app/services/e2-mgr/e2-mgr.service.ts | 41 +++--- 18 files changed, 349 insertions(+), 229 deletions(-) rename e2-mgr-client/src/main/resources/{E2_Manager_API_2019-06-20.yaml => E2_Manager_API_2019-06-26.yaml} (96%) delete mode 100644 webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/E2SetupResponse.java create mode 100644 webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RanDetailsTransport.java diff --git a/docs/release-notes.rst b/docs/release-notes.rst index d98aa0b6..ff4e6b9e 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -20,11 +20,13 @@ 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 diff --git a/e2-mgr-client/pom.xml b/e2-mgr-client/pom.xml index 50d521e0..a4676659 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 - 20190620-SNAPSHOT + 20190626-SNAPSHOT UTF-8 UTF-8 @@ -104,7 +104,7 @@ limitations under the License. generate - ${project.basedir}/src/main/resources/E2_Manager_API_2019-06-20.yaml + ${project.basedir}/src/main/resources/E2_Manager_API_2019-06-26.yaml java ${client.base.package.name} ${client.base.package.name}.model diff --git a/e2-mgr-client/src/main/resources/E2_Manager_API_2019-06-20.yaml b/e2-mgr-client/src/main/resources/E2_Manager_API_2019-06-26.yaml similarity index 96% rename from e2-mgr-client/src/main/resources/E2_Manager_API_2019-06-20.yaml rename to e2-mgr-client/src/main/resources/E2_Manager_API_2019-06-26.yaml index 76588dc5..3e7b08ab 100644 --- a/e2-mgr-client/src/main/resources/E2_Manager_API_2019-06-20.yaml +++ b/e2-mgr-client/src/main/resources/E2_Manager_API_2019-06-26.yaml @@ -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: diff --git a/webapp-backend/pom.xml b/webapp-backend/pom.xml index 26326fed..1107a48e 100644 --- a/webapp-backend/pom.xml +++ b/webapp-backend/pom.xml @@ -56,7 +56,7 @@ limitations under the License. org.o-ran-sc.ric.plt.e2mgr.client e2-mgr-client - 20190620-SNAPSHOT + 20190626-SNAPSHOT org.springframework.boot diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AnrXappMockConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AnrXappMockConfiguration.java index 340036aa..b33aa040 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AnrXappMockConfiguration.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AnrXappMockConfiguration.java @@ -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() { diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java index a03b33e5..ddec4ae4 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java @@ -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 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)); 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 a088af39..6b621f4f 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 @@ -20,24 +20,28 @@ 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:
HTTP server received an invalid response from a - * server it consulted when acting as a proxy or gateway.
+ * 502 on failure and wrap the remote details:
HTTP server received + * an invalid response from a server it consulted when acting as a proxy or + * gateway.
* - * 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 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 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(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 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(new ErrorTransport(ex.getRawStatusCode(), ex.toString()), + HttpStatus.BAD_GATEWAY); + } + List 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 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(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(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(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(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(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 index 15f60fa6..00000000 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/E2SetupResponse.java +++ /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 index 00000000..3162056b --- /dev/null +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RanDetailsTransport.java @@ -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; + } + +} diff --git a/webapp-backend/src/main/resources/application.properties b/webapp-backend/src/main/resources/application.properties index fa2d5784..69118800 100644 --- a/webapp-backend/src/main/resources/application.properties +++ b/webapp-backend/src/main/resources/application.properties @@ -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 diff --git a/webapp-frontend/src/app/interfaces/e2-mgr.types.ts b/webapp-frontend/src/app/interfaces/e2-mgr.types.ts index 70256d2f..c007d869 100644 --- a/webapp-frontend/src/app/interfaces/e2-mgr.types.ts +++ b/webapp-frontend/src/app/interfaces/e2-mgr.types.ts @@ -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; +} diff --git a/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.css b/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.css index 2d846648..9863490f 100644 --- a/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.css +++ b/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.css @@ -23,3 +23,7 @@ display: block; } +/* leave a bit of space */ +.ran-type-radio-button { + margin-left: 5px; +} diff --git a/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html b/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html index 500e763e..1dac6470 100644 --- a/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html +++ b/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html @@ -26,13 +26,13 @@
- - EN-DC - X2 + + EN-DC + X2
- + Example: ABCD123456 Name is required Valid name is required diff --git a/webapp-frontend/src/app/ran-control/ran-control.component.html b/webapp-frontend/src/app/ran-control/ran-control.component.html index ba37728d..860e137b 100644 --- a/webapp-frontend/src/app/ran-control/ran-control.component.html +++ b/webapp-frontend/src/app/ran-control/ran-control.component.html @@ -31,34 +31,34 @@ - - RAN Type - {{rconnect.requestType}} + + Nodeb ID + {{ran.nodebIdentity.globalNbId.nbId}} + + + + Node Type + {{ran.nodebStatus.nodeType}} - eNodeB/gNodeB Name - {{rconnect.ranName}} + RAN Name + {{ran.nodebIdentity.inventoryName}} IP - {{rconnect.ranIp}} + {{ran.nodebStatus.ip}} Port - {{rconnect.ranPort}} - - - - Response - {{rconnect.responseCode}} + {{ran.nodebStatus.port}} - - Time Stamp - {{rconnect.timeStamp}} + + Connection Status + {{ran.nodebStatus.connectionStatus}} diff --git a/webapp-frontend/src/app/ran-control/ran-control.component.scss b/webapp-frontend/src/app/ran-control/ran-control.component.scss index b14459df..af4629ae 100644 --- a/webapp-frontend/src/app/ran-control/ran-control.component.scss +++ b/webapp-frontend/src/app/ran-control/ran-control.component.scss @@ -38,4 +38,10 @@ .disconnect-all-button { float: right; -} \ No newline at end of file +} + +.version__text { + color: gray; + letter-spacing: 0.1rem; + font-size: 10px; +} 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 6e1a2d78..262dd03c 100644 --- a/webapp-frontend/src/app/ran-control/ran-control.component.ts +++ b/webapp-frontend/src/app/ran-control/ran-control.component.ts @@ -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, diff --git a/webapp-frontend/src/app/ran-control/ran-control.datasource.ts b/webapp-frontend/src/app/ran-control/ran-control.datasource.ts index 431537fe..c84ab1ea 100644 --- a/webapp-frontend/src/app/ran-control/ran-control.datasource.ts +++ b/webapp-frontend/src/app/ran-control/ran-control.datasource.ts @@ -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 { +export class RANControlDataSource extends DataSource { - private ranControlSubject = new BehaviorSubject([]); + private ranControlSubject = new BehaviorSubject([]); private loadingSubject = new BehaviorSubject(false); @@ -40,15 +40,15 @@ export class RANControlDataSource extends DataSource { 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 { + connect(collectionViewer: CollectionViewer): Observable { return this.ranControlSubject.asObservable(); } 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 55fd9d59..3f586fb3 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 @@ -18,8 +18,11 @@ * ========================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 { + const url = this.basePath + 'version'; + return this.httpClient.get(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> { + return this.httpClient.get>(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> { + 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> { + 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> { return this.httpClient.delete((this.basePath + 'nodeb'), { observe: 'response' }); } -- 2.16.6