<parent>
<groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
<artifactId>ric-dash-parent</artifactId>
- <version>2.0.2-SNAPSHOT</version>
+ <version>2.0.3-SNAPSHOT</version>
</parent>
<!-- This groupId will NOT allow deployment in LF -->
<groupId>org.o-ran-sc.ric-plt.appmgr.client</groupId>
<parent>
<groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
<artifactId>ric-dash-parent</artifactId>
- <version>2.0.2-SNAPSHOT</version>
+ <version>2.0.3-SNAPSHOT</version>
</parent>
<!-- This groupId will NOT allow deployment in LF -->
<groupId>org.o-ran-sc.ric-plt.e2mgr.client</groupId>
<artifactId>ric-dash-parent</artifactId>
<name>RIC Dashboard Project</name>
<packaging>pom</packaging>
- <version>2.0.2-SNAPSHOT</version>
+ <version>2.0.3-SNAPSHOT</version>
<properties>
<java.version>11</java.version>
<!-- Properties for the license-maven-plugin in child POMs -->
<parent>
<groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
<artifactId>ric-dash-parent</artifactId>
- <version>2.0.2-SNAPSHOT</version>
+ <version>2.0.3-SNAPSHOT</version>
</parent>
<!-- reuse parent groupId -->
<artifactId>ric-dash-be</artifactId>
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
+ STATAPPMETRIC_METHOD)
@Secured({ DashboardConstants.ROLE_ADMIN })
public IDashboardResponse createStats(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
- @RequestBody StatsDetailsTransport statsSetupRequest) throws StatsManagerException, IOException {
+ @Validated @RequestBody StatsDetailsTransport statsSetupRequest) throws StatsManagerException, IOException {
logger.debug("createStats with instance {} request {}", instanceKey, statsSetupRequest);
return appStatsManager.createStats(instanceKey, statsSetupRequest);
}
+ STATAPPMETRIC_METHOD)
@Secured({ DashboardConstants.ROLE_ADMIN })
public void updateStats(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
- @RequestBody StatsDetailsTransport statsSetupRequest) throws StatsManagerException, IOException {
+ @Validated @RequestBody StatsDetailsTransport statsSetupRequest) throws StatsManagerException, IOException {
logger.debug("updateStats for instance {} request {}", instanceKey, statsSetupRequest);
appStatsManager.updateStats(instanceKey, statsSetupRequest);
}
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.util.Assert;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* Proxies calls from the front end to the App Manager API.
*
- * If a method throws RestClientResponseException, it is handled by
- * {@link CustomResponseEntityExceptionHandler#handleProxyMethodException(Exception, org.springframework.web.context.request.WebRequest)}
- * which returns status 502. All other exceptions are handled by Spring which
- * returns status 500.
+ * If a method throws RestClientResponseException, it is handled by a method in
+ * {@link CustomResponseEntityExceptionHandler} which returns status 502. All
+ * other exceptions are handled by Spring which returns status 500.
*/
@Configuration
@RestController
@PutMapping(CONFIG_METHOD_PATH)
@Secured({ DashboardConstants.ROLE_ADMIN })
public ConfigValidationErrors modifyXappConfig(
- @PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey, @RequestBody XAppConfig xAppConfig) {
+ @PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey, //
+ @Validated @RequestBody XAppConfig xAppConfig) {
logger.debug("modifyXappConfig instance {} config {}", instanceKey, xAppConfig);
return appManagerApiBuilder.getXappApi(instanceKey).modifyXappConfig(xAppConfig);
}
@ApiOperation(value = "Deploy a xapp.", response = Xapp.class)
@PostMapping(XAPPS_METHOD_PATH)
@Secured({ DashboardConstants.ROLE_ADMIN })
- public Xapp deployXapp(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
- @RequestBody XappDescriptor appDescriptor) {
+ public Xapp deployXapp(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey, //
+ @Validated @RequestBody XappDescriptor appDescriptor) {
logger.debug("deployXapp instance {} descriptor {}", instanceKey, appDescriptor);
return appManagerApiBuilder.getXappApi(instanceKey).deployXapp(appDescriptor);
}
import io.swagger.annotations.ApiOperation;
/**
- * Proxies calls from the front end to a CAAS-Ingress API, which is a proxy for
- * a Kubernetes API.
+ * Proxies calls from the front end to a CAAS-Ingress API, which in turn is a
+ * proxy for a Kubernetes API.
*
- * If a method throws RestClientResponseException, it is handled by
- * {@link CustomResponseEntityExceptionHandler#handleProxyMethodException(Exception, org.springframework.web.context.request.WebRequest)}
- * which returns status 502. All other exceptions are handled by Spring which
- * returns status 500.
+ * If a method throws RestClientResponseException, it is handled by a method in
+ * {@link CustomResponseEntityExceptionHandler} which returns status 502. All
+ * other exceptions are handled by Spring which returns status 500.
*/
@Configuration
@RestController
import java.lang.invoke.MethodHandles;
+import org.oransc.ric.portal.dashboard.exception.InvalidArgumentException;
import org.oransc.ric.portal.dashboard.exception.StatsManagerException;
import org.oransc.ric.portal.dashboard.exception.UnknownInstanceException;
import org.slf4j.Logger;
* @return A response entity with status code 502 and an unstructured message.
*/
@ExceptionHandler({ RestClientResponseException.class })
- public final ResponseEntity<String> handleProxyMethodException(Exception ex, WebRequest request) {
+ public final ResponseEntity<String> handleRestClientResponse(Exception ex, WebRequest request) {
// Capture the full stack trace in the log.
if (log.isErrorEnabled())
- log.error("handleProxyMethodException: request " + request.getDescription(false), ex);
+ log.error("handleRestClientResponse: request " + request.getDescription(false), ex);
if (ex instanceof HttpStatusCodeException) {
HttpStatusCodeException hsce = (HttpStatusCodeException) ex;
return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(hsce.getResponseBodyAsString());
* @return A response entity with status code 400 and an unstructured message.
*/
@ExceptionHandler({ UnknownInstanceException.class })
- public final ResponseEntity<String> handleUnknownInstanceException(Exception ex, WebRequest request) {
- log.warn("handleUnknownInstanceException: request {}, exception {}", request.getDescription(false),
- ex.toString());
+ public final ResponseEntity<String> handleUnknownInstance(Exception ex, WebRequest request) {
+ log.warn("handleUnknownInstance: request {}, exception {}", request.getDescription(false), ex.toString());
+ return ResponseEntity.badRequest().body(getShortExceptionMessage(ex));
+ }
+
+ /**
+ * Logs the error and generates a response when a REST controller method takes
+ * an InvalidArgumentException, an invalid JSON was sent.
+ *
+ * @param ex
+ * The exception
+ * @param request
+ * The original request
+ * @return A response entity with status code 400 and an unstructured message.
+ */
+ @ExceptionHandler({ InvalidArgumentException.class })
+ public final ResponseEntity<String> handleInvalidArgument(Exception ex, WebRequest request) {
+ log.warn("handleInvalidArgument: request {}, exception {}", request.getDescription(false), ex.toString());
return ResponseEntity.badRequest().body(getShortExceptionMessage(ex));
}
* @return A response entity with status code 400 and an unstructured message.
*/
@ExceptionHandler({ StatsManagerException.class })
- public final ResponseEntity<String> handleStatsManagerException(Exception ex, WebRequest request) {
- log.warn("handleStatsManagerException: request {}, exception {}", request.getDescription(false), ex.toString());
+ public final ResponseEntity<String> handleStatsManager(Exception ex, WebRequest request) {
+ log.warn("handleStatsManager: request {}, exception {}", request.getDescription(false), ex.toString());
return ResponseEntity.badRequest().body(getShortExceptionMessage(ex));
}
import java.util.ArrayList;
import java.util.List;
+import javax.validation.Valid;
+
import org.oransc.ric.portal.dashboard.DashboardApplication;
import org.oransc.ric.portal.dashboard.DashboardConstants;
import org.oransc.ric.portal.dashboard.config.E2ManagerApiBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.util.Assert;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
/**
* Proxies calls from the front end to the E2 Manager API.
*
- * If a method throws RestClientResponseException, it is handled by
- * {@link CustomResponseEntityExceptionHandler#handleProxyMethodException(Exception, org.springframework.web.context.request.WebRequest)}
- * which returns status 502. All other exceptions are handled by Spring which
- * returns status 500.
+ * If a method throws RestClientResponseException, it is handled by a method in
+ * {@link CustomResponseEntityExceptionHandler} which returns status 502. All
+ * other exceptions are handled by Spring which returns status 500.
*/
@Configuration
@RestController
+ "/{" + PP_RANNAME + "}")
@Secured({ DashboardConstants.ROLE_ADMIN })
public ResponseEntity<String> updateGnb(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
- @PathVariable(PP_RANNAME) String ranName, @RequestBody UpdateGnbRequest updateGnbRequest) {
+ @PathVariable(PP_RANNAME) String ranName, //
+ @Valid @Validated @RequestBody UpdateGnbRequest updateGnbRequest) {
logger.debug("updateGnb instance {} ran {}", instanceKey, ranName);
NodebApi api = e2ManagerApiBuilder.getNodebApi(instanceKey);
api.updateGnb(updateGnbRequest, ranName);
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * 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.exception;
+
+public class InvalidArgumentException extends IllegalArgumentException {
+
+ private static final long serialVersionUID = 6897065423512216018L;
+
+ public InvalidArgumentException() {
+ super();
+ }
+
+ public InvalidArgumentException(String s) {
+ super(s);
+ }
+}
import java.util.List;
import org.junit.Assert;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.oransc.ric.portal.dashboard.config.RICInstanceMockConfiguration;
import org.oransc.ric.portal.dashboard.exception.StatsManagerException;
@Test
public void testStatsMgr() throws Exception {
new AppStatsManager("file.json");
- try {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
new AppStatsManager(null);
- throw new Exception("Unexpected success");
- } catch (IllegalArgumentException ex) {
- logger.info("caught expected exception: {}", ex.toString());
- }
+ });
AppStatsManager mgr = new AppStatsManager(true);
AppStats as1 = mgr.createStats(RICInstanceMockConfiguration.INSTANCE_KEY_1,
new StatsDetailsTransport(-1, "app1 name", "http://app1"));
Assert.assertFalse(all.isEmpty());
List<AppStats> byInstance = mgr.getStatsByInstance(RICInstanceMockConfiguration.INSTANCE_KEY_1);
Assert.assertFalse(byInstance.isEmpty());
- mgr = new AppStatsManager(false);
- AppStats as3 = mgr.createStats(RICInstanceMockConfiguration.INSTANCE_KEY_1,
+ final AppStatsManager mgr2 = new AppStatsManager(false);
+ AppStats as3 = mgr2.createStats(RICInstanceMockConfiguration.INSTANCE_KEY_1,
new StatsDetailsTransport(-1, "app3 name", "http://app3"));
Assert.assertNotEquals(as2.getStatsDetails().getAppId(), as3.getStatsDetails().getAppId());
- try {
- mgr.createStats(as3.getInstanceKey(), as3.getStatsDetails());
- throw new Exception("Unexpected success");
- } catch (StatsManagerException ex) {
- logger.info("caught expected exception: {}", ex.toString());
- }
+ Assertions.assertThrows(StatsManagerException.class, () -> {
+ mgr2.createStats(as3.getInstanceKey(), as3.getStatsDetails());
+ });
AppStats as = mgr.getStatsById(as1.getInstanceKey(), as1.getStatsDetails().getAppId());
Assert.assertEquals(as1, as);
AppStats notFound = mgr.getStatsById("bogus", 12345);
as1.getStatsDetails().setMetricUrl("http://other");
mgr.updateStats(as1.getInstanceKey(), as1.getStatsDetails());
mgr.deleteStats(as1.getInstanceKey(), as1.getStatsDetails().getAppId());
- try {
- mgr.updateStats("bogus", as1.getStatsDetails());
- throw new Exception("Unexpected success");
- } catch (StatsManagerException ex) {
- logger.info("caught expected exception: {}", ex.toString());
- }
- try {
- mgr.deleteStats("bogus", 999);
- throw new Exception("Unexpected success");
- } catch (StatsManagerException ex) {
- logger.info("caught expected exception: {}", ex.toString());
- }
+ Assertions.assertThrows(StatsManagerException.class, () -> {
+ mgr2.updateStats("bogus", as1.getStatsDetails());
+ });
+ Assertions.assertThrows(StatsManagerException.class, () -> {
+ mgr2.deleteStats("bogus", 999);
+ });
}
}
import java.util.Set;
import org.junit.Assert;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.onap.portalsdk.core.onboarding.exception.PortalAPIException;
import org.onap.portalsdk.core.restful.domain.EcompRole;
EcompUser user = createEcompUser(loginId);
dum.createUser(user);
logger.info("Created user {}", user);
- try {
+ Assertions.assertThrows(PortalAPIException.class, () -> {
dum.createUser(user);
- throw new Exception("Unexpected success");
- } catch (PortalAPIException ex) {
- logger.info("caught expected exception: {}", ex.toString());
- }
+ });
Assert.assertFalse(dum.getUsers().isEmpty());
EcompUser fetched = dum.getUser(loginId);
Assert.assertEquals(fetched, user);
EcompUser missing = dum.getUser("foo");
Assert.assertNull(missing);
EcompUser unk = createEcompUser("unknown");
- try {
+ Assertions.assertThrows(PortalAPIException.class, () -> {
dum.updateUser("unk", unk);
- } catch (PortalAPIException ex) {
- logger.info("caught expected exception: {}", ex.toString());
- }
+ });
}
}
import java.lang.invoke.MethodHandles;
+import org.oransc.ric.portal.dashboard.exception.InvalidArgumentException;
import org.oransc.ric.portal.dashboard.model.RicRegionList;
import org.oransc.ricplt.appmgr.client.api.HealthApi;
import org.oransc.ricplt.appmgr.client.api.XappApi;
logger.debug("deployXapp of {} sleeping {}", inv.getArgument(0), delayMs);
Thread.sleep(delayMs);
}
+ XappDescriptor descr = inv.<XappDescriptor>getArgument(0);
+ if (descr == null || descr.getXappName() == null)
+ throw new InvalidArgumentException("Name is required");
return deployedXapps.get(0);
}).when(mockApi).deployXapp(any(XappDescriptor.class));
doAnswer(inv -> {
@Bean
public PortalAuthManager portalAuthManagerBean() throws Exception {
logger.debug("portalAuthManagerBean: app {}", appName);
- return new PortalAuthManager(appName, portalApiUsername, portalApiPassword,
- decryptor, userCookie);
+ return new PortalAuthManager(appName, portalApiUsername, portalApiPassword, decryptor, userCookie);
}
}
statsDetails.setMetricUrl("https://www.example2-next.com");
AppStats stNext = testRestTemplateAdminRole().postForObject(uri, statsDetails, AppStats.class);
Assertions.assertTrue(st.getStatsDetails().getAppId() < stNext.getStatsDetails().getAppId());
- try {
+ Assertions.assertThrows(RestClientException.class, () -> {
testRestTemplateAdminRole().postForObject(uri, statsDetails, AppStats.class);
- Assert.assertTrue(false);
- } catch (RestClientException ex) {
- logger.info("Caught exception on create as expected: {}", ex.toString());
- }
+ });
}
@Order(3)
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.RestClientException;
public class AppManagerControllerTest extends AbstractControllerTest {
URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.XAPPS_METHOD);
logger.info("Invoking {}", uri);
- XappDescriptor descr = new XappDescriptor();
+ XappDescriptor descr = new XappDescriptor().xappName("app");
Xapp app = testRestTemplateAdminRole().postForObject(uri, descr, Xapp.class);
+ Assertions.assertNotNull(app);
Assertions.assertFalse(app.getName().isEmpty());
+
+ // An invalid request must be rejected
+ Assertions.assertThrows(RestClientException.class, () -> {
+ testRestTemplateAdminRole().postForObject(uri, new XappDescriptor(), Xapp.class);
+ });
}
@Test
logger.info("Invoking {}", uri);
UpdateGnbRequest update = new UpdateGnbRequest();
HttpEntity<UpdateGnbRequest> entity = new HttpEntity<>(update);
- ResponseEntity<Void> voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.PUT, entity, Void.class);
+ ResponseEntity<Void> voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.PUT, entity,
+ Void.class);
Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
}
*/
package org.oransc.ric.portal.dashboard.k8sapi;
-import java.lang.invoke.MethodHandles;
-
-import org.junit.Assert;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.oransc.ric.portal.dashboard.util.HttpsURLConnectionUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate;
public class CaasIngressTest {
- private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
@Test
public void coverHttpsUtils() throws Exception {
HttpsURLConnectionUtils.turnOffSslChecking();
// Get IP address from REC deployment team for testing
final String podsUrl = "https://localhost:16443/api/v1/namespaces/ricaux/pods";
RestTemplate rt = new RestTemplate();
- try {
+ Assertions.assertThrows(Exception.class, () -> {
rt.getForEntity(podsUrl, String.class);
- Assert.assertTrue(false);
- } catch (Exception ex) {
- Assert.assertNotNull(ex);
- logger.warn("Failed as expected");
- }
+ });
HttpsURLConnectionUtils.turnOnSslChecking();
}
*/
package org.oransc.ric.portal.dashboard.k8sapi;
-import java.lang.invoke.MethodHandles;
-
-import org.junit.Assert;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class SimpleKubernetesClientTest {
- private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Test
public void simpleK8sClientTest() {
SimpleKubernetesClient client = new SimpleKubernetesClient("http://foo.bar");
- try {
- String json = client.listPods("namespace");
- Assert.assertNotNull(json);
- } catch (RuntimeException ex) {
- logger.warn("Failed as expected");
- }
+ Assertions.assertThrows(RuntimeException.class, () -> {
+ client.listPods("namespace");
+ });
}
}
import java.util.List;
import org.junit.Assert;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.onap.portalsdk.core.restful.domain.EcompUser;
import org.oransc.ric.portal.dashboard.DashboardUserManagerTest;
@Test
public void testRicRegionList() {
- RicRegionList m = new RicRegionList();
+ new RicRegionList();
List<RicRegion> list = new ArrayList<>();
- m = new RicRegionList(list);
+ final RicRegionList m = new RicRegionList(list);
Assert.assertEquals(list, m.getRegions());
Assert.assertNotNull(m.getSimpleInstances());
- try {
+ Assertions.assertThrows(UnknownInstanceException.class, () -> {
m.getInstance(s1);
- } catch (UnknownInstanceException ex) {
- logger.info("failed as expected: {}", ex.toString());
- }
+ });
logger.info(m.toString());
}
import javax.servlet.http.Cookie;
import org.junit.Assert;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.onap.portalsdk.core.onboarding.util.PortalApiConstants;
Assert.assertNull(s);
DashboardUserManager dum = new DashboardUserManager(true);
- PortalAuthenticationFilter filter = new PortalAuthenticationFilter(false, m, dum);
+ final PortalAuthenticationFilter filter = new PortalAuthenticationFilter(false, m, dum);
filter.init(null);
filter.destroy();
MockHttpServletResponse response = new MockHttpServletResponse();
- try {
+ Assertions.assertThrows(NullPointerException.class, () -> {
filter.doFilter(request, response, null);
- } catch (NullPointerException ex) {
- logger.debug("chain is null");
- }
+ });
- filter = new PortalAuthenticationFilter(true, m, dum);
- try {
- filter.doFilter(request, response, null);
- } catch (NullPointerException ex) {
- logger.debug("chain is null");
- }
+ PortalAuthenticationFilter filter2 = new PortalAuthenticationFilter(true, m, dum);
+ filter2.doFilter(request, response, null);
}
}
\ No newline at end of file
<parent>
<groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
<artifactId>ric-dash-parent</artifactId>
- <version>2.0.2-SNAPSHOT</version>
+ <version>2.0.3-SNAPSHOT</version>
</parent>
<!-- reuse parent groupId -->
<artifactId>ric-dash-fe</artifactId>
RIC Dashboard Release Notes
===========================
+Version 2.0.3, 19 May 2020
+--------------------------
+* Validate request bodies in backend REST controller methods
+
Version 2.0.2, 18 May 2020
--------------------------
-* Repair App Manager data models in webapp frontend
+* Repair App Manager data models in webapp frontend (`OAM-103 <https://jira.o-ran-sc.org/browse/OAM-103>`_)
Version 2.0.1, 30 Apr 2020
--------------------------