-------------------------
* 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
* 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
--------------------------
<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>
<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>
schema:
$ref: '#/components/schemas/ErrorResponse'
/nodeb:
- delete:
+ put:
tags:
- nodeb
summary: >-
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:
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:
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
<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>
<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>
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;
@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);
}
* 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;
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;
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;
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;
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 })
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());
+ }
+
}
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;
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);
// 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();
}
/**
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;
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);
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;
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);
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());
+ }
+
}
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);
- })
+ }
);
}
});
/**
* 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' });
}
}