From 749749f288de7ef42e3d1507c7f07a4453a774b4 Mon Sep 17 00:00:00 2001 From: "Lott, Christopher (cl778h)" Date: Thu, 22 Aug 2019 21:07:50 -0400 Subject: [PATCH] Use new get method from A1 API for AC policy Upgrade A1 API spec to version 0.10.3 which defines object (not void) return value on the get-policy method. Extend AC FE screen to read policy using get method. Change controller name from AC to A1. Ensure numeric values go as numbers, not strings. Change-Id: I2cede67d499cb2d6a835d9a2938fedcafbe6eed4 Signed-off-by: Lott, Christopher (cl778h) --- a1-med-client/pom.xml | 4 +- ...ediator_0.10.0.yaml => a1_mediator_0.10.3.yaml} | 8 ++-- .../a1med/client/test/A1MediatorClientTest.java | 15 +++++-- docs/release-notes.rst | 5 ++- webapp-backend/pom.xml | 2 +- .../dashboard/config/WebSecurityConfiguration.java | 4 +- ...ppController.java => A1MediatorController.java} | 48 ++++++++++------------ .../config/A1MediatorMockConfiguration.java | 27 +++++++++++- ...llerTest.java => A1MediatorControllerTest.java} | 16 +++++--- .../dashboard/controller/AdminControllerTest.java | 14 +++---- .../src/app/ac-xapp/ac-xapp.component.html | 3 -- .../src/app/ac-xapp/ac-xapp.component.ts | 31 ++++++++++---- .../src/app/services/ac-xapp/ac-xapp.service.ts | 15 +++---- 13 files changed, 121 insertions(+), 71 deletions(-) rename a1-med-client/src/main/resources/{a1_mediator_0.10.0.yaml => a1_mediator_0.10.3.yaml} (97%) rename webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/{AcXappController.java => A1MediatorController.java} (67%) rename webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/{AcXappControllerTest.java => A1MediatorControllerTest.java} (77%) diff --git a/a1-med-client/pom.xml b/a1-med-client/pom.xml index dd4a9e30..edb1b4e1 100644 --- a/a1-med-client/pom.xml +++ b/a1-med-client/pom.xml @@ -31,7 +31,7 @@ limitations under the License. org.o-ran-sc.ric.plt.a1med.client a1-med-client RIC A1 Mediator client - 0.10.0-SNAPSHOT + 0.10.3-SNAPSHOT UTF-8 UTF-8 @@ -102,7 +102,7 @@ limitations under the License. generate - ${project.basedir}/src/main/resources/a1_mediator_0.10.0.yaml + ${project.basedir}/src/main/resources/a1_mediator_0.10.3.yaml java ${client.base.package.name} ${client.base.package.name}.model diff --git a/a1-med-client/src/main/resources/a1_mediator_0.10.0.yaml b/a1-med-client/src/main/resources/a1_mediator_0.10.3.yaml similarity index 97% rename from a1-med-client/src/main/resources/a1_mediator_0.10.0.yaml rename to a1-med-client/src/main/resources/a1_mediator_0.10.3.yaml index e2d17ccb..a49cf799 100644 --- a/a1-med-client/src/main/resources/a1_mediator_0.10.0.yaml +++ b/a1-med-client/src/main/resources/a1_mediator_0.10.3.yaml @@ -16,7 +16,7 @@ # ================================================================================== openapi: 3.0.0 info: - version: 0.10.0 + version: 0.10.3 title: RIC A1 paths: '/a1-p/healthcheck': @@ -43,13 +43,11 @@ paths: description: > Replace the current operation of policyname with the new parameters (replaces the current policy with the new one specified here). - Until there are standard policy definitions that are defined OUTSIDE of the scope of xapps, this API will be *very underspecified*. This is a known gap, do not despair. The PUT body is specified, *currently* in the xapp manifest that implements this policy; the caller should refer to the message_receives_payload_schema field to make this request. The return content is also specified as above (in the xapp manifest) in the message_sends_payload_schema field. - Eventually, we need concrete policy defintions that are decoupled from xapp, and then this API description will become more fully specified. tags: - A1 Mediator @@ -103,6 +101,10 @@ paths: '200': description: > The downstream component responsible for implementing this policy replied with a good response. Check the manifest for response details. + content: + application/json: + schema: + type: object '400': description: > The downstream component for implementing this policy does not support policy fetching. diff --git a/a1-med-client/src/test/java/org/oransc/ric/portal/dashboard/a1med/client/test/A1MediatorClientTest.java b/a1-med-client/src/test/java/org/oransc/ric/portal/dashboard/a1med/client/test/A1MediatorClientTest.java index c09858ed..73a28c88 100644 --- a/a1-med-client/src/test/java/org/oransc/ric/portal/dashboard/a1med/client/test/A1MediatorClientTest.java +++ b/a1-med-client/src/test/java/org/oransc/ric/portal/dashboard/a1med/client/test/A1MediatorClientTest.java @@ -28,7 +28,7 @@ import org.springframework.web.client.RestClientException; /** * Demonstrates use of the generated A1 mediator client. * - * The test fails because no server is available. + * The tests fail because no server is available. */ public class A1MediatorClientTest { @@ -38,8 +38,17 @@ public class A1MediatorClientTest { apiClient.setBasePath("http://localhost:30099/"); A1MediatorApi a1Api = new A1MediatorApi(apiClient); try { - a1Api.a1ControllerGetHandler("policy"); - System.out.println("getPolicy answered: " + apiClient.getStatusCode().toString()); + Object o = a1Api.a1ControllerGetHandler("policy"); + System.out.println( + "getPolicy answered code {} " + apiClient.getStatusCode().toString() + ", content " + o.toString()); + Assertions.assertTrue(apiClient.getStatusCode().is2xxSuccessful()); + } catch (RestClientException e) { + System.err.println("getPolicy failed: " + e.toString()); + } + try { + String policy = "{}"; + a1Api.a1ControllerPutHandler("policy", policy); + System.out.println("putPolicy answered: " + apiClient.getStatusCode().toString()); Assertions.assertTrue(apiClient.getStatusCode().is2xxSuccessful()); } catch (RestClientException e) { System.err.println("getPolicy failed: " + e.toString()); diff --git a/docs/release-notes.rst b/docs/release-notes.rst index 621a5e6f..1e6deb4b 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -23,7 +23,7 @@ Version 1.2.1, ? Aug 2019 ------------------------- * Add EPSDK-FW user management and Portal security -Version 1.2.0, 21 Aug 2019 +Version 1.2.0, 23 Aug 2019 -------------------------- * Split URL properties into prefix/suffix parts * Add jacoco plugin to back-end for code coverage @@ -32,7 +32,6 @@ Version 1.2.0, 21 Aug 2019 * Drop mock RAN names feature that supported R1 testing * Extend mock endpoints to simulate delay seen in tests * 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 20190815 * Add controller for page refresh of Angular routes @@ -46,6 +45,8 @@ Version 1.2.0, 21 Aug 2019 * Display AC xAPP metrics data via Kibana source (metrics.url.ac) on dashboard * Pass AC policy parameter without parsing as JSON * Use snake_case (not camelCase) names in AC policy front end +* Update A1 mediator client to spec version 0.10.3 +* Extend AC control screen to read policy from A1 Version 1.0.5, 5 July 2019 -------------------------- diff --git a/webapp-backend/pom.xml b/webapp-backend/pom.xml index 11f875a8..08cc563a 100644 --- a/webapp-backend/pom.xml +++ b/webapp-backend/pom.xml @@ -52,7 +52,7 @@ limitations under the License. org.o-ran-sc.ric.plt.a1med.client a1-med-client - 0.10.0-SNAPSHOT + 0.10.3-SNAPSHOT org.o-ran-sc.ric.plt.appmgr.client diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java index 92ea75e8..4e1ddb41 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java @@ -27,7 +27,7 @@ import org.onap.portalsdk.core.onboarding.crossapi.PortalRestAPIProxy; import org.onap.portalsdk.core.onboarding.util.PortalApiConstants; import org.oransc.ric.portal.dashboard.DashboardConstants; import org.oransc.ric.portal.dashboard.LoginServlet; -import org.oransc.ric.portal.dashboard.controller.AcXappController; +import org.oransc.ric.portal.dashboard.controller.A1MediatorController; import org.oransc.ric.portal.dashboard.controller.AdminController; import org.oransc.ric.portal.dashboard.controller.AnrXappController; import org.oransc.ric.portal.dashboard.controller.AppManagerController; @@ -93,7 +93,7 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { "/swagger-ui.html", // "/webjars/**", // PortalApiConstants.API_PREFIX + "/**", // - AcXappController.CONTROLLER_PATH + "/" + AcXappController.VERSION_METHOD, // + A1MediatorController.CONTROLLER_PATH + "/" + A1MediatorController.VERSION_METHOD, // AdminController.CONTROLLER_PATH + "/" + AdminController.HEALTH_METHOD, // AdminController.CONTROLLER_PATH + "/" + AdminController.VERSION_METHOD, // AnrXappController.CONTROLLER_PATH + "/" + AnrXappController.HEALTH_ALIVE_METHOD, // diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/AcXappController.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/A1MediatorController.java similarity index 67% rename from webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/AcXappController.java rename to webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/A1MediatorController.java index 1054cc82..a1180f6a 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/AcXappController.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/A1MediatorController.java @@ -34,6 +34,7 @@ import org.springframework.http.MediaType; import org.springframework.security.access.annotation.Secured; import org.springframework.util.Assert; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -43,7 +44,8 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; /** - * Proxies calls from the front end to the AC xApp via the A1 Mediator API. + * Proxies calls from the front end to the A1 Mediator API to get and put + * policies. The first application managed via this path is Admission Control. * * If a method throws RestClientResponseException, it is handled by * {@link CustomResponseEntityExceptionHandler#handleProxyMethodException(Exception, org.springframework.web.context.request.WebRequest)} @@ -51,25 +53,23 @@ import io.swagger.annotations.ApiParam; * returns status 500. */ @RestController -@RequestMapping(value = AcXappController.CONTROLLER_PATH, produces = MediaType.APPLICATION_JSON_VALUE) -public class AcXappController { +@RequestMapping(value = A1MediatorController.CONTROLLER_PATH, produces = MediaType.APPLICATION_JSON_VALUE) +public class A1MediatorController { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); // Publish paths in constants so tests are easy to write - public static final String CONTROLLER_PATH = DashboardConstants.ENDPOINT_PREFIX + "/xapp/admctl"; + public static final String CONTROLLER_PATH = DashboardConstants.ENDPOINT_PREFIX + "/a1-p"; // Endpoints public static final String VERSION_METHOD = DashboardConstants.VERSION_METHOD; - public static final String POLICY_METHOD = "policy"; - - // A "control" is an element in the XApp descriptor - private static final String AC_CONTROL_NAME = "admission_control_policy"; + // Path parameters + public static final String PP_POLICIES = "policies"; // Populated by the autowired constructor private final A1MediatorApi a1MediatorApi; @Autowired - public AcXappController(final A1MediatorApi a1MediatorApi) { + public A1MediatorController(final A1MediatorApi a1MediatorApi) { Assert.notNull(a1MediatorApi, "API must not be null"); this.a1MediatorApi = a1MediatorApi; if (logger.isDebugEnabled()) @@ -84,31 +84,27 @@ public class AcXappController { } /* - * This controller is deliberately kept ignorant of the data expected by AC. The - * fields are defined in the ACAdmissionIntervalControl Typescript interface. + * This method is deliberately kept ignorant of the data passing thru. */ - @ApiOperation(value = "Gets the admission control policy for AC xApp via the A1 Mediator") - @GetMapping(POLICY_METHOD) + @ApiOperation(value = "Gets the specified policy from the A1 Mediator") + @GetMapping(PP_POLICIES + "/{" + PP_POLICIES + "}") @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD }) - public Object getAdmissionControlPolicy(HttpServletResponse response) { - logger.debug("getAdmissionControlPolicy"); - response.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); - return null; + public Object getPolicy(@PathVariable(PP_POLICIES) String policyName) { + logger.debug("getPolicy {}", policyName); + return a1MediatorApi.a1ControllerGetHandler(policyName); } /* - * This controller is deliberately kept ignorant of the data expected by AC. The - * fields are defined in the ACAdmissionIntervalControl Typescript interface. AC - * uses snake_case keys but Jackson automatically converts to CamelCase on - * parse. To avoid this conversion, specify the request parameter as String. + * This method is deliberately kept ignorant of the data passing thru. */ - @ApiOperation(value = "Sets the admission control policy for AC xApp via the A1 Mediator") - @PutMapping(POLICY_METHOD) + @ApiOperation(value = "Puts the specified policy to the A1 Mediator") + @PutMapping(PP_POLICIES + "/{" + PP_POLICIES + "}") @Secured({ DashboardConstants.ROLE_ADMIN }) - public void putAdmissionControlPolicy(@ApiParam(value = "Admission control policy") @RequestBody String acPolicy, // + public void putPolicy(@PathVariable(PP_POLICIES) String policyName, + @ApiParam(value = "Policy body") @RequestBody String policy, // HttpServletResponse response) { - logger.debug("putAdmissionControlPolicy {}", acPolicy); - a1MediatorApi.a1ControllerPutHandler(AC_CONTROL_NAME, acPolicy); + logger.debug("putPolicy name {} value {}", policyName, policy); + a1MediatorApi.a1ControllerPutHandler(policyName, policy); response.setStatus(a1MediatorApi.getApiClient().getStatusCode().value()); } diff --git a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/A1MediatorMockConfiguration.java b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/A1MediatorMockConfiguration.java index aef5bc4c..bf74a91e 100644 --- a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/A1MediatorMockConfiguration.java +++ b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/A1MediatorMockConfiguration.java @@ -25,6 +25,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.lang.invoke.MethodHandles; +import java.util.HashMap; +import java.util.Map; import org.oransc.ric.a1med.client.api.A1MediatorApi; import org.oransc.ric.a1med.client.invoker.ApiClient; @@ -36,6 +38,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.http.HttpStatus; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * Creates a mock implementation of the A1 mediator client API. */ @@ -45,12 +50,28 @@ public class A1MediatorMockConfiguration { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + // A "control" is an element in the XApp descriptor + public static final String AC_CONTROL_NAME = "admission_control_policy"; + // Simulate remote method delay for UI testing @Value("${mock.config.delay:0}") private int delayMs; + private final Map appPolicyMap; + public A1MediatorMockConfiguration() { logger.info("Configuring mock A1 Mediator"); + appPolicyMap = new HashMap<>(); + // Define a mock AC policy + ObjectMapper mapper = new ObjectMapper(); + ObjectNode node = mapper.createObjectNode(); + // These fields are defined in the ACAdmissionIntervalControl + // Typescript interface, but are otherwise unknown to this backend. + node.put("enforce", Boolean.TRUE); + node.put("window_length", 0); + node.put("blocking_rate", 0); + node.put("trigger_threshold", 0); + appPolicyMap.put(AC_CONTROL_NAME, node.toString()); } private ApiClient apiClient() { @@ -70,13 +91,17 @@ public class A1MediatorMockConfiguration { logger.debug("a1ControllerGetHandler sleeping {}", delayMs); Thread.sleep(delayMs); } - return null; + String appName = inv.getArgument(0); + return appPolicyMap.get(appName); }).when(mockApi).a1ControllerGetHandler(any(String.class)); doAnswer(inv -> { if (delayMs > 0) { logger.debug("a1ControllerPutHandler sleeping {}", delayMs); Thread.sleep(delayMs); } + String appName = inv.getArgument(0); + String policy = inv.getArgument(1); + appPolicyMap.put(appName, policy); return null; }).when(mockApi).a1ControllerPutHandler(any(String.class), any(Object.class)); return mockApi; diff --git a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AcXappControllerTest.java b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/A1MediatorControllerTest.java similarity index 77% rename from webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AcXappControllerTest.java rename to webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/A1MediatorControllerTest.java index 7de3bcdd..f6c5f4b7 100644 --- a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AcXappControllerTest.java +++ b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/A1MediatorControllerTest.java @@ -23,8 +23,10 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.net.URI; +import org.junit.Assert; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.oransc.ric.portal.dashboard.config.A1MediatorMockConfiguration; import org.oransc.ric.portal.dashboard.model.SuccessTransport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,13 +37,13 @@ import org.springframework.http.ResponseEntity; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -public class AcXappControllerTest extends AbstractControllerTest { +public class A1MediatorControllerTest extends AbstractControllerTest { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @Test public void versionTest() { - URI uri = buildUri(null, AcXappController.CONTROLLER_PATH, AcXappController.VERSION_METHOD); + URI uri = buildUri(null, A1MediatorController.CONTROLLER_PATH, A1MediatorController.VERSION_METHOD); logger.info("Invoking {}", uri); SuccessTransport st = restTemplate.getForObject(uri, SuccessTransport.class); Assertions.assertFalse(st.getData().toString().isEmpty()); @@ -49,19 +51,21 @@ public class AcXappControllerTest extends AbstractControllerTest { @Test public void getTest() throws IOException { - // Always returns 501; surprised that no exception is thrown. - URI uri = buildUri(null, AcXappController.CONTROLLER_PATH, AcXappController.POLICY_METHOD); + URI uri = buildUri(null, A1MediatorController.CONTROLLER_PATH, A1MediatorController.PP_POLICIES, + A1MediatorMockConfiguration.AC_CONTROL_NAME); logger.info("Invoking {}", uri); ResponseEntity response = testRestTemplateStandardRole().exchange(uri, HttpMethod.GET, null, String.class); - Assertions.assertTrue(response.getStatusCode().is5xxServerError()); + Assertions.assertTrue(response.getStatusCode().is2xxSuccessful()); + Assert.assertFalse(response.getBody().isEmpty()); } @Test public void putTest() throws IOException { ObjectMapper mapper = new ObjectMapper(); JsonNode body = mapper.readTree("{ \"policy\" : true }"); - URI uri = buildUri(null, AcXappController.CONTROLLER_PATH, AcXappController.POLICY_METHOD); + URI uri = buildUri(null, A1MediatorController.CONTROLLER_PATH, A1MediatorController.PP_POLICIES, + A1MediatorMockConfiguration.AC_CONTROL_NAME); HttpEntity entity = new HttpEntity<>(body); logger.info("Invoking {}", uri); ResponseEntity voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.PUT, entity, diff --git a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AdminControllerTest.java b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AdminControllerTest.java index 8c61a4e4..604a071a 100644 --- a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AdminControllerTest.java +++ b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AdminControllerTest.java @@ -30,7 +30,6 @@ import org.junit.jupiter.api.Test; import org.oransc.ric.portal.dashboard.DashboardConstants; import org.oransc.ric.portal.dashboard.model.DashboardUser; import org.oransc.ric.portal.dashboard.model.ErrorTransport; -import org.oransc.ric.portal.dashboard.model.IDashboardResponse; import org.oransc.ric.portal.dashboard.model.SuccessTransport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -83,21 +82,22 @@ public class AdminControllerTest extends AbstractControllerTest { metricsQueryParms.put("app", DashboardConstants.APP_NAME_AC); URI uri = buildUri(metricsQueryParms, AdminController.CONTROLLER_PATH, AdminController.XAPPMETRICS_METHOD); logger.debug("Invoking {}", uri); - ResponseEntity successResponse = testRestTemplateStandardRole().exchange(uri, HttpMethod.GET, null, - SuccessTransport.class); + ResponseEntity successResponse = testRestTemplateStandardRole().exchange(uri, HttpMethod.GET, + null, SuccessTransport.class); Assertions.assertFalse(successResponse.getBody().getData().toString().isEmpty()); Assertions.assertTrue(successResponse.getStatusCode().is2xxSuccessful()); } @Test public void getxAppMetricsUrlTestFail() { - Map metricsQueryParms = new HashMap(); - //Providing a bogus value for application name in query parameter to test failure + Map metricsQueryParms = new HashMap(); + // Providing a bogus value for application name in query parameter to test + // failure metricsQueryParms.put("app", "ABCD"); URI uri = buildUri(metricsQueryParms, AdminController.CONTROLLER_PATH, AdminController.XAPPMETRICS_METHOD); logger.debug("Invoking {}", uri); - ResponseEntity errorResponse = testRestTemplateStandardRole().exchange(uri, HttpMethod.GET, null, - ErrorTransport.class); + ResponseEntity errorResponse = testRestTemplateStandardRole().exchange(uri, HttpMethod.GET, + null, ErrorTransport.class); logger.debug("{}", errorResponse.getBody().getError().toString()); Assertions.assertTrue(errorResponse.getStatusCode().is4xxClientError()); } diff --git a/webapp-frontend/src/app/ac-xapp/ac-xapp.component.html b/webapp-frontend/src/app/ac-xapp/ac-xapp.component.html index d6081b02..e6a70bf7 100644 --- a/webapp-frontend/src/app/ac-xapp/ac-xapp.component.html +++ b/webapp-frontend/src/app/ac-xapp/ac-xapp.component.html @@ -48,9 +48,6 @@
-
- AC API version {{acVersion}} -
\ No newline at end of file diff --git a/webapp-frontend/src/app/ac-xapp/ac-xapp.component.ts b/webapp-frontend/src/app/ac-xapp/ac-xapp.component.ts index f7c360cc..7cadd26c 100644 --- a/webapp-frontend/src/app/ac-xapp/ac-xapp.component.ts +++ b/webapp-frontend/src/app/ac-xapp/ac-xapp.component.ts @@ -24,6 +24,7 @@ import { ACAdmissionIntervalControl, ACAdmissionIntervalControlAck } from '../in import { ACXappService } from '../services/ac-xapp/ac-xapp.service'; import { ErrorDialogService } from '../services/ui/error-dialog.service'; import { NotificationService } from './../services/ui/notification.service'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'rd-ac-xapp', @@ -34,9 +35,6 @@ export class AcXappComponent implements OnInit { private acForm: FormGroup; - // this is probably the A1 version string - acVersion: string; - constructor( private acXappService: ACXappService, private errorDialogService: ErrorDialogService, @@ -46,22 +44,39 @@ export class AcXappComponent implements OnInit { const windowLengthPattern = /^([0-9]{1}|[1-5][0-9]{1}|60)$/; const blockingRatePattern = /^([0-9]{1,2}|100)$/; const triggerPattern = /^([0-9]+)$/; - // No way to fetch current settings via A1 at present this.acForm = new FormGroup({ // Names must match the ACAdmissionIntervalControl interface - enforce: new FormControl(true, [Validators.required]), + enforce: new FormControl(true, [Validators.required]), window_length: new FormControl('', [Validators.required, Validators.pattern(windowLengthPattern)]), blocking_rate: new FormControl('', [Validators.required, Validators.pattern(blockingRatePattern)]), trigger_threshold: new FormControl('', [Validators.required, Validators.pattern(triggerPattern)]) }); - this.acXappService.getVersion().subscribe((res: string) => this.acVersion = res); + // TODO: show pending action indicator + this.acXappService.getPolicy().subscribe((res: ACAdmissionIntervalControl) => { + this.acForm.controls['enforce'].setValue(res.enforce); + this.acForm.controls['window_length'].setValue(res.window_length); + this.acForm.controls['blocking_rate'].setValue(res.blocking_rate); + this.acForm.controls['trigger_threshold'].setValue(res.trigger_threshold); + // TODO: clear pending action indicator + }, + (error: HttpErrorResponse) => { + // TODO: clear pending action indicator + this.errorDialogService.displayError(error.message); + }); } updateAc = (acFormValue: ACAdmissionIntervalControl) => { if (this.acForm.valid) { - this.acXappService.putPolicy(acFormValue).subscribe( + // convert strings to numbers using the plus operator + const acFormValueConverted = { + enforce: acFormValue.enforce, + window_length: +acFormValue.window_length, + blocking_rate: +acFormValue.blocking_rate, + trigger_threshold: +acFormValue.trigger_threshold + }; + this.acXappService.putPolicy(acFormValueConverted).subscribe( response => { - if (response.status === 200 ) { + if (response.status === 200) { this.notificationService.success('AC update policy succeeded!'); } }, diff --git a/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.ts b/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.ts index 19e5fc94..47b54401 100644 --- a/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.ts +++ b/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.ts @@ -26,15 +26,16 @@ import { ACAdmissionIntervalControl, ACAdmissionIntervalControlAck } from '../.. import { DashboardSuccessTransport } from '../../interfaces/dashboard.types'; /** - * Services for calling the Dashboard's AC endpoints. + * Services for calling the Dashboard's A1 endpoints to get/put AC policies. */ @Injectable({ providedIn: 'root' }) export class ACXappService { - private basePath = 'api/xapp/admctl'; - private policyPath = 'policy'; + private basePath = 'api/a1-p'; + private policyPath = 'policies'; + private acPolicyName = 'admission_control_policy'; private buildPath(...args: any[]) { let result = this.basePath; @@ -61,21 +62,21 @@ export class ACXappService { } /** - * Gets admission control parameters. + * Gets admission control policy. * @returns Observable that should yield an ACAdmissionIntervalControl */ getPolicy(): Observable { - const url = this.buildPath(this.policyPath); + const url = this.buildPath(this.policyPath, this.acPolicyName); return this.httpClient.get(url); } /** - * Puts admission control parameters. + * Puts admission control policy. * @param policy an instance of ACAdmissionIntervalControl * @returns Observable that should yield a response code, no data */ putPolicy(policy: ACAdmissionIntervalControl): Observable { - const url = this.buildPath(this.policyPath); + const url = this.buildPath(this.policyPath, this.acPolicyName); return this.httpClient.put(url, policy, { observe: 'response' }); } -- 2.16.6