diff --git a/CHANGELOG.md b/CHANGELOG.md index e20afb66644..b69b3a4c374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## v1.148.0 (04/12/2023) + +### Bug Fixes: +- [#5476](https://github.com/telstra/open-kilda/pull/5476) Fix a bug with writing history before the history event is created. (Issue: [#4738](https://github.com/telstra/open-kilda/issues/4738)) + +### Improvements: +- [#5472](https://github.com/telstra/open-kilda/pull/5472) Remove opentsdb from Kilda-gui [**gui**] +- [#5479](https://github.com/telstra/open-kilda/pull/5479) kilda-gui deps update [**gui**] +- [#5483](https://github.com/telstra/open-kilda/pull/5483) [TEST]: Server42: Flow: Rtt stats: Adding origin [**tests**] +- [#5484](https://github.com/telstra/open-kilda/pull/5484) #5390: [TEST] Avoid possibility of Y-Flow's subflows vlan conflict (Issues: [#5390](https://github.com/telstra/open-kilda/issues/5390) [#5390](https://github.com/telstra/open-kilda/issues/5390)) [**tests**] +- [#5487](https://github.com/telstra/open-kilda/pull/5487) [TEST]: Rigel: Stats: Victoria [**tests**] +- [#5488](https://github.com/telstra/open-kilda/pull/5488) #5390: [TEST] Fix flaky HA-Flow ping test (Issues: [#5390](https://github.com/telstra/open-kilda/issues/5390) [#5390](https://github.com/telstra/open-kilda/issues/5390)) [**tests**] +- [#5461](https://github.com/telstra/open-kilda/pull/5461) Change health check test for the MySQL container. Update docs. (Issue: [#5459](https://github.com/telstra/open-kilda/issues/5459)) [**configuration**] + +For the complete list of changes, check out [the commit log](https://github.com/telstra/open-kilda/compare/v1.147.1...v1.148.0). + +### Affected Components: +history + +--- + ## v1.147.1 (27/11/2023) ### Bug Fixes: diff --git a/confd/templates/docker-compose/docker-compose.tmpl b/confd/templates/docker-compose/docker-compose.tmpl index a035e9426cf..3149b8bd91f 100644 --- a/confd/templates/docker-compose/docker-compose.tmpl +++ b/confd/templates/docker-compose/docker-compose.tmpl @@ -140,7 +140,11 @@ services: ports: - 8101:3306 healthcheck: - test: "mysqladmin -u kilda -pkilda ping" + test: "mysql -u kilda -pkilda --protocol=tcp -e 'use kilda; select count(user());'" + interval: 3s + timeout: 3s + retries: 5 + start_period: 20s networks: default: aliases: diff --git a/confd/templates/functional-tests/kilda.properties.tmpl b/confd/templates/functional-tests/kilda.properties.tmpl index 7ccec82965b..7ac3354ab17 100644 --- a/confd/templates/functional-tests/kilda.properties.tmpl +++ b/confd/templates/functional-tests/kilda.properties.tmpl @@ -18,7 +18,7 @@ hibernate.url = {{ getv "/kilda_hibernate_url" }} elasticsearch.endpoint={{ getv "/kilda_logging_elasticsearch_proto" }}://{{ getv "/kilda_logging_elasticsearch_hosts" }} zookeeper.connect_string = {{ getv "/kilda_zookeeper_hosts"}}/{{ getv "/kilda_zookeeper_state_root" }} legacy.tsdb.endpoint=http://{{ getv "/kilda_opentsdb_hosts" }}:{{ getv "/kilda_opentsdb_port" }} -tsdb.endpoint=http://{{ getv "/kilda_victoriametrics_host" }}:{{ getv "/kilda_victoriametrics_read_port" }}{{ getv "/kilda_tests_victoriametrics_query_path" }} +tsdb.endpoint={{ getv "/kilda_victoria_read_url_schema" }}://{{ getv "/kilda_victoriametrics_host" }}:{{ getv "/kilda_victoriametrics_read_port" }}{{ getv "/kilda_tests_victoriametrics_query_path" }} kafka.bootstrap.server={{ getv "/kilda_kafka_hosts" }} kafka.bootstrap.server.internal={{ getv "/kilda_kafka_hosts" }} grpc.endpoint={{ getv "/kilda_grpc_endpoint" }}:{{ getv "/kilda_grpc_rest_port" }} diff --git a/confd/templates/gui/application.properties.tmpl b/confd/templates/gui/application.properties.tmpl index ddd6346075e..766f81845ba 100644 --- a/confd/templates/gui/application.properties.tmpl +++ b/confd/templates/gui/application.properties.tmpl @@ -44,9 +44,8 @@ spring.mvc.throw-exception-if-no-handler-found=true #Northbound Base URL nb.base.url={{ getv "/kilda_northbound_endpoint" }}:{{ getv "/kilda_northbound_rest_port" }}/api -#OPEN TSDB Base URL and metric prefix -opentsdb.base.url=http://{{ getv "/kilda_opentsdb_hosts" }}:{{ getv "/kilda_opentsdb_port" }} -opentsdb.metric.prefix = {{ getv "/kilda_opentsdb_metric_prefix" }} +#Metric prefix +metric.prefix = {{ getv "/kilda_opentsdb_metric_prefix" }} #VICTORIA METRICS Base URL and metric prefix victoria.base.url={{ getv "/kilda_victoria_read_url_schema" }}://{{ getv "/kilda_victoriametrics_host" }}:{{ getv "/kilda_victoriametrics_read_port" }}{{ getv "/kilda_victoriametrics_read_path" }}/prometheus diff --git a/docker/db-mysql-migration/migrations/README.md b/docker/db-mysql-migration/migrations/README.md index 25392b31a48..847623c4af1 100644 --- a/docker/db-mysql-migration/migrations/README.md +++ b/docker/db-mysql-migration/migrations/README.md @@ -47,7 +47,7 @@ changeSet: To start DB update manually you need to compose a migration image and execute a migration script. Optionally, you can execute liquibase with arbitrary parameters. -To create an image, navigate to (TODO) +To create an image, navigate to the root of the OpenKilda project and execute: ```shell script docker-compose build db_mysql_migration ``` diff --git a/src-gui/Makefile b/src-gui/Makefile index d8e627c9757..73b868f9e32 100644 --- a/src-gui/Makefile +++ b/src-gui/Makefile @@ -8,8 +8,8 @@ build/libs/${APP}.war: .deps/node .deps/resources ./gradlew build .deps/node: | .deps - docker run --rm -e LOCAL_UID=`id -u $(USER)` -e LOCAL_GID=`id -g $(USER)` -v $(CURDIR)/src:/app/src -v $(CURDIR)/ui:/app/ui node:14.17-alpine \ - sh -c 'cd /app/ui && npm install && /app/ui/node_modules/.bin/ng build --prod && chown -R $$LOCAL_UID:$$LOCAL_GID /app' + docker run --rm -e LOCAL_UID=`id -u $(USER)` -e LOCAL_GID=`id -g $(USER)` -v $(CURDIR)/src:/app/src -v $(CURDIR)/ui:/app/ui node:18.18.2-alpine \ + sh -c 'cd /app/ui && npm install && /app/ui/node_modules/.bin/ng build --configuration production && chown -R $$LOCAL_UID:$$LOCAL_GID /app' .deps/resources: .deps mkdir -p src/main/webapp/lib/css/ diff --git a/src-gui/src/main/java/org/openkilda/config/ApplicationProperties.java b/src-gui/src/main/java/org/openkilda/config/ApplicationProperties.java index dc498b7c60b..b07b66bf32b 100644 --- a/src-gui/src/main/java/org/openkilda/config/ApplicationProperties.java +++ b/src-gui/src/main/java/org/openkilda/config/ApplicationProperties.java @@ -33,13 +33,10 @@ public class ApplicationProperties { @Value("${nb.base.url}") private String nbBaseUrl; - @Value("${opentsdb.base.url}") - private String openTsdbBaseUrl; - @Value("${victoria.base.url}") private String victoriaBaseUrl; - @Value("${opentsdb.metric.prefix}") + @Value("${metric.prefix}") private String metricPrefix; @Value("${kilda.username}") diff --git a/src-gui/src/main/java/org/openkilda/constants/Metrics.java b/src-gui/src/main/java/org/openkilda/constants/Metrics.java index 1c4ea606f0e..a0447c4b566 100644 --- a/src-gui/src/main/java/org/openkilda/constants/Metrics.java +++ b/src-gui/src/main/java/org/openkilda/constants/Metrics.java @@ -26,8 +26,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; import java.util.stream.Collectors; @Getter @@ -261,17 +259,4 @@ public static List list(String prefix) { return Arrays.stream(values()).map(metric -> metric.getMetricName(prefix)).collect(Collectors.toList()); } - /** - * Tags. - * - * @return the sets the - */ - public static Set tags() { - Set tags = new TreeSet<>(); - for (Metrics metric : values()) { - String[] v = metric.getTag().split("_"); - tags.add(v[1]); - } - return tags; - } } diff --git a/src-gui/src/main/java/org/openkilda/controller/StatsController.java b/src-gui/src/main/java/org/openkilda/controller/StatsController.java index 5f4b051d341..2d96ab07ef8 100644 --- a/src-gui/src/main/java/org/openkilda/controller/StatsController.java +++ b/src-gui/src/main/java/org/openkilda/controller/StatsController.java @@ -1,4 +1,4 @@ -/* Copyright 2018 Telstra Open Source +/* Copyright 2023 Telstra Open Source * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -82,78 +82,6 @@ public StatsController(StatsService statsService, ApplicationProperties applicat return Metrics.list(applicationProperties.getMetricPrefix()); } - - /** - * Gets the isl stats. - * - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @return the flow stats - */ - @RequestMapping(value = - "isl/{srcSwitch}/{srcPort}/{dstSwitch}/{dstPort}/{startDate}/{endDate}/{downsample}/{metric}", - method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @Permissions(values = {IConstants.Permission.MENU_ISL}) - @ResponseBody - public String getIslStats(@PathVariable String srcSwitch, @PathVariable String srcPort, - @PathVariable String dstSwitch, @PathVariable String dstPort, - @PathVariable String startDate, @PathVariable String endDate, - @PathVariable String downsample, @PathVariable String metric) { - - LOGGER.info("Get stat for Isl"); - return statsService.getSwitchIslStats(startDate, endDate, downsample, srcSwitch, srcPort, dstSwitch, dstPort, - metric); - - } - - /** - * Gets the port stats. - * - * @param switchid the switchid - * @param port the port - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @return the port stats - */ - @RequestMapping(value = "switchid/{switchid}/port/{port}/{startDate}/{endDate}/{downsample}/{metric}", - method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @Permissions(values = {IConstants.Permission.MENU_SWITCHES}) - @ResponseBody - public String getPortStats(@PathVariable String switchid, @PathVariable String port, - @PathVariable String startDate, @PathVariable String endDate, - @PathVariable String downsample, @PathVariable String metric) { - - LOGGER.info("Get stat for port"); - return statsService.getSwitchPortStats(startDate, endDate, downsample, switchid, port, metric); - - } - - /** - * Gets the flow stats. - * - * @param flowid the flowid - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @return the flow stats - */ - @RequestMapping(value = "flowid/{flowid:.+}/{startDate}/{endDate}/{downsample}/{metric}", - method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @Permissions(values = {IConstants.Permission.MENU_FLOWS}) - @ResponseBody - public String getFlowStats(@PathVariable String flowid, @PathVariable String startDate, - @PathVariable String endDate, @PathVariable String downsample, - @PathVariable String metric) { - - LOGGER.info("Get stat for flow"); - return statsService.getFlowStats(startDate, endDate, downsample, flowid, metric); - } - /** * Retrieves Victoria statistics data for a specific flow based on the provided parameters. * @@ -166,7 +94,7 @@ public String getFlowStats(@PathVariable String flowid, @PathVariable String sta * @return A {@link ResponseEntity} containing a {@link VictoriaStatsRes} object with the retrieved statistics. * @see VictoriaStatsRes */ - @RequestMapping(value = "victoria/{statsType}", + @RequestMapping(value = "flowgraph/{statsType}", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Permissions(values = {IConstants.Permission.MENU_FLOWS}) @@ -178,7 +106,7 @@ public ResponseEntity getFlowVictoriaStats(@PathVariable Strin @RequestParam String step, @RequestParam List metric, @RequestParam(required = false) String direction) { - + //TODO find a way to unite this controller method with the commonVictoriaStats method. LOGGER.info("Get victoria stat for flow"); if (StringUtils.isBlank(startDate)) { return buildVictoriaBadRequestErrorRes(REQUIRED_START_DATE_ERROR); @@ -201,73 +129,13 @@ public ResponseEntity getFlowVictoriaStats(@PathVariable Strin statsService.getTransformedFlowVictoriaStats(statsType, startDate, endDate, step, flowId, metric, Direction.byDisplayName(direction)); - Optional errorData = victoriaResult.stream().filter(this::hasError).findFirst(); - - if (errorData.isPresent()) { - VictoriaData err = errorData.get(); - res = buildVictoriaBadRequestErrorRes(Integer.parseInt(err.getErrorType()), err.getError()); - } else { - res = ResponseEntity.ok(VictoriaStatsRes.builder().status(SUCCESS) - .dataList(victoriaResult).build()); - } + res = convertToVictoriaStatsRes(victoriaResult); } catch (InvalidRequestException e) { res = buildVictoriaBadRequestErrorRes(e.getMessage()); } return res; } - /** - * Gets the switch isl loss packet stats. - * - * @param srcSwitch the src switch - * @param srcPort the src port - * @param dstSwitch the dst switch - * @param dstPort the dst port - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param metric the metric - * @return the isl loss packet stats - */ - @RequestMapping(value = - "isl/losspackets/{srcSwitch}/{srcPort}/{dstSwitch}/{dstPort}/{startDate}/{endDate}/{downsample}/{metric}", - method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @Permissions(values = {IConstants.Permission.MENU_ISL}) - @ResponseBody - public String getIslLossPacketStats(@PathVariable String srcSwitch, @PathVariable String srcPort, - @PathVariable String dstSwitch, @PathVariable String dstPort, - @PathVariable String startDate, @PathVariable String endDate, - @PathVariable String downsample, @PathVariable String metric) { - - LOGGER.info("Get stat of Isl loss packet"); - return statsService.getSwitchIslLossPacketStats(startDate, endDate, downsample, srcSwitch, srcPort, dstSwitch, - dstPort, metric); - } - - /** - * Gets the flow loss packet stats. - * - * @param flowid the flowid - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param direction the direction - * @return the flow loss packet stats - */ - @RequestMapping(value = "flow/losspackets/{flowid:.+}/{startDate}/{endDate}/{downsample}/{direction}", - method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @Permissions(values = {IConstants.Permission.MENU_FLOWS}) - @ResponseBody - public String getFlowLossPacketStats(@PathVariable String flowid, @PathVariable String startDate, - @PathVariable String endDate, @PathVariable String downsample, - @PathVariable String direction) { - - LOGGER.info("Get stat of flow loss packet"); - return statsService.getFlowLossPacketStats(startDate, endDate, downsample, flowid, direction); - } - /** * Gets the flow path stat from victoria db. * @@ -285,15 +153,7 @@ public ResponseEntity commonVictoriaStats(@RequestBody Victori try { List victoriaResult = statsService.getVictoriaStats(victoriaStatsReq); - Optional errorData = victoriaResult.stream().filter(this::hasError).findFirst(); - - if (errorData.isPresent()) { - VictoriaData err = errorData.get(); - res = buildVictoriaBadRequestErrorRes(Integer.parseInt(err.getErrorType()), err.getError()); - } else { - res = ResponseEntity.ok(VictoriaStatsRes.builder().status(SUCCESS) - .dataList(victoriaResult).build()); - } + res = convertToVictoriaStatsRes(victoriaResult); } catch (InvalidRequestException e) { res = buildVictoriaBadRequestErrorRes(e.getMessage()); } @@ -322,29 +182,18 @@ public List switchPortsStats(@RequestBody VictoriaStatsReq statsReq) t return statsService.getSwitchPortsStats(statsReq); } - - /** - * Gets the meter stats. - * - * @param flowid the flowid - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param direction the direction - * @param metric the metric - * @return the meter stats - */ - @RequestMapping(value = "meter/{flowid:.+}/{startDate}/{endDate}/{downsample}/{metric}/{direction}", - method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @Permissions(values = {IConstants.Permission.MENU_FLOWS}) - @ResponseBody - public String getMeterStats(@PathVariable String flowid, @PathVariable String startDate, - @PathVariable String endDate, @PathVariable String downsample, - @PathVariable String metric, @PathVariable String direction) { - - LOGGER.info("Get stat for meter"); - return statsService.getMeterStats(startDate, endDate, downsample, flowid, metric, direction); + private ResponseEntity convertToVictoriaStatsRes(List victoriaResult) { + ResponseEntity res; + Optional errorData = victoriaResult.stream().filter(this::hasError).findFirst(); + + if (errorData.isPresent()) { + VictoriaData err = errorData.get(); + res = buildVictoriaBadRequestErrorRes(Integer.parseInt(err.getErrorType()), err.getError()); + } else { + res = ResponseEntity.ok(VictoriaStatsRes.builder().status(SUCCESS) + .dataList(victoriaResult).build()); + } + return res; } private boolean hasError(VictoriaData victoriaData) { diff --git a/src-gui/src/main/java/org/openkilda/integration/service/StatsIntegrationService.java b/src-gui/src/main/java/org/openkilda/integration/service/StatsIntegrationService.java index e87564a1007..1630d623338 100644 --- a/src-gui/src/main/java/org/openkilda/integration/service/StatsIntegrationService.java +++ b/src-gui/src/main/java/org/openkilda/integration/service/StatsIntegrationService.java @@ -1,4 +1,4 @@ -/* Copyright 2019 Telstra Open Source +/* Copyright 2023 Telstra Open Source * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,38 +15,20 @@ package org.openkilda.integration.service; -import static org.apache.commons.collections4.CollectionUtils.isEmpty; -import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; - import org.openkilda.auth.context.ServerContext; import org.openkilda.auth.model.RequestContext; import org.openkilda.config.ApplicationProperties; import org.openkilda.constants.IAuthConstants; import org.openkilda.constants.IConstants; -import org.openkilda.constants.Metrics; -import org.openkilda.constants.OpenTsDb; -import org.openkilda.constants.OpenTsDb.StatsType; -import org.openkilda.helper.RestClientManager; -import org.openkilda.integration.exception.IntegrationException; -import org.openkilda.integration.exception.InvalidResponseException; -import org.openkilda.integration.model.Filter; -import org.openkilda.integration.model.IslStats; -import org.openkilda.integration.model.Query; import org.openkilda.model.victoria.RangeQueryParams; import org.openkilda.model.victoria.Status; import org.openkilda.model.victoria.dbdto.VictoriaDbRes; -import org.openkilda.utility.IoUtil; -import org.openkilda.utility.JsonUtil; -import org.openkilda.utility.StringUtil; -import com.fasterxml.jackson.core.JsonProcessingException; import org.apache.commons.lang.StringUtils; -import org.apache.http.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -55,34 +37,19 @@ import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * The Class StatsIntegrationService. - * - * @author Gaurav Chugh - */ - @Service public class StatsIntegrationService { private static final Logger LOGGER = LoggerFactory.getLogger(StatsIntegrationService.class); - private final RestClientManager restClientManager; private final ApplicationProperties appProps; private final ServerContext serverContext; private final RestTemplate restTemplate; - public StatsIntegrationService(RestClientManager restClientManager, ApplicationProperties appProps, - ServerContext serverContext, RestTemplate restTemplate) { - this.restClientManager = restClientManager; + public StatsIntegrationService(ApplicationProperties appProps, + ServerContext serverContext, + RestTemplate restTemplate) { this.appProps = appProps; this.serverContext = serverContext; this.restTemplate = restTemplate; @@ -135,434 +102,4 @@ private static HttpEntity> getMultiValueMapHttpEnt // Create HttpEntity with form data and headers return new HttpEntity<>(formData, headers); } - - /** - * Gets the stats. - * - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param switchId the switch id - * @param port the port - * @param flowId the flow id - * @param srcSwitch the src switch - * @param srcPort the src port - * @param dstSwitch the dst switch - * @param dstPort the dst port - * @param statsType the stats type - * @param metric the metric - * @param direction the direction - * @return the stats - * @throws IntegrationException the integration exception - */ - public String getStats(final String startDate, final String endDate, final String downsample, - final List switchId, final String port, final String flowId, - final String srcSwitch, final String srcPort, final String dstSwitch, final String dstPort, - final StatsType statsType, final String metric, final String direction) - throws IntegrationException { - - LOGGER.info("Inside getStats: switchId: " + switchId); - try { - String payload = getOpenTsdbRequestBody(startDate, endDate, downsample, switchId, port, flowId, srcSwitch, - srcPort, dstSwitch, dstPort, statsType, metric, direction); - - LOGGER.info("Inside getStats: startDate: " + startDate + ": endDate: " + endDate + ": payload: " + payload); - - HttpResponse response = restClientManager.invoke( - appProps.getOpenTsdbBaseUrl() + IConstants.OpenTsDbUrl.OPEN_TSDB_QUERY, - HttpMethod.POST, payload, "application/json", ""); - if (RestClientManager.isValidResponse(response)) { - return IoUtil.toString(response.getEntity().getContent()); - } - } catch (InvalidResponseException e) { - LOGGER.error("Error occurred while getting stats", e); - throw new InvalidResponseException(e.getCode(), e.getResponse()); - } catch (IOException e) { - LOGGER.warn("Error occurred while getting stats", e); - throw new IntegrationException(e); - } - return null; - } - - private String populateFiltersAndReturnDownsample(final List filters, final Map params, - final Integer index, final StatsType statsType) { - String downsample = ""; - if (params != null) { - for (Map.Entry param : params.entrySet()) { - if (param.getKey().equalsIgnoreCase("averageOf")) { - downsample = param.getValue().toString(); - } else if (param.getValue() != null) { - Filter filter = new Filter(); - filter.setGroupBy(OpenTsDb.GROUP_BY); - - if ((statsType.equals(StatsType.SWITCH_PORT) && param.getKey().equals("port")) - || ((statsType.equals(StatsType.FLOW_RAW_PACKET) || statsType.equals(StatsType.METER)) - && param.getKey().equals("cookie")) - || (statsType.equals(StatsType.METER) && param.getKey().equals("switchid")) - || (statsType.equals(StatsType.METER) && param.getKey().equals("direction") - && index == -1) - || (statsType.equals(StatsType.METER) && param.getKey().equals("meterid")) - ) { - filter.setType(OpenTsDb.TYPE_WILDCARD); - } else if (((statsType.equals(StatsType.FLOW_RAW_PACKET) && param.getKey().equals("switchid")) - || param.getKey().equals("flowid"))) { - String[] paramValue = param.getValue(); - if (paramValue[0].equals("*")) { - filter.setType(OpenTsDb.TYPE_WILDCARD); - } else { - filter.setType(OpenTsDb.TYPE); - } - } else { - filter.setType(OpenTsDb.TYPE); - } - filter.setTagk(param.getKey()); - if (index == 0 && param.getKey().equals("direction")) { - filter.setFilter("forward"); - } else if (index == 1 && param.getKey().equals("direction")) { - filter.setFilter("reverse"); - } else if (index == -1 && param.getKey().equals("direction")) { - filter.setFilter("*"); - } else { - filter.setFilter(param.getValue()[0]); - } - filters.add(filter); - } - } - } - return downsample; - } - - private Query getQuery(final String downsample, final String metric, final Map params, - final Integer index, final StatsType statsType) { - List filters = new ArrayList<>(); - String paramDownSample = ""; - if (params != null) { - paramDownSample = populateFiltersAndReturnDownsample(filters, params, index, statsType); - } - - if (!StringUtil.isNullOrEmpty(downsample)) { - paramDownSample = downsample + "-avg"; - } else if (!StringUtil.isNullOrEmpty(paramDownSample)) { - paramDownSample = paramDownSample + "-avg"; - } - Query query = new Query(); - query.setAggregator(OpenTsDb.AGGREGATOR); - if (!statsType.equals(StatsType.ISL)) { - query.setRate(OpenTsDb.RATE); - } - if (statsType.equals(StatsType.SWITCH_PORT) - && Metrics.SWITCH_STATE.getMetricName(appProps.getMetricPrefix()).equals(metric)) { - query.setRate(false); - } else { - if (validateDownSample(paramDownSample)) { - query.setDownsample(paramDownSample); - } - } - query.setMetric(metric); - query.setFilters(filters); - return query; - } - - private boolean validateDownSample(String paramDownSample) { - boolean isValidDownsample = false; - paramDownSample = paramDownSample.replaceFirst("^0+(?!$)", ""); - if (Character.isDigit(paramDownSample.charAt(0))) { - String[] downSampleArr = paramDownSample.split("-"); - if (downSampleArr.length > 0) { - String dwnSample = downSampleArr[0]; - Pattern pattern = Pattern.compile("[msh]"); - Matcher matcher = pattern.matcher(dwnSample); - if (matcher.find()) { - isValidDownsample = true; - } - } - } - return isValidDownsample; - } - - /** - * Sets the date format. - * - * @param date the date - * @return the string - */ - private String formatDate(final String date) { - return date.replaceFirst("-", "/").replaceFirst("-", "/"); - } - - private String getOpenTsdbRequestBody(final String startDate, final String endDate, final String downsample, - final List switchIds, final String port, final String flowId, - final String srcSwitch, final String srcPort, final String dstSwitch, - final String dstPort, final StatsType statsType, final String metric, - final String direction) throws JsonProcessingException { - LOGGER.info("Inside getOpenTsdbRequestBody :"); - - List queries = getQueries(downsample, switchIds, port, flowId, srcSwitch, srcPort, - dstSwitch, dstPort, statsType, metric, direction); - return getRequest(startDate, endDate, queries); - } - - private String getRequest(final String startDate, final String endDate, final List queryList) - throws JsonProcessingException { - IslStats islStatsRequest = new IslStats(); - islStatsRequest.setStart(formatDate(startDate)); - islStatsRequest.setEnd(formatDate(endDate)); - islStatsRequest.setQueries(queryList); - return JsonUtil.toString(islStatsRequest); - } - - /** - * Gets the metircs. - * - * @param statsType the stats type - * @param metric the metric - * @return the metircs - */ - private List getMetircs(StatsType statsType, String metric) { - List metricList = new ArrayList<>(); - if (statsType.equals(StatsType.PORT)) { - metricList = Metrics.switchValue(metric, appProps.getMetricPrefix()); - } else if (statsType.equals(StatsType.FLOW)) { - metricList = Metrics.flowValue(metric, true, appProps.getMetricPrefix()); - } else if (statsType.equals(StatsType.ISL)) { - metricList = Metrics.switchValue(metric, appProps.getMetricPrefix()); - } else if (statsType.equals(StatsType.ISL_LOSS_PACKET)) { - metricList = Metrics.switchValue(metric, appProps.getMetricPrefix()); - } else if (statsType.equals(StatsType.FLOW_LOSS_PACKET)) { - metricList = Metrics.flowValue("packets", false, appProps.getMetricPrefix()); - metricList.addAll(Metrics.flowValue(metric, false, appProps.getMetricPrefix())); - } else if (statsType.equals(StatsType.FLOW_RAW_PACKET)) { - metricList = Metrics.flowRawValue(metric, appProps.getMetricPrefix()); - } else if (statsType.equals(StatsType.SWITCH_PORT)) { - metricList = Metrics.getStartsWith("Switch_", appProps.getMetricPrefix()); - } else if (statsType.equals(StatsType.METER)) { - metricList = Metrics.meterValue(metric, appProps.getMetricPrefix()); - } - return metricList; - } - - /** - * Gets the queries. - * - * @param downsample the downsample - * @param switchIds the switch ids - * @param port the port - * @param flowId the flow id - * @param srcSwitch the src switch - * @param srcPort the src port - * @param dstSwitch the dst switch - * @param dstPort the dst port - * @param statsType the stats type - * @param metric the metric - * @param direction the direction - * @return the queries - */ - private List getQueries(final String downsample, final List switchIds, final String port, - final String flowId, final String srcSwitch, final String srcPort, - final String dstSwitch, final String dstPort, final StatsType statsType, - final String metric, final String direction) { - - List metricList = getMetircs(statsType, metric); - - List queries = new ArrayList<>(); - if (statsType.equals(StatsType.FLOW_LOSS_PACKET)) { - queries = getFlowLossPacketsQueries(queries, downsample, flowId, srcSwitch, srcPort, statsType, metricList, - direction); - } else if (statsType.equals(StatsType.ISL_LOSS_PACKET)) { - queries = getIslLossPacketsQueries(queries, downsample, flowId, srcSwitch, srcPort, dstSwitch, dstPort, - statsType, metricList); - } else if (statsType.equals(StatsType.FLOW_RAW_PACKET)) { - queries = getFlowRawPacketsQueries(queries, downsample, switchIds, flowId, - srcPort, dstPort, statsType, metricList, direction); - } else if (statsType.equals(StatsType.SWITCH_PORT)) { - queries = getSwitchPortQueries(queries, switchIds, metricList, statsType, downsample); - } else if (statsType.equals(StatsType.METER)) { - queries = getFlowMeterQueries(queries, downsample, flowId, direction, statsType, metricList); - } else { - String switchId = isEmpty(switchIds) ? null : switchIds.get(0); - Map params = getParam(statsType, switchId, port, flowId, srcSwitch, srcPort, dstSwitch, - dstPort); - if (isNotEmpty(metricList)) { - for (int index = 0; index < metricList.size(); index++) { - String metricName = metricList.get(index); - queries.add(getQuery(downsample, metricName, params, index, statsType)); - } - } - } - return queries; - } - - - private List getFlowMeterQueries(List queries, final String downsample, - final String flowId, final String direction, final StatsType statsType, - final List metricList) { - Map params = getParam(statsType, null, null, flowId, null, null, null, null); - int indexDirection = (direction.isEmpty() - || "forward".equalsIgnoreCase(direction)) ? 0 : - ("reverse".equalsIgnoreCase(direction)) ? 1 : -1; - if (metricList != null && !metricList.isEmpty()) { - for (String s : metricList) { - queries.add(getQuery(downsample, s, params, indexDirection, statsType)); - } - } - return queries; - } - - /** - * Gets the flow loss packets queries. - * - * @param queries the queries - * @param downsample the downsample - * @param flowId the flow id - * @param srcSwitch the src switch - * @param srcPort the src port - * @param statsType the stats type - * @param metricList the metric list - * @param direction the direction - * @return the flow loss packets queries - */ - private List getFlowLossPacketsQueries(List queries, final String downsample, final String flowId, - final String srcSwitch, final String srcPort, - final StatsType statsType, final List metricList, - final String direction) { - Map params = getParam(statsType, null, null, flowId, srcSwitch, srcPort, null, null); - int index = (direction.isEmpty() || "forward".equalsIgnoreCase(direction)) ? 0 : 1; - if (metricList != null && !metricList.isEmpty()) { - queries.add(getQuery(downsample, metricList.get(0), params, index, statsType)); - queries.add(getQuery(downsample, metricList.get(1), params, index, statsType)); - } - return queries; - } - - /** - * Gets the isl loss packets queries. - * - * @param queries the queries - * @param downsample the downsample - * @param flowId the flow id - * @param srcSwitch the src switch - * @param srcPort the src port - * @param dstSwitch the dst switch - * @param dstPort the dst port - * @param statsType the stats type - * @param metricList the metric list - * @return the isl loss packets queries - */ - private List getIslLossPacketsQueries(List queries, final String downsample, final String flowId, - final String srcSwitch, final String srcPort, final String dstSwitch, - final String dstPort, final StatsType statsType, - final List metricList) { - Map txParams = getParam(statsType, null, null, flowId, srcSwitch, srcPort, null, null); - Map rxParams = getParam(statsType, null, null, flowId, null, null, dstSwitch, dstPort); - if (metricList != null && !metricList.isEmpty()) { - queries.add(getQuery(downsample, metricList.get(0), rxParams, 0, statsType)); - queries.add(getQuery(downsample, metricList.get(1), txParams, 0, statsType)); - } - return queries; - } - - /** - * Gets the flow raw packets queries. - * - * @param queries the queries - * @param downsample the downsample - * @param switchIds the switch ids - * @param flowId the flow id - * @param statsType the stats type - * @param metricList the metric list - * @return the flow raw packets queries - */ - private List getFlowRawPacketsQueries(List queries, final String downsample, - final List switchIds, final String flowId, - final String srcPort, final String dstPort, final StatsType statsType, - final List metricList, - final String direction) { - Map params = getParam(StatsType.FLOW_RAW_PACKET, null, null, flowId, null, - srcPort, null, dstPort); - if (metricList != null && !metricList.isEmpty()) { - int index = (direction.isEmpty() || "forward".equalsIgnoreCase(direction)) ? 0 : 1; - - Query query = getQuery(downsample, metricList.get(0), params, index, statsType); - for (String switchId : switchIds) { - params = getParam(StatsType.SWITCH, switchId, null, null, null, srcPort, null, dstPort); - populateFiltersAndReturnDownsample(query.getFilters(), params, 0, statsType); - } - queries.add(query); - } - return queries; - } - - /** - * Gets the switch port queries. - * - * @param queries the queries - * @param switchIds the switch ids - * @param metricList the metric list - * @param statsType the stats type - * @param downsample the downsample - * @return the switch port queries - */ - private List getSwitchPortQueries(List queries, final List switchIds, - final List metricList, final StatsType statsType, - final String downsample) { - String switchId = switchIds.isEmpty() ? null : switchIds.get(0); - Map params = getParam(StatsType.PORT, switchId, "*", null, null, null, null, null); - if (metricList != null && !metricList.isEmpty()) { - for (String metricName : metricList) { - queries.add(getQuery(downsample, metricName, params, 0, statsType)); - } - } - return queries; - } - - private Map getParam(final StatsType statsType, final String switchId, final String port, - final String flowId, final String srcSwitch, final String srcPort, - final String dstSwitch, final String dstPort) { - Map params = new HashMap<>(); - - if (statsType.equals(StatsType.SWITCH)) { - params.put("switchid", new String[]{switchId}); - } else if (statsType.equals(StatsType.PORT)) { - params.put("switchid", new String[]{switchId}); - params.put("port", new String[]{port}); - } else if (statsType.equals(StatsType.FLOW) || statsType.equals(StatsType.FLOW_LOSS_PACKET)) { - params.put("flowid", new String[]{flowId}); - params.put("direction", new String[]{}); - } else if (statsType.equals(StatsType.ISL)) { - params.put("src_switch", new String[]{srcSwitch}); - params.put("src_port", new String[]{srcPort}); - params.put("dst_switch", new String[]{dstSwitch}); - params.put("dst_port", new String[]{dstPort}); - } else if (statsType.equals(StatsType.ISL_LOSS_PACKET)) { - if (srcSwitch == null && srcPort == null) { - params.put("switchid", new String[]{dstSwitch}); - params.put("port", new String[]{dstPort}); - } else { - params.put("switchid", new String[]{srcSwitch}); - params.put("port", new String[]{srcPort}); - } - } else if (statsType.equals(StatsType.FLOW_RAW_PACKET)) { - if (flowId == null) { - params.put("flowid", new String[]{"*"}); - } else { - params.put("flowid", new String[]{flowId}); - } - params.put("cookie", new String[]{"*"}); - params.put("direction", new String[]{}); - if (srcPort != null) { - params.put("inPort", new String[]{srcPort}); - } - if (dstPort != null) { - params.put("outPort", new String[]{dstPort}); - } - } else if (statsType.equals(StatsType.METER)) { - params.put("flowid", new String[]{flowId}); - params.put("cookie", new String[]{"*"}); - params.put("meterid", new String[]{"*"}); - params.put("switchid", new String[]{"*"}); - params.put("direction", new String[]{}); - } - return params; - } - } diff --git a/src-gui/src/main/java/org/openkilda/service/StatsService.java b/src-gui/src/main/java/org/openkilda/service/StatsService.java index be5bcc6011a..b09b7cb6225 100644 --- a/src-gui/src/main/java/org/openkilda/service/StatsService.java +++ b/src-gui/src/main/java/org/openkilda/service/StatsService.java @@ -1,4 +1,4 @@ -/* Copyright 2018 Telstra Open Source +/* Copyright 2023 Telstra Open Source * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import static org.openkilda.constants.Metrics.ISL_LATENCY; import static org.openkilda.constants.Metrics.ISL_RTT; import static org.openkilda.constants.Metrics.SWITCH_STATE; +import static org.openkilda.utility.VictoriaQueryUtil.buildRangeQueryParams; import org.openkilda.config.ApplicationProperties; import org.openkilda.constants.Direction; @@ -27,7 +28,6 @@ import org.openkilda.constants.OpenTsDb.StatsType; import org.openkilda.exception.InvalidRequestException; import org.openkilda.integration.converter.PortConverter; -import org.openkilda.integration.exception.IntegrationException; import org.openkilda.integration.model.response.IslLink; import org.openkilda.integration.model.response.IslPath; import org.openkilda.integration.service.StatsIntegrationService; @@ -64,13 +64,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; - -/** - * The Class StatsService. - * - * @author Gaurav Chugh - */ @Service public class StatsService { @@ -102,44 +95,6 @@ public StatsService(StatsIntegrationService statsIntegrationService, this.appProps = appProps; } - /** - * Gets the stats. - * - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param srcSwitch the src switch - * @param srcPort the src port - * @param dstSwitch the dst switch - * @param dstPort the dst port - * @param metric the metric - * @return the stats - * @throws IntegrationException the integration exception - */ - public String getSwitchIslStats(String startDate, String endDate, String downsample, String srcSwitch, - String srcPort, String dstSwitch, String dstPort, String metric) - throws IntegrationException { - return statsIntegrationService.getStats(startDate, endDate, downsample, null, null, null, srcSwitch, srcPort, - dstSwitch, dstPort, StatsType.ISL, metric, null); - } - - /** - * Gets the flow stats. - * - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param flowId the flow id - * @param metric the metric - * @return the flow stats - * @throws IntegrationException the integration exception - */ - public String getFlowStats(String startDate, String endDate, String downsample, String flowId, String metric) - throws IntegrationException { - return statsIntegrationService.getStats(startDate, endDate, downsample, null, null, flowId, null, null, null, - null, StatsType.FLOW, metric, null); - } - /** * Retrieves and transforms Victoria statistics data for a specific flow and metric. * @@ -195,63 +150,6 @@ public List getTransformedFlowVictoriaStats(String statsType, return victoriaDataList; } - /** - * Gets the switch stats. - * - * @param switchid the switchid - * @param portnumber the portnumber - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param metric the metric - * @return the switch stats - * @throws IntegrationException the integration exception - */ - public String getSwitchPortStats(String startDate, String endDate, String downsample, String switchid, - String portnumber, String metric) throws IntegrationException { - List switchIds = new ArrayList(); - switchIds.add(switchid); - return statsIntegrationService.getStats(startDate, endDate, downsample, switchIds, portnumber, - null, null, null, null, null, StatsType.PORT, metric, null); - } - - /** - * Gets the switch isl loss packet stats. - * - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param srcSwitch the src switch - * @param srcPort the src port - * @param dstSwitch the dst switch - * @param dstPort the dst port - * @param metric the metric - * @return the switch isl loss packet stats - */ - public String getSwitchIslLossPacketStats(String startDate, String endDate, String downsample, String srcSwitch, - String srcPort, String dstSwitch, String dstPort, String metric) { - return statsIntegrationService.getStats(startDate, endDate, downsample, null, null, null, srcSwitch, srcPort, - dstSwitch, dstPort, StatsType.ISL_LOSS_PACKET, metric, null); - } - - /** - * Gets the flow loss packet stats. - * - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param flowId the flow id - * @param direction the direction - * @return the flow loss packet stats - * @throws IntegrationException the integration exception - */ - public String getFlowLossPacketStats(String startDate, String endDate, String downsample, String flowId, - String direction) throws IntegrationException { - return statsIntegrationService.getStats(startDate, endDate, downsample, null, null, flowId, null, null, null, - null, StatsType.FLOW_LOSS_PACKET, Metrics.FLOW_INGRESS_PACKETS.getTag().replace("Flow_", ""), - direction); - } - /** * Retrieves Victoria Flow Path statistics data based on the provided request parameters. * @@ -322,25 +220,6 @@ public List getSwitchPortsStats(VictoriaStatsReq statsReq) throws Inva } - /** - * Gets the meter stats. - * - * @param startDate the start date - * @param endDate the end date - * @param downsample the downsample - * @param flowId the flow id - * @param metric the direction - * @return the flow stats - * @throws IntegrationException the integration exception - */ - public String getMeterStats(String startDate, String endDate, String downsample, - String flowId, String metric, String direction) - throws IntegrationException { - return statsIntegrationService.getStats(startDate, endDate, downsample, null, - null, flowId, null, null, null, null, - StatsType.METER, metric, direction); - } - private void processInventoryPorts(final List portStats, final List inventoryPorts) { if (!CollectionUtil.isEmpty(inventoryPorts)) { List discrepancyPorts = new ArrayList(); @@ -447,7 +326,7 @@ private double getLastValue(LinkedHashMap dps) { * @return the list */ private List getIslPorts(final Map> portStatsByPortNo, String switchid) { - List portInfos = getPortInfo(portStatsByPortNo); + List portInfos = buildPortInfos(portStatsByPortNo); String switchIdentifier = IoUtil.switchCodeToSwitchId(switchid); List switchLogicalPorts = switchIntegrationService.getLogicalPort(switchIdentifier); if (isNotEmpty(switchLogicalPorts)) { @@ -486,7 +365,7 @@ private List getIslPorts(final Map> portSt return portInfos; } - private List getPortInfo(final Map> portStatsByPortNo) { + private List buildPortInfos(final Map> portStatsByPortNo) { List portInfos = new ArrayList(); for (Map.Entry> portStats : portStatsByPortNo.entrySet()) { PortInfo portInfo = new PortInfo(); @@ -503,6 +382,26 @@ private List getPortInfo(final Map> portSt return portInfos; } + private List buildVictoriaDataList(VictoriaDbRes dbData, String metricName) { + List result = new ArrayList<>(); + if (dbData.getData() == null) { + return result; + } + + dbData.getData().getResult().stream() + .map(metricValues -> buildVictoriaData(dbData, metricName, metricValues)) + .forEach(result::add); + return result; + } + + private VictoriaData buildVictoriaData(VictoriaDbRes dbData, String metricName) { + MetricValues metricValues = null; + if (dbData.getData() != null && isNotEmpty(dbData.getData().getResult())) { + metricValues = dbData.getData().getResult().get(0); + } + return buildVictoriaData(dbData, metricName, metricValues); + } + private VictoriaData buildVictoriaData(VictoriaDbRes dbData, String metricName, MetricValues metricValues) { LinkedHashMap timeToValueMap = new LinkedHashMap<>(); Map tags = new HashMap<>(); @@ -523,26 +422,6 @@ private VictoriaData buildVictoriaData(VictoriaDbRes dbData, String metricName, .build(); } - private VictoriaData buildVictoriaData(VictoriaDbRes dbData, String metricName) { - MetricValues metricValues = null; - if (dbData.getData() != null && isNotEmpty(dbData.getData().getResult())) { - metricValues = dbData.getData().getResult().get(0); - } - return buildVictoriaData(dbData, metricName, metricValues); - } - - private List buildVictoriaDataList(VictoriaDbRes dbData, String metricName) { - List result = new ArrayList<>(); - if (dbData.getData() == null) { - return result; - } - - dbData.getData().getResult().stream() - .map(metricValues -> buildVictoriaData(dbData, metricName, metricValues)) - .forEach(result::add); - return result; - } - private Map buildQueryParamLabelFilters(String flowId, Direction direction) { Map queryParamLabelFilters = new LinkedHashMap<>(); queryParamLabelFilters.put("flowid", flowId); @@ -550,43 +429,6 @@ private Map buildQueryParamLabelFilters(String flowId, Direction return queryParamLabelFilters; } - private RangeQueryParams buildRangeQueryParams(Long startTimeStamp, Long endTimeStamp, - String step, String metricName, - Map queryParamLabelFilters, - boolean useRate, boolean useSum) { - return RangeQueryParams.builder() - .start(startTimeStamp) - .end(endTimeStamp) - .step(step) - .query(buildVictoriaRequestRangeQueryFormParam(metricName, queryParamLabelFilters, useRate, useSum)) - .build(); - } - - private String buildVictoriaRequestRangeQueryFormParam(String metricName, - Map queryParamLabelFilters, - boolean useRate, boolean useSum) { - String lableFilterString = queryParamLabelFilters.entrySet().stream() - .filter(keyValue -> !keyValue.getValue().equals("*")) - .map(entry -> String.format("%s='%s'", entry.getKey(), entry.getValue())) - .collect(Collectors.joining(", ")); - String labelList = String.join(",", queryParamLabelFilters.keySet()); - String query = String.format("%s{%s}", metricName.replace("-", "\\-"), lableFilterString); - if (useSum) { - query = addSumToQuery(query, labelList); - } - if (useRate) { - query = addRateToQuery(query); - } - return query; - } - - private String addRateToQuery(String query) { - return "rate(" + query + ")"; - } - - private String addSumToQuery(String query, String groupByLabels) { - return String.format("sum(" + query + ") by (%s)", groupByLabels); - } private void validateRequestParameters(String startDate, List metric, String flowId) throws InvalidRequestException { diff --git a/src-gui/src/main/java/org/openkilda/utility/VictoriaQueryUtil.java b/src-gui/src/main/java/org/openkilda/utility/VictoriaQueryUtil.java new file mode 100644 index 00000000000..df833d369b0 --- /dev/null +++ b/src-gui/src/main/java/org/openkilda/utility/VictoriaQueryUtil.java @@ -0,0 +1,79 @@ +/* Copyright 2023 Telstra Open Source + * + * 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. + */ + +package org.openkilda.utility; + +import org.openkilda.model.victoria.RangeQueryParams; + +import java.util.Map; +import java.util.stream.Collectors; + +public final class VictoriaQueryUtil { + + private VictoriaQueryUtil() { + + } + + /** + * Builds and returns RangeQueryParams for a given time range, metric, and optional query parameters. + * + * @param startTimeStamp The start timestamp of the time range. + * @param endTimeStamp The end timestamp of the time range. + * @param step The time step interval for data points. + * @param metricName The name of the metric to query. + * @param queryParamLabelFilters A map of label filters for the metric query. + * @param useRate A flag indicating whether to calculate the rate. + * @param useSum A flag indicating whether to calculate the sum. + * @return RangeQueryParams object representing the parameters for the range query. + */ + public static RangeQueryParams buildRangeQueryParams(Long startTimeStamp, Long endTimeStamp, + String step, String metricName, + Map queryParamLabelFilters, + boolean useRate, boolean useSum) { + return RangeQueryParams.builder() + .start(startTimeStamp) + .end(endTimeStamp) + .step(step) + .query(buildVictoriaRequestRangeQueryFormParam(metricName, queryParamLabelFilters, useRate, useSum)) + .build(); + } + + private static String buildVictoriaRequestRangeQueryFormParam(String metricName, + Map queryParamLabelFilters, + boolean useRate, boolean useSum) { + String lableFilterString = queryParamLabelFilters.entrySet().stream() + .filter(keyValue -> !keyValue.getValue().equals("*")) + .map(entry -> String.format("%s='%s'", entry.getKey(), entry.getValue())) + .collect(Collectors.joining(", ")); + String labelList = String.join(",", queryParamLabelFilters.keySet()); + String query = String.format("%s{%s}", metricName.replace("-", "\\-"), lableFilterString); + if (useSum) { + query = addSumToQuery(query, labelList); + } + if (useRate) { + query = addRateToQuery(query); + } + return query; + } + + private static String addRateToQuery(String query) { + return "rate(" + query + ")"; + } + + private static String addSumToQuery(String query, String groupByLabels) { + return String.format("sum(" + query + ") by (%s)", groupByLabels); + } + +} diff --git a/src-gui/src/main/resources/application.properties.example b/src-gui/src/main/resources/application.properties.example index 19e7121cd90..eb0298649a1 100644 --- a/src-gui/src/main/resources/application.properties.example +++ b/src-gui/src/main/resources/application.properties.example @@ -30,9 +30,8 @@ spring.mvc.throw-exception-if-no-handler-found=true #Northbound Base URL nb.base.url=http://northbound.pendev:8080/api -#OPEN TSDB Base URL -opentsdb.base.url=http://opentsdb.pendev:4242 -opentsdb.metric.prefix = kilda. +#Metric prefix +metric.prefix = kilda. #VICTORIA METRICS Base URL victoria.base.url=http://victoriametrics.pendev:8428/prometheus diff --git a/src-gui/ui/.eslintrc.js b/src-gui/ui/.eslintrc.js new file mode 100644 index 00000000000..36b0ed8605b --- /dev/null +++ b/src-gui/ui/.eslintrc.js @@ -0,0 +1,209 @@ +/* +👋 Hi! This file was autogenerated by tslint-to-eslint-config. +https://github.com/typescript-eslint/tslint-to-eslint-config + +It represents the closest reasonable ESLint configuration to this +project's original TSLint configuration. + +We recommend eventually switching this configuration to extend from +the recommended rulesets in typescript-eslint. +https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md + +Happy linting! 💖 +*/ +module.exports = { + "env": { + "browser": true, + "es6": true, + "node": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "plugins": [ + "eslint-plugin-import", + "@angular-eslint/eslint-plugin", + "@typescript-eslint", + "@typescript-eslint/tslint" + ], + "root": true, + "rules": { + "@angular-eslint/component-class-suffix": "error", + "@angular-eslint/directive-class-suffix": "error", + "@angular-eslint/no-host-metadata-property": "error", + "@angular-eslint/no-input-rename": "error", + "@angular-eslint/no-inputs-metadata-property": "error", + "@angular-eslint/no-output-on-prefix": "error", + "@angular-eslint/no-output-rename": "error", + "@angular-eslint/no-outputs-metadata-property": "error", + "@angular-eslint/use-lifecycle-interface": "error", + "@angular-eslint/use-pipe-transform-interface": "error", + "@typescript-eslint/consistent-type-definitions": "error", + "@typescript-eslint/dot-notation": "off", + "@typescript-eslint/explicit-member-accessibility": [ + "off", + { + "accessibility": "explicit" + } + ], + "@typescript-eslint/indent": "error", + "@typescript-eslint/member-delimiter-style": [ + "error", + { + "multiline": { + "delimiter": "semi", + "requireLast": true + }, + "singleline": { + "delimiter": "semi", + "requireLast": false + } + } + ], + "@typescript-eslint/member-ordering": "error", + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "variable", + "format": [ + "camelCase", + "UPPER_CASE" + ], + "leadingUnderscore": "forbid", + "trailingUnderscore": "forbid" + } + ], + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-empty-interface": "error", + "@typescript-eslint/no-inferrable-types": [ + "error", + { + "ignoreParameters": true + } + ], + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-non-null-assertion": "error", + "@typescript-eslint/no-shadow": [ + "error", + { + "hoist": "all" + } + ], + "@typescript-eslint/no-unused-expressions": "error", + "@typescript-eslint/no-use-before-define": "error", + "@typescript-eslint/prefer-function-type": "error", + "@typescript-eslint/quotes": [ + "error", + "single" + ], + "@typescript-eslint/semi": [ + "error", + "always" + ], + "@typescript-eslint/type-annotation-spacing": "error", + "@typescript-eslint/unified-signatures": "error", + "arrow-body-style": "error", + "brace-style": [ + "error", + "1tbs" + ], + "constructor-super": "error", + "curly": "error", + "dot-notation": "off", + "eol-last": "error", + "eqeqeq": [ + "error", + "smart" + ], + "guard-for-in": "error", + "id-denylist": "off", + "id-match": "off", + "import/no-deprecated": "warn", + "indent": "off", + "max-len": [ + "error", + { + "code": 140 + } + ], + "no-bitwise": "error", + "no-caller": "error", + "no-console": [ + "error", + { + "allow": [ + "log", + "warn", + "dir", + "timeLog", + "assert", + "clear", + "count", + "countReset", + "group", + "groupEnd", + "table", + "dirxml", + "error", + "groupCollapsed", + "Console", + "profile", + "profileEnd", + "timeStamp", + "context", + "createTask" + ] + } + ], + "no-debugger": "error", + "no-empty": "off", + "no-empty-function": "off", + "no-eval": "error", + "no-fallthrough": "error", + "no-new-wrappers": "error", + "no-restricted-imports": [ + "error", + "rxjs/Rx" + ], + "no-shadow": "off", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-undef-init": "error", + "no-underscore-dangle": "off", + "no-unused-expressions": "off", + "no-unused-labels": "error", + "no-use-before-define": "off", + "no-var": "error", + "prefer-const": "error", + "quotes": "off", + "radix": "error", + "semi": "off", + "spaced-comment": [ + "error", + "always", + { + "markers": [ + "/" + ] + } + ], + "@typescript-eslint/tslint/config": [ + "error", + { + "rules": { + "import-spacing": true, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ] + } + } + ] + } +}; diff --git a/src-gui/ui/angular.json b/src-gui/ui/angular.json index 1245a54d841..4aff44dde5f 100644 --- a/src-gui/ui/angular.json +++ b/src-gui/ui/angular.json @@ -41,12 +41,13 @@ ], "scripts": [ "node_modules/jquery/dist/jquery.js", + "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js", "node_modules/datatables.net/js/jquery.dataTables.js", "src/assets/alertifyjs/alertify.js", "node_modules/dygraphs/dist/dygraph.min.js", "src/assets/js/moment.js", "src/assets/js/jquery.datetimepicker.full.js", - "node_modules/d3/build/d3.min.js", + "node_modules/d3/dist/d3.min.js", "node_modules/dt-colresize/js/dataTables.colResize.js", "node_modules/jszip/dist/jszip.js", "node_modules/datatables.net-buttons/js/dataTables.buttons.js", @@ -67,7 +68,6 @@ "optimization": true, "outputHashing": "all", "sourceMap": false, - "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": false, @@ -109,11 +109,11 @@ "src/assets" ] - + } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { "tsConfig": [ "src/tsconfig.app.json", @@ -143,7 +143,7 @@ } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { "tsConfig": "e2e/tsconfig.e2e.json", "exclude": [ @@ -153,6 +153,5 @@ } } } - }, - "defaultProject": "ui" -} \ No newline at end of file + } +} diff --git a/src-gui/ui/package.json b/src-gui/ui/package.json index d8fa796d391..b05ee2cbdc7 100644 --- a/src-gui/ui/package.json +++ b/src-gui/ui/package.json @@ -4,80 +4,79 @@ "scripts": { "ng": "ng", "start": "ng serve", - "build": "ng build --prod && cd.. && cp src/main/resources/ui/index.html src/main/resources/ui/index.php", + "build": "ng build --configuration production && cd.. && cp src/main/resources/ui/index.html src/main/resources/ui/index.php", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, "private": true, "dependencies": { - "@angular/animations": "^8.2.14", - "@angular/cdk": "^6.4.7", - "@angular/common": "^8.2.14", - "@angular/compiler": "^8.2.14", - "@angular/core": "^8.2.14", - "@angular/forms": "^8.2.14", - "@angular/platform-browser": "^8.2.14", - "@angular/platform-browser-dynamic": "^8.2.14", - "@angular/router": "^8.2.14", - "@ng-bootstrap/ng-bootstrap": "^3.2.0", - "@ng-select/ng-select": "^2.8.0", - "@types/d3": "^4.13.0", - "@types/geojson": "7946.0.8", - "@types/jqueryui": "^1.12.4", - "angular-datatables": "^6.0.0", - "angular-font-awesome": "^3.1.2", - "angular-progress-bar": "^1.0.9", - "bootstrap": "^4.1.3", - "core-js": "^2.5.4", - "d3": "^4.13.0", - "datatables.net": "^1.10.19", - "datatables.net-buttons": "^1.5.4", - "datatables.net-buttons-dt": "^1.5.4", - "datatables.net-dt": "^1.10.19", + "@angular/animations": "16.2.12", + "@angular/cdk": "16.2.12", + "@angular/common": "16.2.12", + "@angular/core": "16.2.12", + "@angular/forms": "16.2.12", + "@angular/platform-browser": "16.2.12", + "@angular/platform-browser-dynamic": "16.2.12", + "@angular/router": "16.2.12", + "@fortawesome/angular-fontawesome": "0.13.0", + "@ng-bootstrap/ng-bootstrap": "^15.1.2", + "@ng-select/ng-select": "^11.2.0", + "@perfectmemory/ngx-contextmenu": "16.0.2", + "@types/d3": "^7.4.3", + "angular-datatables": "16.0.1", + "bootstrap": "^4.6.2", + "d3": "^7.8.5", + "datatables.net": "^1.13.7", + "datatables.net-buttons": "^2.4.2", + "datatables.net-buttons-dt": "^2.4.2", + "datatables.net-dt": "^1.13.7", "dt-colresize": "^2.6.0", - "dygraphs": "^2.1.0", + "dygraphs": "^2.2.1", "font-awesome": "^4.7.0", - "jquery": "^3.3.1", - "jszip": "^3.1.5", - "moment": "^2.22.2", - "ng-click-outside": "^4.0.0", - "ng-dygraphs": "^0.4.0", - "ng-select2-component": "^6.0.1", - "ngx-clipboard": "^12.3.1", - "ngx-contextmenu": "5.0.3", - "ngx-moment": "^3.1.0", - "ngx-spinner": "^7.1.4", - "ngx-toastr": "^9.0.2", - "ngx-typeahead": "^6.0.0", + "jquery": "^3.7.1", + "jszip": "^3.10.1", + "moment": "^2.29.4", + "ng-click-outside": "^9.0.0", + "ng-select2-component": "11.1.0", + "ngx-clipboard": "^16.0.0", + "ngx-infinite-scroll": "16.0.0", + "ngx-spinner": "^16.0.2", + "ngx-toastr": "^18.0.0", "ol": "6.3.1", - "open-iconic": "^1.1.1", - "rxjs": "6.6.7", - "tslib": "^1.9.0", - "zone.js": "~0.9.1" + "rxjs": "7.4.0", + "zone.js": "~0.13.0" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.803.29", - "@angular/cli": "~8.3.29", - "@angular/compiler-cli": "^8.2.14", - "@angular/language-service": "^8.2.14", - "@types/datatables.net": "^1.10.13", - "@types/datatables.net-buttons": "^1.4.0", - "@types/jasmine": "~2.8.6", - "@types/jasminewd2": "~2.0.3", - "@types/jquery": "^3.3.6", - "@types/node": "~8.9.4", - "codelyzer": "^5.0.1", - "jasmine-core": "~2.99.1", - "jasmine-spec-reporter": "~4.2.1", - "karma": "^4.4.1", - "karma-chrome-launcher": "~2.2.0", - "karma-coverage-istanbul-reporter": "~2.0.0", - "karma-jasmine": "~1.1.1", - "karma-jasmine-html-reporter": "^0.2.2", - "protractor": "~5.4.0", - "ts-node": "~5.0.1", - "tslint": "~5.9.1", - "typescript": "~3.5.3" + "@angular-devkit/build-angular": "16.2.10", + "@angular-eslint/builder": "16.3.1", + "@angular-eslint/eslint-plugin": "16.3.1", + "@angular-eslint/eslint-plugin-template": "16.3.1", + "@angular-eslint/schematics": "16.3.1", + "@angular-eslint/template-parser": "16.3.1", + "@angular/cli": "16.2.10", + "@angular/compiler-cli": "16.2.12", + "@angular/language-service": "16.2.12", + "@angular/localize": "^16.2.12", + "@types/datatables.net": "^1.10.27", + "@types/datatables.net-buttons": "^1.4.10", + "@types/jasmine": "^5.1.2", + "@types/jasminewd2": "^2.0.13", + "@types/node": "~20.9.0", + "@typescript-eslint/eslint-plugin": "5.62.0", + "@typescript-eslint/eslint-plugin-tslint": "^6.11.0", + "@typescript-eslint/parser": "5.62.0", + "eslint": "^8.51.0", + "eslint-plugin-import": "^2.29.0", + "jasmine-core": "~5.1.1", + "jasmine-spec-reporter": "~7.0.0", + "karma": "^6.4.2", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage-istanbul-reporter": "~3.0.3", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "^2.1.0", + "protractor": "^7.0.0", + "ts-node": "~10.9.1", + "typescript": "5.1.6" } } diff --git a/src-gui/ui/src/app/app.module.ts b/src-gui/ui/src/app/app.module.ts index 69faaf27714..5b7d46ec749 100644 --- a/src-gui/ui/src/app/app.module.ts +++ b/src-gui/ui/src/app/app.module.ts @@ -1,7 +1,6 @@ import {BrowserModule, Title} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {DataTablesModule} from 'angular-datatables'; -import {AngularFontAwesomeModule} from 'angular-font-awesome'; import {AppRoutingModule} from './app-routing.module'; import {NgSelectModule} from '@ng-select/ng-select'; import {ReactiveFormsModule} from '@angular/forms'; @@ -10,11 +9,9 @@ import {Select2Module} from 'ng-select2-component'; import {HttpClientModule} from '@angular/common/http'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {ToastrModule} from 'ngx-toastr'; -import {NgDygraphsModule} from 'ng-dygraphs'; import {NgxSpinnerModule} from 'ngx-spinner'; import {ClipboardModule} from 'ngx-clipboard'; import {NgbModule} from '@ng-bootstrap/ng-bootstrap'; -import {NgxTypeaheadModule} from 'ngx-typeahead'; import {AppComponent} from './app.component'; import {SidebarComponent} from './common/components/sidebar/sidebar.component'; import {HeaderComponent} from './common/components/header/header.component'; @@ -74,9 +71,9 @@ import {AffectedIslComponent} from './modules/topology/affected-isl/affected-isl import {FailedIslComponent} from './modules/topology/failed-isl/failed-isl.component'; import {UnidirectionalIslComponent} from './modules/topology/unidirectional-isl/unidirectional-isl.component'; import {SettingsComponent} from './modules/settings/settings.component'; +import {CustomDygraphsComponent} from './common/components/custom-ng-dygraphs/custom-dygraphs.component'; import {IdentityServerComponent} from './modules/settings/identity-server/identity-server.component'; import {LinkStoreComponent} from './modules/settings/link-store/link-store.component'; -import {ContextMenuModule} from 'ngx-contextmenu'; import {ModalconfirmationComponent} from './common/components/modalconfirmation/modalconfirmation.component'; import {LogoutComponent} from './common/components/logout/logout.component'; import {FlowDatatablesComponent} from './modules/flows/flow-datatables/flow-datatables.component'; @@ -112,11 +109,14 @@ import {SwitchupdatemodalComponent} from './common/components/switchupdatemodal/ import {UseractivityListComponent} from './modules/useractivity/useractivity-list/useractivity-list.component'; import {FlowPingModalComponent} from './common/components/flow-ping-modal/flow-ping-modal.component'; import { CreateLagPortComponent } from './modules/switches/create-lag-port/create-lag-port.component'; +import {ContextMenuModule} from '@perfectmemory/ngx-contextmenu'; +import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; @NgModule({ declarations: [ AppComponent, SidebarComponent, + CustomDygraphsComponent, HeaderComponent, HomeComponent, TopologyComponent, @@ -211,16 +211,14 @@ import { CreateLagPortComponent } from './modules/switches/create-lag-port/creat imports: [ HttpClientModule, BrowserModule, - NgDygraphsModule, AppRoutingModule, - AngularFontAwesomeModule, + FontAwesomeModule, DataTablesModule, NgSelectModule, ReactiveFormsModule, Select2Module, ClipboardModule, NgbModule, - NgxTypeaheadModule, BrowserAnimationsModule, // required animations module ToastrModule.forRoot({ timeOut: 4000, @@ -228,31 +226,11 @@ import { CreateLagPortComponent } from './modules/switches/create-lag-port/creat preventDuplicates: true, }), NgxSpinnerModule, - ContextMenuModule.forRoot({ - autoFocus: true - }), ClickOutsideModule, - FormsModule + FormsModule, + ContextMenuModule ], providers: [SwitchidmaskPipe, AlertifyService, Title, AppAuthProvider], - bootstrap: [AppComponent], - entryComponents: [ - OtpComponent, - ModalComponent, - ModalconfirmationComponent, - FlowReRouteModalComponent, - ChangepasswordComponent, - AffectedIslComponent, - FlowGraphComponent, - FlowPathGraphComponent, - FlowContractsComponent, - ResetPasswordComponent, - ImportTopologySettingComponent, - ExportTopologySettingComponent, - IslmaintenancemodalComponent, - SwitchupdatemodalComponent, - FlowPingModalComponent, - CreateLagPortComponent, - ] + bootstrap: [AppComponent] }) export class AppModule { } diff --git a/src-gui/ui/src/app/common/components/custom-ng-dygraphs/custom-dygraphs.component.css b/src-gui/ui/src/app/common/components/custom-ng-dygraphs/custom-dygraphs.component.css new file mode 100644 index 00000000000..e4c3c661ef0 --- /dev/null +++ b/src-gui/ui/src/app/common/components/custom-ng-dygraphs/custom-dygraphs.component.css @@ -0,0 +1,102 @@ +.app-custom-dygraphs { + position: relative; } + .app-custom-dygraphs .name-nodes-holder { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding-right: 30px; + padding-left: 30px; } + .app-custom-dygraphs .name-nodes-holder .checkbox { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; } + .app-custom-dygraphs .dygraphs-chart-container { + background-color: #fff; + padding: 24px; } + .app-custom-dygraphs .dygraphs-chart-container .nodata { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + color: #5c5c5c; + font-weight: bold; + font-size: 24px; + display: flex; + align-content: center; } + .app-custom-dygraphs .dygraphs-chart-container .hide { + display: none; } + .app-custom-dygraphs .loader-holder { + position: absolute; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + width: 100%; + height: 100%; + background-color: #fff; + z-index: 55; + opacity: 0.9; } + .app-custom-dygraphs .loader { + color: #0dc5c1; + font-size: 20px; + margin: 100px auto; + width: 1em; + height: 1em; + border-radius: 50%; + position: relative; + text-indent: -9999em; + -webkit-animation: load4 1.3s infinite linear; + animation: load4 1.3s infinite linear; + -webkit-transform: translateZ(0); + transform: translateZ(0); } + +@-webkit-keyframes load4 { + 0%, + 100% { + box-shadow: 0 -3em 0 0.2em, 2em -2em 0 0em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 0; } + 12.5% { + box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, 3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em; } + 25% { + box-shadow: 0 -3em 0 -0.5em, 2em -2em 0 0, 3em 0 0 0.2em, 2em 2em 0 0, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em; } + 37.5% { + box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em, -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em; } + 50% { + box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em, -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em; } + 62.5% { + box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0, -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em; } + 75% { + box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0; } + 87.5% { + box-shadow: 0em -3em 0 0, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em; } } + +@keyframes load4 { + 0%, + 100% { + box-shadow: 0 -3em 0 0.2em, 2em -2em 0 0em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 0; } + 12.5% { + box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, 3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em; } + 25% { + box-shadow: 0 -3em 0 -0.5em, 2em -2em 0 0, 3em 0 0 0.2em, 2em 2em 0 0, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em; } + 37.5% { + box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em, -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em; } + 50% { + box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em, -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em; } + 62.5% { + box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0, -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em; } + 75% { + box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0; } + 87.5% { + box-shadow: 0em -3em 0 0, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em; } } diff --git a/src-gui/ui/src/app/common/components/custom-ng-dygraphs/custom-dygraphs.component.html b/src-gui/ui/src/app/common/components/custom-ng-dygraphs/custom-dygraphs.component.html new file mode 100644 index 00000000000..c4c01e5b129 --- /dev/null +++ b/src-gui/ui/src/app/common/components/custom-ng-dygraphs/custom-dygraphs.component.html @@ -0,0 +1,19 @@ +
+
+
+
+
+
+ +
+
+
+
+
+ {{noDataLabel}} +
+
+
diff --git a/src-gui/ui/src/app/common/components/custom-ng-dygraphs/custom-dygraphs.component.ts b/src-gui/ui/src/app/common/components/custom-ng-dygraphs/custom-dygraphs.component.ts new file mode 100644 index 00000000000..b7ce9d64e02 --- /dev/null +++ b/src-gui/ui/src/app/common/components/custom-ng-dygraphs/custom-dygraphs.component.ts @@ -0,0 +1,100 @@ +import {Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core'; +import {DygraphOptions} from './dygraphOptions'; + +declare const Dygraph: any; + +@Component({ + selector: 'app-custom-dygraphs', + templateUrl: './custom-dygraphs.component.html', + styleUrls: ['./custom-dygraphs.component.css'] +}) +/** + * Wrapper arround Dygraphs + * + * @class CustomDygraphsComponent + */ +export class CustomDygraphsComponent implements OnInit, OnChanges { + @Input() public options: DygraphOptions; + @Input() public data: any; + @Input() public customVisibility: boolean; + @Input() public noDataLabel: string; + @ViewChild('chart') public chart: ElementRef; + + public loadingInProgress: boolean; + public chartWidth: number; + public chartHeight: number; + public labels: string[]; + + private _g: any; + + constructor() { + } + + public ngOnInit() { + this.noDataLabel = this.noDataLabel || 'NO DATA AVAILABLE'; + this.chartWidth = (this.options && this.options.width) || 640; + this.chartHeight = (this.options && this.options.height) || 480; + } + + /** + * ngOnChanges + * @method ngOnChanges + * @return {void} + */ + public ngOnChanges(changes: SimpleChanges) { + + if (!changes) { + return; + } + + if (!this.data || !this.data.length) { + this.loadingInProgress = false; + return; + } + + this.loadingInProgress = true; + + const options = Object.assign({}, this.options); + + if (!options.width) { + options.width = this.chartWidth; + } + if (!options.height) { + options.height = this.chartHeight; + } + if (!options.legend) { + options.legend = 'always'; + } + + const initialVisibility: boolean[] = []; + if (options.labels) { + if (this.customVisibility && options.labels.length > 1) { + // options.labels[0] is always X axis + this.labels = options.labels.slice(1); + } + + options.labels.forEach((_) => { + initialVisibility.push(true); + }); + } + if (options.labels) { + options.visibility = initialVisibility; + } + + setTimeout(() => { + if (this._g) { + this._g.destroy(); + } + this._g = new Dygraph(this.chart.nativeElement, + this.data, + options + ); + this.loadingInProgress = false; + }, 500); + } + + public changeVisibility(el: any) { + const elem = el.currentTarget; + this._g.setVisibility(parseInt(elem.id, 10), elem.checked); + } +} diff --git a/src-gui/ui/src/app/common/components/custom-ng-dygraphs/dygraphOptions.ts b/src-gui/ui/src/app/common/components/custom-ng-dygraphs/dygraphOptions.ts new file mode 100644 index 00000000000..3135da65657 --- /dev/null +++ b/src-gui/ui/src/app/common/components/custom-ng-dygraphs/dygraphOptions.ts @@ -0,0 +1,92 @@ +export interface DygraphOptions { + /** + * Set this option to animate the transition between zoom windows. Applies to programmatic + * and interactive zooms. Note that if you also set a drawCallback, it will be called several + * times on each zoom. If you set a zoomCallback, it will only be called after the animation + * is complete. + */ + animatedZooms?: boolean; + + /** + * Defines per-axis options. Valid keys are 'x', 'y' and 'y2'. Only some options may be set + * on a per-axis basis. If an option may be set in this way, it will be noted on this page. + * See also documentation on per-series and + * per-axis options. + */ + axes?: any; + + /** + * Should the area underneath the graph be filled? This option is not compatible with error bars. + */ + fillGraph?: boolean; + + /** + * Height, in pixels, of the chart. If the container div has been explicitly sized, this will + * be ignored. + */ + height?: number; + + /** + * A name for each data series, including the independent (X) series. For CSV files and + * DataTable objections, this is determined by context. For raw data, this must be specified. + * If it is not, default values are supplied and a warning is logged. + */ + labels?: string[]; + + /** + * When to display the legend. By default ("onmouseover"), it only appears when a user mouses over the chart. + * Set it to "always" to always display a legend of some sort. + * When set to "follow", legend follows highlighted points. + */ + legend?: string; + + /** + * A function (or array of functions) which plot each data series on the chart. + */ + plotter?: Function | Function[]; + + /** + * The size of the dot to draw on each point in pixels (see drawPoints). A dot is always + * drawn when a point is "isolated", i.e. there is a missing point on either side of it. This + * also controls the size of those dots. + */ + pointSize?: number; + + /** + * Text to display above the chart. You can supply any HTML for this value, not just text. If + * you wish to style it using CSS, use the 'dygraph-label' or 'dygraph-title' classes. + */ + title?: string; + + /** + * Which series should initially be visible? Once the Dygraph has been constructed, you can + * access and modify the visibility of each series using the visibility and + * setVisibility methods. + */ + visibility?: boolean[]; + + /** + * Width, in pixels, of the chart. If the container div has been explicitly sized, this will + * be ignored. + */ + width?: number; + + /** + * Text to display below the chart's x-axis. You can supply any HTML for this value, not just + * text. If you wish to style it using CSS, use the 'dygraph-label' or 'dygraph-xlabel' + * classes. + */ + xlabel?: string; + + /** + * Text to display to the left of the chart's y-axis. You can supply any HTML for this value, + * not just text. If you wish to style it using CSS, use the 'dygraph-label' or + * 'dygraph-ylabel' classes. The text will be rotated 90 degrees by default, so CSS rules may + * behave in unintuitive ways. No additional space is set aside for a y-axis label. If you + * need more space, increase the width of the y-axis tick labels using the yAxisLabelWidth + * option. If you need a wider div for the y-axis label, either style it that way with CSS + * (but remember that it's rotated, so width is controlled by the 'height' property) or set + * the yLabelWidth option. + */ + ylabel?: string; +} diff --git a/src-gui/ui/src/app/common/components/flow-ping-modal/flow-ping-modal.component.html b/src-gui/ui/src/app/common/components/flow-ping-modal/flow-ping-modal.component.html index a5212a3745a..dc8c421d8b1 100644 --- a/src-gui/ui/src/app/common/components/flow-ping-modal/flow-ping-modal.component.html +++ b/src-gui/ui/src/app/common/components/flow-ping-modal/flow-ping-modal.component.html @@ -1,40 +1,50 @@ \ No newline at end of file + + diff --git a/src-gui/ui/src/app/common/dygraph/dygraph.component.css b/src-gui/ui/src/app/common/dygraph/dygraph.component.css index 7c2201795c0..1b33f02d4ec 100644 --- a/src-gui/ui/src/app/common/dygraph/dygraph.component.css +++ b/src-gui/ui/src/app/common/dygraph/dygraph.component.css @@ -3,11 +3,11 @@ canvas{ height: 400px !important; } -.ng-dygraphs .loader-holder { +.app-custom-dygraphs .loader-holder { display: none !important; } - .ng-dygraphs .loader { + .app-custom-dygraphs .loader { display: none !important; } @@ -16,4 +16,4 @@ canvas{ width: 350px !important; font-family: arial; top: -20px !important; - } \ No newline at end of file + } diff --git a/src-gui/ui/src/app/common/dygraph/dygraph.component.html b/src-gui/ui/src/app/common/dygraph/dygraph.component.html index 0a475770277..c45269028f5 100644 --- a/src-gui/ui/src/app/common/dygraph/dygraph.component.html +++ b/src-gui/ui/src/app/common/dygraph/dygraph.component.html @@ -1 +1 @@ - + diff --git a/src-gui/ui/src/app/common/services/dygraph.service.ts b/src-gui/ui/src/app/common/services/dygraph.service.ts index 5ae8e205d00..d5203d31fc6 100644 --- a/src-gui/ui/src/app/common/services/dygraph.service.ts +++ b/src-gui/ui/src/app/common/services/dygraph.service.ts @@ -81,14 +81,6 @@ export class DygraphService { ]; } - getMetricDirections() { - return [ - { label: 'Both', value: 'both' }, - { label: 'Forward', value: 'forward' }, - { label: 'Reverse', value: 'reverse' } - ]; - } - constructVictoriaGraphData(victoriaDataArr: VictoriaData[], startDate: string, endDate: string, timezone: string) { this.numOperator = 0; let fwdMetricDirectionLbl: string; diff --git a/src-gui/ui/src/app/common/services/flowpath.service.ts b/src-gui/ui/src/app/common/services/flowpath.service.ts index 93fe3c7d138..09f6f5897e2 100644 --- a/src-gui/ui/src/app/common/services/flowpath.service.ts +++ b/src-gui/ui/src/app/common/services/flowpath.service.ts @@ -88,46 +88,51 @@ export class FlowpathService { ); } - dragStartForward = () => { + dragStartForward = (event) => { const simulation = this.simulationArr['forwardDiverse']; - if (!d3.event.active) { simulation.alphaTarget(1).stop(); } + if (!event.active) { simulation.alphaTarget(1).stop(); } } - draggingForward = (d: any, i) => { + draggingForward = (event, d) => { this.isDragMoveForward = true; - d.py += d3.event.dy; - d.x += d3.event.dx; - d.y += d3.event.dy; - this.tick( this.graphLinkArr['forwardDiverse'], this.graphNodeArr['forwardDiverse'], this.graphPortArrSource['forwardDiverse'], this.graphPortArrTarget['forwardDiverse'], this.linksSource['forwardDiverse'], this.linkNum['forwardDiverse']); + d.py += event.dy; + d.x += event.dx; + d.y += event.dy; + this.tick( this.graphLinkArr['forwardDiverse'], this.graphNodeArr['forwardDiverse'], + this.graphPortArrSource['forwardDiverse'], this.graphPortArrTarget['forwardDiverse'], + this.linksSource['forwardDiverse'], this.linkNum['forwardDiverse']); } - dragEndForward = (d: any, i) => { + dragEndForward = (event, d) => { const simulation = this.simulationArr['forwardDiverse']; - if (!d3.event.active) { simulation.alphaTarget(0); } + if (!event.active) { simulation.alphaTarget(0); } d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff - this.tick( this.graphLinkArr['forwardDiverse'], this.graphNodeArr['forwardDiverse'], this.graphPortArrSource['forwardDiverse'], this.graphPortArrTarget['forwardDiverse'], this.linksSource['forwardDiverse'], this.linkNum['forwardDiverse']); + this.tick( this.graphLinkArr['forwardDiverse'], this.graphNodeArr['forwardDiverse'], this.graphPortArrSource['forwardDiverse'], + this.graphPortArrTarget['forwardDiverse'], this.linksSource['forwardDiverse'], this.linkNum['forwardDiverse']); } // for reverse - dragStartReverse = () => { + dragStartReverse = (event, d) => { const simulation = this.simulationArr['reverseDiverse']; - if (!d3.event.active) { simulation.alphaTarget(1).stop(); } + if (!event.active) { simulation.alphaTarget(1).stop(); } jQuery('#topology-hover-txt').hide(); jQuery('#topology-click-txt').hide(); } - draggingReverse = (d: any, i) => { + draggingReverse = (event, d) => { this.isDragMoveReverse = true; - d.py += d3.event.dy; - d.x += d3.event.dx; - d.y += d3.event.dy; - this.tick( this.graphLinkArr['reverseDiverse'], this.graphNodeArr['reverseDiverse'], this.graphPortArrSource['reverseDiverse'], this.graphPortArrTarget['reverseDiverse'], this.linksSource['reverseDiverse'], this.linkNum['reverseDiverse']); + d.py += event.dy; + d.x += event.dx; + d.y += event.dy; + this.tick( this.graphLinkArr['reverseDiverse'], this.graphNodeArr['reverseDiverse'], this.graphPortArrSource['reverseDiverse'], + this.graphPortArrTarget['reverseDiverse'], this.linksSource['reverseDiverse'], this.linkNum['reverseDiverse']); } - dragEndReverse = (d: any, i) => { + dragEndReverse = (event, d) => { const simulation = this.simulationArr['reverseDiverse']; - if (!d3.event.active) { simulation.alphaTarget(0); } + if (!event.active) { simulation.alphaTarget(0); } d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff - this.tick( this.graphLinkArr['reverseDiverse'], this.graphNodeArr['reverseDiverse'], this.graphPortArrSource['reverseDiverse'], this.graphPortArrTarget['reverseDiverse'], this.linksSource['reverseDiverse'], this.linkNum['reverseDiverse']); + this.tick( this.graphLinkArr['reverseDiverse'], this.graphNodeArr['reverseDiverse'], this.graphPortArrSource['reverseDiverse'], + this.graphPortArrTarget['reverseDiverse'], this.linksSource['reverseDiverse'], this.linkNum['reverseDiverse']); } initSimulation(nodes, links, svgElement, graphWrapper, type, positions, hoverTextID, showValueID, hideValueID) { this.svgElementArr[type] = svgElement; @@ -180,17 +185,17 @@ export class FlowpathService { .zoom() .scaleExtent([this.min_zoom, this.max_zoom]) .extent([[0, 0], [width - 200, height - 50]]) - .on('zoom', () => { - zoomLevel = Math.round(d3.event.transform.k * 100) / 100; + .on('zoom', (event, d) => { + zoomLevel = Math.round(event.transform.k * 100) / 100; self.zoomLevelArr[type] = zoomLevel; g.attr( 'transform', 'translate(' + - d3.event.transform.x + + event.transform.x + ',' + - d3.event.transform.y + + event.transform.y + ') scale(' + - d3.event.transform.k + + event.transform.k + ')' ); @@ -344,7 +349,8 @@ export class FlowpathService { }).attr('stroke-width', (d) => 4.5).attr('stroke', function(d, index) { return d.colourCode; }).attr('cursor', 'pointer') - .on('mouseover', function(d, index) { + .on('mouseover', function(event, d) { + const index = d.index; if (type == 'forwardDiverse' || type == 'reverseDiverse' ) { const element = document.getElementById(type + '_link' + index); let classes = element.getAttribute('class'); @@ -375,10 +381,10 @@ export class FlowpathService { }); } - }).on('mouseout', function(d, index) { - $('#' + type + '_link' + index).removeClass('overlay'); + }).on('mouseout', function(event, d) { + $('#' + type + '_link' + d.index).removeClass('overlay'); $('#' + hoverTextID).css('display', 'none'); - }).on('click', function(d) { + }).on('click', function(event, d) { if (d.type == 'isl') { const src_switch = d.source_detail.id, src_port = d.source_detail.out_port, @@ -413,7 +419,7 @@ export class FlowpathService { .attr('stroke', '#00baff') .attr('stroke-width', '1px') .attr('fill', '#FFF').attr('style', 'cursor:pointer') - .on('mouseover', function(d, index) { + .on('mouseover', function(event, d) { if (type == 'forwardDiverse' || type == 'reverseDiverse' ) { const element = document.getElementById('textCircle_target_' + type + '_' + d.target.switch_id); const rec: any = element.getBoundingClientRect(); @@ -428,7 +434,7 @@ export class FlowpathService { } - }).on('mouseout', function(d, index) { + }).on('mouseout', function(event, d) { $('#' + hoverTextID).css('display', 'none'); }); @@ -476,7 +482,7 @@ export class FlowpathService { .attr('stroke', '#00baff') .attr('stroke-width', '1px') .attr('fill', '#FFF').attr('style', 'cursor:pointer') - .on('mouseover', function(d, index) { + .on('mouseover', function(event, d) { if (type == 'forwardDiverse' || type == 'reverseDiverse' ) { const element = document.getElementById('textCircle_source_' + type + '_' + d.source.switch_id); const rec: any = element.getBoundingClientRect(); @@ -492,7 +498,7 @@ export class FlowpathService { } - }).on('mouseout', function(d, index) { + }).on('mouseout', function(event, d) { $('#' + hoverTextID).css('display', 'none'); }); @@ -559,7 +565,7 @@ export class FlowpathService { .attr('id', function(d, index) { return type + '_circle_' + d.switch_id; }).style('cursor', 'pointer') - .on('click', function(d) { + .on('click', function(event, d) { ref.loadSwitchDetail(d.switch_id); }); const images = graphNodeElement @@ -582,7 +588,7 @@ export class FlowpathService { return 'image_' + index; }) .attr('cursor', 'pointer') - .on('mouseover', function(d, index) { + .on('mouseover', function(event, d) { if (type == 'forwardDiverse' || type == 'reverseDiverse' ) { const element = document.getElementById(type + '_circle_' + d.switch_id); const rec: any = element.getBoundingClientRect(); @@ -597,7 +603,7 @@ export class FlowpathService { } - }).on('mouseout', function(d, index) { + }).on('mouseout', function(event, d) { $('#' + hoverTextID).css('display', 'none'); }); diff --git a/src-gui/ui/src/app/common/services/permission.service.ts b/src-gui/ui/src/app/common/services/permission.service.ts index ed5560248cc..e4564d8a723 100644 --- a/src-gui/ui/src/app/common/services/permission.service.ts +++ b/src-gui/ui/src/app/common/services/permission.service.ts @@ -48,17 +48,7 @@ import { BehaviorSubject } from 'rxjs'; const url = `${this.configUrl}/role/permission/${id}`; return this.http.put(url, role); } - - getPermissionRoleById(id: number): Observable { - const url = `${this.configUrl}/role/permission/${id}`; - return this.http.get(url); - } - selectedPermission(userId: number) { this.permissionSource.next(userId); } - - clearselectedPermission() { - this.subject.next(); - } } diff --git a/src-gui/ui/src/app/common/services/role.service.ts b/src-gui/ui/src/app/common/services/role.service.ts index 52742ac4485..af92f4d4d47 100644 --- a/src-gui/ui/src/app/common/services/role.service.ts +++ b/src-gui/ui/src/app/common/services/role.service.ts @@ -12,7 +12,7 @@ import { BehaviorSubject } from 'rxjs'; export class RoleService { configUrl: string; - public subject = new Subject(); + public subject = new Subject(); private roleSource = new BehaviorSubject(null); currentRole = this.roleSource.asObservable(); @@ -58,9 +58,4 @@ import { BehaviorSubject } from 'rxjs'; selectedRole(userId: number) { this.roleSource.next(userId); } - - clearSelectedRole() { - this.subject.next(); - } - - } +} diff --git a/src-gui/ui/src/app/common/services/stats.service.ts b/src-gui/ui/src/app/common/services/stats.service.ts index d02e62f0c95..e2081ee3296 100644 --- a/src-gui/ui/src/app/common/services/stats.service.ts +++ b/src-gui/ui/src/app/common/services/stats.service.ts @@ -4,7 +4,6 @@ import {CookieManagerService} from './cookie-manager.service'; import {Observable} from 'rxjs'; import {VictoriaStatsReq, VictoriaStatsRes} from '../data-models/flowMetricVictoria'; import {environment} from '../../../environments/environment'; -import {FlowMetricTsdb} from '../data-models/flowMetricTsdb'; import * as moment from 'moment'; import {PortInfo} from '../data-models/port-info'; import {concatMap, map} from 'rxjs/operators'; @@ -26,7 +25,7 @@ export class StatsService { downsampling: string, metrics: string[], direction?: string): Observable { - const url = `${environment.apiEndPoint}/stats/victoria/${statsType}`; + const url = `${environment.apiEndPoint}/stats/flowgraph/${statsType}`; // Construct form data const formData = new FormData(); @@ -45,27 +44,11 @@ export class StatsService { return this.httpClient.post(url, formData); } - getFlowGraphData(flowid, convertedStartDate, convertedEndDate, downsampling, metric): Observable { - return this.httpClient.get( - `${environment.apiEndPoint}/stats/flowid/${flowid}/${convertedStartDate}/${convertedEndDate}/${downsampling}/${metric}`); - } - - getMeterGraphData(flowid, convertedStartDate, convertedEndDate, downsampling, metric, direction): Observable { - return this.httpClient.get(`${environment.apiEndPoint}/stats/meter/ - ${flowid}/${convertedStartDate}/${convertedEndDate}/${downsampling}/${metric}/${direction}`); - } - - getFlowPacketGraphData(flowid, convertedStartDate, convertedEndDate, downsampling, direction): Observable { - return this.httpClient.get(`${environment.apiEndPoint}/stats/flow/losspackets/ - ${flowid}/${convertedStartDate}/${convertedEndDate}/${downsampling}/${direction}`); - } - - getFlowPathStats(jsonPayload: VictoriaStatsReq): Observable { return this.httpClient.post(`${environment.apiEndPoint}/stats/common`, jsonPayload); } - getSwitchPortsStats(switchId): Observable { + getSwitchPortsStats(switchId: string): Observable { const startDate = moment().utc().subtract(30, 'minutes').format('YYYY-MM-DD-HH:mm:ss'); const endDate = moment().utc().format('YYYY-MM-DD-HH:mm:ss'); @@ -83,14 +66,12 @@ export class StatsService { `${environment.apiEndPoint}/stats/switchports`, requestPayload); } - getPortGraphData(src_switch, - src_port, - dst_switch, - dst_port, - frequency, - metric, - from, - to): Observable { + getPortGraphData(src_switch: string, + src_port: string, + frequency: string, + metric: string, + from: string, + to: string): Observable { const requestPayload: VictoriaStatsReq = { metrics: [metric], statsType: 'port', @@ -106,15 +87,15 @@ export class StatsService { } getForwardGraphData( - src_switch, - src_port, - dst_switch, - dst_port, - frequency, - graph, - metric, - from, - to + src_switch: string, + src_port: string, + dst_switch: string, + dst_port: string, + frequency: string, + graph: string, + metric: string, + from: string, + to: string ): Observable { if (graph === 'latency') { const requestPayload: VictoriaStatsReq = { @@ -181,14 +162,14 @@ export class StatsService { } getBackwardGraphData( - src_switch, - src_port, - dst_switch, - dst_port, - frequency, - graph, - from, - to + src_switch: string, + src_port: string, + dst_switch: string, + dst_port: string, + frequency: string, + graph: string, + from: string, + to: string ): Observable { if (graph === 'rtt') { const requestPayload: VictoriaStatsReq = { @@ -224,15 +205,15 @@ export class StatsService { } } - getIslLossGraphData(src_switch, - src_port, - dst_switch, - dst_port, - step, - graph, - metric, - from, - to): Observable { + getIslLossGraphData(src_switch: string, + src_port: string, + dst_switch: string, + dst_port: string, + step: string, + graph: string, + metric: any, + from: string, + to: string): Observable { const metricList: string[] = []; switch (metric) { case 'bits': diff --git a/src-gui/ui/src/app/common/services/tab.service.ts b/src-gui/ui/src/app/common/services/tab.service.ts index 3e550a191ab..345b585d811 100644 --- a/src-gui/ui/src/app/common/services/tab.service.ts +++ b/src-gui/ui/src/app/common/services/tab.service.ts @@ -14,6 +14,6 @@ export class TabService { } clearSelectedTab() { - this.subject.next(); + this.subject.next(true); } } diff --git a/src-gui/ui/src/app/common/services/topology-graph.service.ts b/src-gui/ui/src/app/common/services/topology-graph.service.ts index dceefbd4d83..781158be4c6 100644 --- a/src-gui/ui/src/app/common/services/topology-graph.service.ts +++ b/src-gui/ui/src/app/common/services/topology-graph.service.ts @@ -64,15 +64,15 @@ export class TopologyGraphService { .zoom() .scaleExtent([this.scaleLimit, this.max_zoom]) .extent([[0, 0], [width, height]]) - .on('zoom', () => { + .on('zoom', (event, d) => { this.g.attr( 'transform', 'translate(' + - d3.event.transform.x + + event.transform.x + ',' + - d3.event.transform.y + + event.transform.y + ') scale(' + - d3.event.transform.k + + event.transform.k + ')' ); }); @@ -314,7 +314,7 @@ export class TopologyGraphService { }) .attr('cursor', 'pointer'); if (!forMap) { - graphNodeElement.on('mouseover', function(d, index) { + graphNodeElement.on('mouseover', function(event, d) { $('#isl_hover').css('display', 'none'); const element = document.getElementById('circle_' + d.switch_id); @@ -360,7 +360,7 @@ export class TopologyGraphService { } }) - .on('mouseout', function(d, index) { + .on('mouseout', function(event, d) { if (this.flagHover == false) { this.flagHover = true; } else { @@ -378,7 +378,7 @@ export class TopologyGraphService { } }) - .on('click', function(d, index) { + .on('click', function(event, d) { $('#topology-hover-txt').css('display', 'none'); const cName = document.getElementById('circle_' + d.switch_id).className; @@ -485,8 +485,8 @@ export class TopologyGraphService { }) .attr('id', (d, index) => { return 'link' + index; - }).on('click', function(d, index) { - const element = $('#link' + index)[0]; + }).on('click', function(event, d) { + const element = $('#link' + d.index)[0]; const availbandwidth = d.available_bandwidth; const max_bandwidth = d.max_bandwidth; const percentage = ref.commonService.getPercentage(availbandwidth, max_bandwidth); @@ -571,7 +571,8 @@ export class TopologyGraphService { } }); if (!forMap) { - graphLinksData.on('mouseover', function(d, index) { + graphLinksData.on('mouseover', function(event, d) { + const index = d.index; $('#switch_hover').css('display', 'none'); const element = $('#link' + index)[0]; const availbandwidth = d.available_bandwidth; @@ -739,9 +740,9 @@ export class TopologyGraphService { ); } }) - .on('mouseout', function(d, index) { + .on('mouseout', function(event, d) { $('#topology-hover-txt, #isl_hover').css('display', 'none'); - const element = $('#link' + index)[0]; + const element = $('#link' + d.index)[0]; const availbandwidth = d.available_bandwidth; const max_bandwidth = d.max_bandwidth; const percentage = ref.commonService.getPercentage(availbandwidth, max_bandwidth); @@ -1064,19 +1065,19 @@ export class TopologyGraphService { }); } - dragStart = () => { - if (!d3.event.active) { this.simulation.alphaTarget(1).stop(); } + dragStart = (event, d) => { + if (!event.active) { this.simulation.alphaTarget(1).stop(); } } - dragging = (d: any, i) => { + dragging = (event, d) => { // this.isDragMove = true; - d.py += d3.event.dy; - d.x += d3.event.dx; - d.y += d3.event.dy; + d.py += event.dy; + d.x += event.dx; + d.y += event.dy; this.ticked(); } - dragEnd = (d: any, i) => { - if (!d3.event.active) { this.simulation.alphaTarget(0); } + dragEnd = (event, d) => { + if (!event.active) { this.simulation.alphaTarget(0); } } } diff --git a/src-gui/ui/src/app/common/services/user.service.ts b/src-gui/ui/src/app/common/services/user.service.ts index 4d1be4a8489..78b180c1d98 100644 --- a/src-gui/ui/src/app/common/services/user.service.ts +++ b/src-gui/ui/src/app/common/services/user.service.ts @@ -19,7 +19,7 @@ const httpOptions = { export class UserService { configUrl: string; - public subject = new Subject(); + public subject = new Subject(); private userSource = new BehaviorSubject(null); currentUser = this.userSource.asObservable(); diff --git a/src-gui/ui/src/app/modules/flows/connected-devices/connected-devices.component.spec.ts b/src-gui/ui/src/app/modules/flows/connected-devices/connected-devices.component.spec.ts index 5a529380703..7aeff214032 100644 --- a/src-gui/ui/src/app/modules/flows/connected-devices/connected-devices.component.spec.ts +++ b/src-gui/ui/src/app/modules/flows/connected-devices/connected-devices.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import { ConnectedDevicesComponent } from './connected-devices.component'; @@ -6,7 +6,7 @@ describe('ConnectedDevicesComponent', () => { let component: ConnectedDevicesComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ declarations: [ ConnectedDevicesComponent ] }) diff --git a/src-gui/ui/src/app/modules/flows/connected-devices/connected-devices.component.ts b/src-gui/ui/src/app/modules/flows/connected-devices/connected-devices.component.ts index 8faf7d8a845..ca071dfc992 100644 --- a/src-gui/ui/src/app/modules/flows/connected-devices/connected-devices.component.ts +++ b/src-gui/ui/src/app/modules/flows/connected-devices/connected-devices.component.ts @@ -4,7 +4,6 @@ import { LoaderService } from 'src/app/common/services/loader.service'; import * as d3 from 'd3'; import { ISL } from '../../../common/enums/isl.enum'; import { environment } from '../../../../environments/environment'; -import { AngularFontAwesomeComponent } from 'angular-font-awesome'; @Component({ selector: 'app-connected-devices', @@ -130,20 +129,20 @@ export class ConnectedDevicesComponent implements OnInit, OnChanges, AfterViewIn } } - dragStart = () => { - if (!d3.event.active) { this.forceSimulation.alphaTarget(1).stop(); } + dragStart = (event, d) => { + if (!event.active) { this.forceSimulation.alphaTarget(1).stop(); } } - dragging = (d: any, i) => { + dragging = (event, d) => { this.isDragMove = true; - d.py += d3.event.dy; - d.x += d3.event.dx; - d.y += d3.event.dy; + d.py += event.dy; + d.x += event.dx; + d.y += event.dy; this.tick(); } - dragEnd = (d: any, i) => { - if (!d3.event.active) { this.forceSimulation.alphaTarget(0); } + dragEnd = (event, d) => { + if (!event.active) { this.forceSimulation.alphaTarget(0); } if (!d.connected) { d.fixed = true; } @@ -250,15 +249,15 @@ export class ConnectedDevicesComponent implements OnInit, OnChanges, AfterViewIn .zoom() .scaleExtent([this.min_zoom, this.max_zoom]) .extent([[0, 0], [this.width, this.height]]) - .on('zoom', () => { + .on('zoom', (event, d) => { this.g.attr( 'transform', 'translate(' + - d3.event.transform.x + + event.transform.x + ',' + - d3.event.transform.y + + event.transform.y + ') scale(' + - d3.event.transform.k + + event.transform.k + ')' ); }); @@ -414,8 +413,8 @@ export class ConnectedDevicesComponent implements OnInit, OnChanges, AfterViewIn }) .attr('id', function(d, index) { return 'image_' + index; - }).attr('cursor', 'pointer').on('mouseover', function(d, index) { - const element = document.getElementById('circle_' + index); + }).attr('cursor', 'pointer').on('mouseover', function(event, d) { + const element = document.getElementById('circle_' + d.index); const rec: any = element.getBoundingClientRect(); if (d.connected) { $('#tooltip_connected_device').css('display', 'block'); @@ -444,7 +443,7 @@ export class ConnectedDevicesComponent implements OnInit, OnChanges, AfterViewIn } } - }).on('mouseout', function(d, index) { + }).on('mouseout', function(event, d) { $('#tooltip_connected_device').css('display', 'none'); }); diff --git a/src-gui/ui/src/app/modules/flows/flow-add/flow-add.component.ts b/src-gui/ui/src/app/modules/flows/flow-add/flow-add.component.ts index 9dc4832ee64..a7387338805 100644 --- a/src-gui/ui/src/app/modules/flows/flow-add/flow-add.component.ts +++ b/src-gui/ui/src/app/modules/flows/flow-add/flow-add.component.ts @@ -13,7 +13,6 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { ModalconfirmationComponent } from '../../../common/components/modalconfirmation/modalconfirmation.component'; import { CommonService } from 'src/app/common/services/common.service'; import { MessageObj } from 'src/app/common/constants/constants'; -import { Message } from '@angular/compiler/src/i18n/i18n_ast'; import {StatsService} from '../../../common/services/stats.service'; declare var jQuery: any; diff --git a/src-gui/ui/src/app/modules/flows/flow-contracts/flow-contracts.component.ts b/src-gui/ui/src/app/modules/flows/flow-contracts/flow-contracts.component.ts index f33eadd762a..22261db8791 100644 --- a/src-gui/ui/src/app/modules/flows/flow-contracts/flow-contracts.component.ts +++ b/src-gui/ui/src/app/modules/flows/flow-contracts/flow-contracts.component.ts @@ -16,7 +16,7 @@ import { MessageObj } from 'src/app/common/constants/constants'; export class FlowContractsComponent implements OnInit, OnChanges, AfterViewInit { @ViewChild(DataTableDirective, { static: true }) datatableElement: DataTableDirective; dtOptions = {}; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); @Input() data = []; @Input() flowId; diff --git a/src-gui/ui/src/app/modules/flows/flow-datatables/flow-datatables.component.ts b/src-gui/ui/src/app/modules/flows/flow-datatables/flow-datatables.component.ts index 5a6f0e7c629..24262433d5c 100644 --- a/src-gui/ui/src/app/modules/flows/flow-datatables/flow-datatables.component.ts +++ b/src-gui/ui/src/app/modules/flows/flow-datatables/flow-datatables.component.ts @@ -5,7 +5,7 @@ import { Subject } from 'rxjs'; import { Flow } from 'src/app/common/data-models/flow'; import { Router } from '@angular/router'; import { CommonService } from 'src/app/common/services/common.service'; -import { FormBuilder, FormGroup } from '@angular/forms'; +import { FormBuilder } from '@angular/forms'; import { ClipboardService } from 'ngx-clipboard'; import { FlowReRouteModalComponent } from 'src/app/common/components/flow-re-route-modal/flow-re-route-modal.component'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; @@ -35,7 +35,7 @@ export class FlowDatatablesComponent implements OnInit, AfterViewInit, OnChanges reRouteList: any = []; checkedFlow = []; selectAll = false; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); wrapperHide = true; expandedSrcSwitchName = false; diff --git a/src-gui/ui/src/app/modules/flows/flow-detail/flow-detail.component.ts b/src-gui/ui/src/app/modules/flows/flow-detail/flow-detail.component.ts index 9947459fab5..a32907e60fb 100644 --- a/src-gui/ui/src/app/modules/flows/flow-detail/flow-detail.component.ts +++ b/src-gui/ui/src/app/modules/flows/flow-detail/flow-detail.component.ts @@ -173,24 +173,7 @@ export class FlowDetailComponent implements OnInit { this.getFlowHistory(); } } - - dragStart = () => { - if (!d3.event.active) { this.forceSimulation.alphaTarget(1).stop(); } - } - - dragging = (d: any, i) => { - this.isDragMove = true; - d.py += d3.event.dy; - d.x += d3.event.dx; - d.y += d3.event.dy; - this.tick(); - } - - dragEnd = (d: any, i) => { - if (!d3.event.active) { this.forceSimulation.alphaTarget(0); } - } - - horizontallyBound = (parentDiv, childDiv) => { + horizontallyBound = (parentDiv, childDiv) => { const parentRect: any = parentDiv.getBoundingClientRect(); const childRect: any = childDiv.getBoundingClientRect(); return ( @@ -285,7 +268,8 @@ export class FlowDetailComponent implements OnInit { }).attr('stroke-width', (d) => 2.5).attr('stroke', function(d, index) { return ISL.DISCOVERED; }).attr('cursor', 'pointer') - .on('mouseover', function(d, index) { + .on('mouseover', function(event, d) { + const index = d.index; const element = document.getElementById('link' + index); let classes = element.getAttribute('class'); classes = classes + ' overlay'; @@ -321,7 +305,8 @@ export class FlowDetailComponent implements OnInit { }); } - }).on('mouseout', function(d, index) { + }).on('mouseout', function(event, d) { + const index = d.index; const element = document.getElementById('link' + index); $('#link' + index).removeClass('overlay'); $('#ping-hover-txt').css('display', 'none'); @@ -380,8 +365,8 @@ export class FlowDetailComponent implements OnInit { .attr('width', 58) .attr('id', function(d, index) { return 'image_' + index; - }).attr('cursor', 'pointer').on('mouseover', function(d, index) { - const element = document.getElementById('circle_' + index); + }).attr('cursor', 'pointer').on('mouseover', function(event, d) { + const element = document.getElementById('circle_' + d.index); const rec: any = element.getBoundingClientRect(); $('#ping-hover-txt,#switch_hover').css('display', 'block'); $('#ping-hover-txt').css('top', rec.y + 'px'); @@ -411,7 +396,7 @@ export class FlowDetailComponent implements OnInit { $('#ping-hover-txt').css('left', left + 'px'); $('#ping-hover-txt').addClass('left'); } - }).on('mouseout', function(d, index) { + }).on('mouseout', function(event, d) { $('#ping-hover-txt,#switch_hover').css('display', 'none'); }); @@ -764,9 +749,9 @@ export class FlowDetailComponent implements OnInit { } } - isSubflowForYFlow(flowDetail): boolean { - return typeof flowDetail.y_flow_id === 'string' && flowDetail.y_flow_id !== ''; - } + isSubflowForYFlow(flowDetail: { y_flow_id: string; }): boolean { + return flowDetail.y_flow_id !== undefined && typeof flowDetail.y_flow_id === 'string' && flowDetail.y_flow_id !== ''; + } processRerouteResult( data: any) { this.loaderService.hide(); diff --git a/src-gui/ui/src/app/modules/flows/flow-graph/flow-graph.component.html b/src-gui/ui/src/app/modules/flows/flow-graph/flow-graph.component.html index 0b854f312a7..9ada43158e7 100644 --- a/src-gui/ui/src/app/modules/flows/flow-graph/flow-graph.component.html +++ b/src-gui/ui/src/app/modules/flows/flow-graph/flow-graph.component.html @@ -5,8 +5,7 @@
    -
  • Forward
  • -
  • Reverse
  • +
  • {{ direction }}
@@ -67,14 +66,6 @@
-
- -
- -
-
@@ -89,24 +80,8 @@
Auto reload time should be number
Auto reload time required
-
-
- -
-
-
- - -
-
-
-
diff --git a/src-gui/ui/src/app/modules/flows/flow-graph/flow-graph.component.ts b/src-gui/ui/src/app/modules/flows/flow-graph/flow-graph.component.ts index c11bb94453a..6416c851ae8 100644 --- a/src-gui/ui/src/app/modules/flows/flow-graph/flow-graph.component.ts +++ b/src-gui/ui/src/app/modules/flows/flow-graph/flow-graph.component.ts @@ -15,12 +15,12 @@ declare var moment: any; export class FlowGraphComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges { @Input() flowId; - + directionItems: string[] = ['Forward', 'Reverse']; autoReloadTimerId = null; flowMetrics = []; packetMetrics = []; metersDirection = []; - getautoReloadValues = this.commonService.getAutoreloadValues(); + getautoReloadValues; filterForm: FormGroup; constructor( @@ -30,7 +30,7 @@ export class FlowGraphComponent implements OnInit, AfterViewInit, OnDestroy, OnC private toaster: ToastrService, private commonService: CommonService ) { - + this.getautoReloadValues = this.commonService.getAutoreloadValues(); } ngOnChanges(change: SimpleChanges) { @@ -51,15 +51,12 @@ export class FlowGraphComponent implements OnInit, AfterViewInit, OnDestroy, OnC graph: ['flow'], metric: ['packets'], direction: ['forward'], - meterdirection: ['both'], auto_reload: [''], auto_reload_time: ['', Validators.compose([Validators.pattern('[0-9]*')])], - victoriaSource: [true] }); this.flowMetrics = this.dygraphService.getFlowMetricData(); this.packetMetrics = this.dygraphService.getPacketsMetricData(); - this.metersDirection = this.dygraphService.getMetricDirections(); } getDateRange(): any { @@ -140,15 +137,23 @@ export class FlowGraphComponent implements OnInit, AfterViewInit, OnDestroy, OnC this.loadGraphData(); } + setDirectionLabels(formdata) { + if (formdata.graph === 'flow' || formdata.graph === 'flowmeter') { + this.directionItems = ['Forward', 'Reverse']; + } else { + const label = this.packetMetrics.find(element => element.value === this.filterForm.value.direction).label; + this.directionItems = [label, label]; + } + } + loadGraphData() { const formdata = this.filterForm.value; - console.log('loadGraphData() called, isVictoriaSource:' + formdata.victoriaSource); + this.setDirectionLabels(formdata); const flowid = this.flowId; const autoReloadTime = Number( this.filterForm.controls['auto_reload_time'].value ); - const direction = (formdata.graph == 'flowmeter') ? formdata.meterdirection : formdata.direction; const downsampling = formdata.download_sample; const metric = formdata.metric; const timezone = formdata.timezone; @@ -189,7 +194,7 @@ export class FlowGraphComponent implements OnInit, AfterViewInit, OnDestroy, OnC endDate: endDate, timezone: timezone }); - const statsDbName = formdata.victoriaSource ? 'Victoria DB' : 'OpenTSDB'; + const statsDbName = 'Victoria DB'; const errorMsg = res && res.error && res.error.message ? res.error.message : `Something went wrong while accessing ${statsDbName}`; this.toaster.error(errorMsg, 'Error'); @@ -210,71 +215,39 @@ export class FlowGraphComponent implements OnInit, AfterViewInit, OnDestroy, OnC endDate: endDate, timezone: timezone }); - const statsDbName = formdata.victoriaSource ? 'Victoria DB' : 'OpenTSDB'; + const statsDbName = 'Victoria DB'; const errorMsg = error && error.message ? error.message : `Something went wrong while accessing ${statsDbName}`; this.toaster.error(errorMsg, 'Error'); }; if (formdata.graph == 'flow') { - if (formdata.victoriaSource) { - this.statsService.getFlowGraphVictoriaData( - 'flow', - flowid, - convertedStartDate, - convertedEndDate, - downsampling, - [metric]) - .subscribe(handleSuccessForFlow, handleErrorForFlow); - } else { - this.statsService.getFlowGraphData(flowid, convertedStartDate, convertedEndDate, downsampling, metric) - .subscribe(handleSuccessForFlow, handleErrorForFlow); - } + this.statsService.getFlowGraphVictoriaData( + 'flow', + flowid, + convertedStartDate, + convertedEndDate, + downsampling, + [metric]) + .subscribe(handleSuccessForFlow, handleErrorForFlow); } else if (formdata.graph == 'flowmeter') { - if (formdata.victoriaSource) { - this.statsService.getFlowGraphVictoriaData( - 'meter', - flowid, - convertedStartDate, - convertedEndDate, - downsampling, - [metric]) - .subscribe(res => { - console.log(res); - }); - } else { - this.statsService - .getMeterGraphData( - flowid, - convertedStartDate, - convertedEndDate, - downsampling, - metric, - direction - ) - .subscribe(handleSuccessMeter, handleErrorMeter); - } + this.statsService.getFlowGraphVictoriaData( + 'meter', + flowid, + convertedStartDate, + convertedEndDate, + downsampling, + [metric]) + .subscribe(handleSuccessMeter, handleErrorMeter); } else { // packet loss - if (formdata.victoriaSource) { - this.statsService.getFlowGraphVictoriaData( - 'flow', - flowid, - convertedStartDate, - convertedEndDate, - downsampling, - [metric, 'ingress_packets'], - direction) - .subscribe(handleSuccessForFlow, handleErrorForFlow); - } else { - this.statsService - .getFlowPacketGraphData( - flowid, - convertedStartDate, - convertedEndDate, - downsampling, - direction - ) - .subscribe(handleSuccessForFlow, handleErrorForFlow); - } + this.statsService.getFlowGraphVictoriaData( + 'flow', + flowid, + convertedStartDate, + convertedEndDate, + downsampling, + [metric, 'ingress_packets'], + formdata.direction) + .subscribe(handleSuccessForFlow, handleErrorForFlow); } } diff --git a/src-gui/ui/src/app/modules/flows/flow-list/flow-list.component.ts b/src-gui/ui/src/app/modules/flows/flow-list/flow-list.component.ts index efdcccf04c2..e4598b5835c 100644 --- a/src-gui/ui/src/app/modules/flows/flow-list/flow-list.component.ts +++ b/src-gui/ui/src/app/modules/flows/flow-list/flow-list.component.ts @@ -1,9 +1,6 @@ import { AfterViewInit, Component, OnInit, ViewChild, OnDestroy, HostListener, Renderer2, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { DataTableDirective } from 'angular-datatables'; import { FlowsService } from '../../../common/services/flows.service'; import { ToastrService } from 'ngx-toastr'; -import { Subject } from 'rxjs'; -import { Flow } from '../../../common/data-models/flow'; import { Router } from '@angular/router'; import { LoaderService } from '../../../common/services/loader.service'; import { MessageObj } from 'src/app/common/constants/constants'; diff --git a/src-gui/ui/src/app/modules/flows/flow-path-graph/flow-path-graph.component.html b/src-gui/ui/src/app/modules/flows/flow-path-graph/flow-path-graph.component.html index 0e71d2baee6..175c055f7b0 100644 --- a/src-gui/ui/src/app/modules/flows/flow-path-graph/flow-path-graph.component.html +++ b/src-gui/ui/src/app/modules/flows/flow-path-graph/flow-path-graph.component.html @@ -32,18 +32,17 @@
- +
- +
- +
- - +
@@ -52,4 +51,4 @@ Copy to Clipboard - \ No newline at end of file + diff --git a/src-gui/ui/src/app/modules/isl/datatable/datatable.component.ts b/src-gui/ui/src/app/modules/isl/datatable/datatable.component.ts index 473e83c8a33..9ebfa33aa4c 100644 --- a/src-gui/ui/src/app/modules/isl/datatable/datatable.component.ts +++ b/src-gui/ui/src/app/modules/isl/datatable/datatable.component.ts @@ -10,16 +10,12 @@ import { SimpleChanges, EventEmitter } from '@angular/core'; -import { IslModel } from '../../../common/data-models/isl-model'; -import { IslDetailModel } from '../../../common/data-models/isl-detail-model'; import { IslListService } from '../../../common/services/isl-list.service'; import { Router } from '@angular/router'; import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; import { Subject } from 'rxjs'; import { DataTableDirective } from 'angular-datatables'; import { ToastrService } from 'ngx-toastr'; -import { NgxSpinnerService } from 'ngx-spinner'; import { LoaderService } from '../../../common/services/loader.service'; import { ClipboardService } from 'ngx-clipboard'; @@ -31,7 +27,7 @@ import { ClipboardService } from 'ngx-clipboard'; export class DatatableComponent implements OnDestroy, OnInit, AfterViewInit, OnChanges { @ViewChild(DataTableDirective, { static: true }) datatableElement: DataTableDirective; dtOptions: any = {}; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); @Input() data = []; @Output() refresh = new EventEmitter(); diff --git a/src-gui/ui/src/app/modules/isl/isl-detail/isl-detail.component.html b/src-gui/ui/src/app/modules/isl/isl-detail/isl-detail.component.html index aeda71e7edc..9c89bf50452 100644 --- a/src-gui/ui/src/app/modules/isl/isl-detail/isl-detail.component.html +++ b/src-gui/ui/src/app/modules/isl/isl-detail/isl-detail.component.html @@ -34,13 +34,13 @@ {{src_switch_name }} -
+
{{bfdPropertyData.effective_source.properties['interval_ms']}}
-
+
{{bfdPropertyData.effective_source.properties['multiplier']}} @@ -100,13 +100,13 @@
-
+
{{bfdPropertyData.effective_destination.properties['interval_ms']}}
-
+
{{bfdPropertyData.effective_destination.properties['multiplier']}} @@ -209,9 +209,9 @@
- - +
ISL DETAILS
-
+
@@ -277,7 +277,7 @@

{{bfd_session_status}}

- +
@@ -299,7 +299,7 @@
- {{bfdPropertyData.properties['interval_ms']}} + {{bfdPropertyData?.properties?.['interval_ms']}}
@@ -307,7 +307,7 @@
- {{bfdPropertyData.properties['multiplier']}} + {{bfdPropertyData?.properties?.['multiplier']}}
@@ -336,7 +336,7 @@
-
@@ -345,7 +345,7 @@
-
diff --git a/src-gui/ui/src/app/modules/isl/isl-detail/isl-detail.component.ts b/src-gui/ui/src/app/modules/isl/isl-detail/isl-detail.component.ts index 5cb0ee8729e..4a42520b028 100644 --- a/src-gui/ui/src/app/modules/isl/isl-detail/isl-detail.component.ts +++ b/src-gui/ui/src/app/modules/isl/isl-detail/isl-detail.component.ts @@ -1,5 +1,4 @@ import {AfterViewInit, Component, EventEmitter, OnDestroy, OnInit, Output} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; import {ActivatedRoute, Router} from '@angular/router'; import {SwitchidmaskPipe} from '../../../common/pipes/switchidmask.pipe'; import {IslListService} from '../../../common/services/isl-list.service'; @@ -34,7 +33,6 @@ declare var moment: any; export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { openedTab = 'graph'; loaderName = 'graphSpinner'; - detailUrl = ''; src_switch = ''; src_port = ''; dst_switch = ''; @@ -56,13 +54,10 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { bfdPropertyData: any; src_switch_name: string; dst_switch_name: string; - graphDataForwardUrl: string; - graphDataBackwardUrl: string; responseGraph = []; src_switch_kilda: string; dst_switch_kilda: string; dataForISLFLowGraph = []; - callGraphAPIFlag = false; currentGraphData = { data: [], startDate: moment(new Date()).format('YYYY/MM/DD HH:mm:ss'), @@ -72,9 +67,8 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { series: {}, colors: [], }; - graphObj: any; message: {}; - getautoReloadValues = this.commonService.getAutoreloadValues(); + getautoReloadValues; filterForm: FormGroup; graphMetrics = []; @@ -86,7 +80,6 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { showDescriptionEditing = false; showBandwidthEditing = false; currentGraphName = 'Round Trip Latency Graph (In Seconds)'; - dateMessage: string; clipBoardItems = { sourceSwitchName: '', sourceSwitch: '', @@ -102,26 +95,24 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { this.islDataService.changeMessage(this.currentGraphData); } - constructor(private httpClient: HttpClient, - private route: ActivatedRoute, + constructor(private route: ActivatedRoute, private maskPipe: SwitchidmaskPipe, private router: Router, private islListService: IslListService, private toastr: ToastrService, private dygraphService: DygraphService, private islDataService: IslDataService, - private formBuiler: FormBuilder, + private formBuilder: FormBuilder, private loaderService: LoaderService, private clipboardService: ClipboardService, - private islFormBuiler: FormBuilder, private titleService: Title, private modalService: NgbModal, - private commonService: CommonService, + public commonService: CommonService, private islDetailService: IslDetailService, private statsService: StatsService, private graphLoader: NgxSpinnerService ) { - + this.getautoReloadValues = this.commonService.getAutoreloadValues(); if (!this.commonService.hasPermission('menu_isl')) { this.toastr.error(MessageObj.unauthorised); this.router.navigate(['/home']); @@ -147,7 +138,7 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { this.getIslDetailData(this.src_switch, this.src_port, this.dst_switch, this.dst_port); }); - this.filterForm = this.formBuiler.group({ + this.filterForm = this.formBuilder.group({ timezone: ['LOCAL'], fromDate: [dateRange.from], toDate: [dateRange.to], @@ -161,6 +152,17 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { no_flows: 10, auto_reload_time: ['', Validators.compose([Validators.pattern('[0-9]*')])] }); + this.bfdPropForm = this.formBuilder.group({ + interval_ms: [0, Validators.min(0)], + multiplier: [0, Validators.min(0)] + }); + + this.islForm = this.formBuilder.group({ + cost: [0, Validators.min(0)], + max_bandwidth: [0, Validators.min(0)], + description: '' + }); + this.graphMetrics = this.dygraphService.getPortMetricData(); this.flowGraphMetrics = this.dygraphService.getFlowMetricData(); } @@ -198,11 +200,6 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { this.islListService.getIslDetail(this.src_switch, this.src_port, this.dst_switch, this.dst_port).subscribe((data: any) => { if (data != null) { this.detailDataObservable = data; - this.islForm = this.islFormBuiler.group({ - cost: [this.detailDataObservable.cost, Validators.min(0)], - max_bandwidth: [this.max_bandwidth, Validators.min(0)], - description: [this.detailDataObservable.props.description], - }); } else { this.detailDataObservable = { 'props': { @@ -210,13 +207,10 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { 'description': '' } }; - - this.islForm = this.islFormBuiler.group({ - cost: [this.detailDataObservable.cost, Validators.min(0)], - max_bandwidth: [this.max_bandwidth, Validators.min(0)], - description: [this.detailDataObservable.props.description], - }); } + this.islForm.get('cost').setValue(this.detailDataObservable.props.cost); + this.islForm.get('max_bandwidth').setValue(this.max_bandwidth); + this.islForm.get('description').setValue(this.detailDataObservable.props.description); }, error => { this.toastr.error(MessageObj.no_cost_data_returned, 'Error'); }); @@ -224,16 +218,12 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { this.islListService.getLinkBFDProperties(this.src_switch, this.src_port, this.dst_switch, this.dst_port).subscribe((data: any) => { if (data != null) { this.bfdPropertyData = data; - this.bfdPropForm = this.formBuiler.group({ - interval_ms: [this.bfdPropertyData.properties['interval_ms'], Validators.min(0)], - multiplier: [this.bfdPropertyData.properties['multiplier'], Validators.min(0)] - }); + this.bfdPropForm.get('interval_ms').setValue(this.bfdPropertyData.properties['interval_ms']); + this.bfdPropForm.get('multiplier').setValue(this.bfdPropertyData.properties['multiplier']); } else { this.bfdPropertyData = {}; - this.bfdPropForm = this.formBuiler.group({ - interval_ms: [0, Validators.min(0)], - multiplier: [0, Validators.min(0)] - }); + this.bfdPropForm.get('interval_ms').setValue(0); + this.bfdPropForm.get('multiplier').setValue(0); } }, error => { @@ -674,7 +664,7 @@ export class IslDetailComponent implements OnInit, AfterViewInit, OnDestroy { graph, convertedStartDate, convertedEndDate).subscribe((res: VictoriaStatsRes) => { - const dataBackward = res.dataList; + const dataBackward = res.dataList; if (dataBackward[0] !== undefined) { dataBackward[0].tags.direction = 'R'; if (graph == 'rtt') { diff --git a/src-gui/ui/src/app/modules/isl/isl-flow-datatables/isl-flow-datatables.component.ts b/src-gui/ui/src/app/modules/isl/isl-flow-datatables/isl-flow-datatables.component.ts index 1ac1ef1bc62..ca62a43ff2f 100644 --- a/src-gui/ui/src/app/modules/isl/isl-flow-datatables/isl-flow-datatables.component.ts +++ b/src-gui/ui/src/app/modules/isl/isl-flow-datatables/isl-flow-datatables.component.ts @@ -5,7 +5,7 @@ import { LoaderService } from 'src/app/common/services/loader.service'; import { FlowsService } from 'src/app/common/services/flows.service'; import { ToastrService } from 'ngx-toastr'; import { FlowReRouteModalComponent } from 'src/app/common/components/flow-re-route-modal/flow-re-route-modal.component'; -import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { MessageObj } from 'src/app/common/constants/constants'; @Component({ @@ -24,7 +24,7 @@ export class IslFlowDatatablesComponent implements OnInit , AfterViewInit , OnDe islFlow = []; selectAll = false; reRouteList: any = []; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); wrapperHide = true; expandedFlowId = false; expandedSrcSwitchPort = false; diff --git a/src-gui/ui/src/app/modules/networkpath/networkpath.component.ts b/src-gui/ui/src/app/modules/networkpath/networkpath.component.ts index 45c17ee3c5d..9ae8bff5818 100644 --- a/src-gui/ui/src/app/modules/networkpath/networkpath.component.ts +++ b/src-gui/ui/src/app/modules/networkpath/networkpath.component.ts @@ -271,16 +271,16 @@ export class NetworkpathComponent implements OnInit { .zoom() .scaleExtent([this.min_zoom, this.max_zoom]) .extent([[0, 0], [width - 200, height - 50]]) - .on('zoom', () => { - self.zoomLevel = Math.round(d3.event.transform.k * 100) / 100; + .on('zoom', (event, d) => { + self.zoomLevel = Math.round(event.transform.k * 100) / 100; self.g.attr( 'transform', 'translate(' + - d3.event.transform.x + + event.transform.x + ',' + - d3.event.transform.y + + event.transform.y + ') scale(' + - d3.event.transform.k + + event.transform.k + ')' ); @@ -380,20 +380,20 @@ export class NetworkpathComponent implements OnInit { } return mLinkNum; } - dragStart = () => { - if (!d3.event.active) { this.forceSimulation.alphaTarget(1).stop(); } + dragStart = (event, d) => { + if (!event.active) { this.forceSimulation.alphaTarget(1).stop(); } } - dragging = (d: any, i) => { + dragging = (event, d) => { this.isDragMove = true; - d.py += d3.event.dy; - d.x += d3.event.dx; - d.y += d3.event.dy; + d.py += event.dy; + d.x += event.dx; + d.y += event.dy; this.tick(); } - dragEnd = (d: any, i) => { - if (!d3.event.active) { this.forceSimulation.alphaTarget(0); } + dragEnd = (event, d) => { + if (!event.active) { this.forceSimulation.alphaTarget(0); } this.flagHover = false; d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff this.tick(); diff --git a/src-gui/ui/src/app/modules/reports/affected-flow-list/affected-flow-list.component.ts b/src-gui/ui/src/app/modules/reports/affected-flow-list/affected-flow-list.component.ts index 6e0bf0fa51b..fbea62a6598 100644 --- a/src-gui/ui/src/app/modules/reports/affected-flow-list/affected-flow-list.component.ts +++ b/src-gui/ui/src/app/modules/reports/affected-flow-list/affected-flow-list.component.ts @@ -5,13 +5,11 @@ import { Subject } from 'rxjs'; import { Flow } from 'src/app/common/data-models/flow'; import { Router } from '@angular/router'; import { CommonService } from 'src/app/common/services/common.service'; -import { FormBuilder, FormGroup } from '@angular/forms'; +import { FormBuilder } from '@angular/forms'; import { ClipboardService } from 'ngx-clipboard'; -import { FlowReRouteModalComponent } from 'src/app/common/components/flow-re-route-modal/flow-re-route-modal.component'; -import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { FlowsService } from 'src/app/common/services/flows.service'; declare var jQuery: any; -import { MessageObj } from 'src/app/common/constants/constants'; @Component({ selector: 'app-affected-flow-list', @@ -27,7 +25,7 @@ export class AffectedFlowListComponent implements OnInit, AfterViewInit, OnChang typeFilter = ''; dtOptions = {}; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); wrapperHide = true; expandedSrcSwitchName = false; diff --git a/src-gui/ui/src/app/modules/reports/affected-flows-report/affected-flows-report.component.ts b/src-gui/ui/src/app/modules/reports/affected-flows-report/affected-flows-report.component.ts index 0cad7324c4b..28ef1bde343 100644 --- a/src-gui/ui/src/app/modules/reports/affected-flows-report/affected-flows-report.component.ts +++ b/src-gui/ui/src/app/modules/reports/affected-flows-report/affected-flows-report.component.ts @@ -1,9 +1,6 @@ import { AfterViewInit, Component, OnInit, ViewChild, OnDestroy, HostListener, Renderer2, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { DataTableDirective } from 'angular-datatables'; import { FlowsService } from '../../../common/services/flows.service'; import { ToastrService } from 'ngx-toastr'; -import { Subject } from 'rxjs'; -import { Flow } from '../../../common/data-models/flow'; import { Router } from '@angular/router'; import { LoaderService } from '../../../common/services/loader.service'; import { MessageObj } from 'src/app/common/constants/constants'; diff --git a/src-gui/ui/src/app/modules/settings/saml-list-table/saml-list-table.component.ts b/src-gui/ui/src/app/modules/settings/saml-list-table/saml-list-table.component.ts index 80d11c9018a..15cb1b63261 100644 --- a/src-gui/ui/src/app/modules/settings/saml-list-table/saml-list-table.component.ts +++ b/src-gui/ui/src/app/modules/settings/saml-list-table/saml-list-table.component.ts @@ -1,8 +1,6 @@ import { Component, OnInit , ViewChild, Input, OnChanges, Output, EventEmitter, Renderer2, SimpleChanges} from '@angular/core'; import { SamlSettingService } from 'src/app/common/services/saml-setting.service'; import { LoaderService } from 'src/app/common/services/loader.service'; -import {MessageObj} from '../../../common/constants/constants'; -import { ToastrService } from 'ngx-toastr'; import { DataTableDirective } from 'angular-datatables'; import { Subject } from 'rxjs'; @Component({ @@ -18,7 +16,7 @@ export class SamlListTableComponent implements OnInit , OnChanges { @Output() deletesaml = new EventEmitter(); dtOptions = {}; wrapperHide = true; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); constructor( private samlSettingService: SamlSettingService, private loaderService: LoaderService, diff --git a/src-gui/ui/src/app/modules/settings/saml-setting/saml-setting.component.ts b/src-gui/ui/src/app/modules/settings/saml-setting/saml-setting.component.ts index e13d8d0e39d..7406d4aefa9 100644 --- a/src-gui/ui/src/app/modules/settings/saml-setting/saml-setting.component.ts +++ b/src-gui/ui/src/app/modules/settings/saml-setting/saml-setting.component.ts @@ -3,7 +3,6 @@ import { SamlSettingService } from 'src/app/common/services/saml-setting.service import { LoaderService } from 'src/app/common/services/loader.service'; import {MessageObj} from '../../../common/constants/constants'; import { ToastrService } from 'ngx-toastr'; -import { DataTableDirective } from 'angular-datatables'; import { Subject } from 'rxjs'; import { ModalconfirmationComponent } from '../../../common/components/modalconfirmation/modalconfirmation.component'; import { ModalComponent } from '../../../common/components/modal/modal.component'; diff --git a/src-gui/ui/src/app/modules/switches/port-flows/port-flows.component.ts b/src-gui/ui/src/app/modules/switches/port-flows/port-flows.component.ts index 462c61d5664..811aa469cb1 100644 --- a/src-gui/ui/src/app/modules/switches/port-flows/port-flows.component.ts +++ b/src-gui/ui/src/app/modules/switches/port-flows/port-flows.component.ts @@ -18,7 +18,7 @@ export class PortFlowsComponent implements OnDestroy, OnInit, OnChanges, AfterV @Input() data; @Input() textSearch: any; dtOptions: any = {}; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); wrapperHide = false; srcSwitch: string; dstSwitch: string; diff --git a/src-gui/ui/src/app/modules/switches/port-graph/port-graph.component.ts b/src-gui/ui/src/app/modules/switches/port-graph/port-graph.component.ts index 7d45f6a3b67..ea68a56765e 100644 --- a/src-gui/ui/src/app/modules/switches/port-graph/port-graph.component.ts +++ b/src-gui/ui/src/app/modules/switches/port-graph/port-graph.component.ts @@ -35,7 +35,7 @@ export class PortGraphComponent implements OnInit, AfterViewInit, OnDestroy { graphSubscriber = null; responseGraph = []; autoReloadTimerId = null; - getautoReloadValues = this.commonService.getAutoreloadValues(); + getautoReloadValues; portMetrics = []; switchId = null; portId = null; @@ -51,7 +51,9 @@ export class PortGraphComponent implements OnInit, AfterViewInit, OnDestroy { private loaderService: LoaderService, private islDataService: IslDataService, private commonService: CommonService, - ) { } + ) { + this.getautoReloadValues = this.commonService.getAutoreloadValues(); + } ngOnInit() { this.route.parent.params.subscribe(params => this.switchId = params['id']); @@ -160,7 +162,7 @@ export class PortGraphComponent implements OnInit, AfterViewInit, OnDestroy { getPortGraphData( this.port_src_switch, this.portDataObject.port_number, - '', '', downsampling, + downsampling, metric, convertedStartDate, convertedEndDate).subscribe((data: VictoriaStatsRes) => { diff --git a/src-gui/ui/src/app/modules/switches/port-inventory-flows/port-inventory-flows.component.ts b/src-gui/ui/src/app/modules/switches/port-inventory-flows/port-inventory-flows.component.ts index d164b2830ec..c936a92db44 100644 --- a/src-gui/ui/src/app/modules/switches/port-inventory-flows/port-inventory-flows.component.ts +++ b/src-gui/ui/src/app/modules/switches/port-inventory-flows/port-inventory-flows.component.ts @@ -19,7 +19,7 @@ export class PortInventoryFlowsComponent implements OnDestroy, OnInit, OnChange @Input() data; @Input() textSearch: any; dtOptions: any = {}; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); wrapperHide = false; customername = false; customerid = false; diff --git a/src-gui/ui/src/app/modules/switches/port-list/port-list.component.ts b/src-gui/ui/src/app/modules/switches/port-list/port-list.component.ts index 927d837f1d9..4dbbfd44bce 100644 --- a/src-gui/ui/src/app/modules/switches/port-list/port-list.component.ts +++ b/src-gui/ui/src/app/modules/switches/port-list/port-list.component.ts @@ -26,7 +26,7 @@ export class PortListComponent implements OnInit, AfterViewInit, OnDestroy, OnCh @Input() loadinterval = false; isLoaderActive = false; dtOptions: any = {}; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); currentActivatedRoute: string; switch_id: string; diff --git a/src-gui/ui/src/app/modules/switches/switch-datatable/switch-datatable.component.ts b/src-gui/ui/src/app/modules/switches/switch-datatable/switch-datatable.component.ts index 3f8c8137bcd..13196eb4bc5 100644 --- a/src-gui/ui/src/app/modules/switches/switch-datatable/switch-datatable.component.ts +++ b/src-gui/ui/src/app/modules/switches/switch-datatable/switch-datatable.component.ts @@ -24,7 +24,7 @@ export class SwitchDatatableComponent implements OnInit, OnChanges, OnDestroy, A @Input() switchFilterFlag: string; @Input() textSearch: any; dtOptions: any = {}; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); wrapperHide = false; hasStoreSetting = false; flowSubscription: Subscription[] = []; diff --git a/src-gui/ui/src/app/modules/switches/switch-detail/switch-detail.component.ts b/src-gui/ui/src/app/modules/switches/switch-detail/switch-detail.component.ts index b1b2d53278a..3232f942000 100644 --- a/src-gui/ui/src/app/modules/switches/switch-detail/switch-detail.component.ts +++ b/src-gui/ui/src/app/modules/switches/switch-detail/switch-detail.component.ts @@ -4,7 +4,6 @@ import { SwitchidmaskPipe } from '../../../common/pipes/switchidmask.pipe'; import { ToastrService } from 'ngx-toastr'; import { Router, NavigationEnd, ActivatedRoute} from '@angular/router'; import { filter } from 'rxjs/operators'; -import { NgxSpinnerService } from 'ngx-spinner'; import { LoaderService } from '../../../common/services/loader.service'; import { ClipboardService } from 'ngx-clipboard'; import { Title } from '@angular/platform-browser'; @@ -37,7 +36,6 @@ export class SwitchDetailComponent implements OnInit, AfterViewInit, OnDestroy { switchFlows: any = []; openedTab = 'port'; isSwitchNameEdit = false; - isStorageDBType = false; evacuate = false; underMaintenance: boolean; flowBandwidthSum: any = 0; diff --git a/src-gui/ui/src/app/modules/switches/switch-flows/switch-flows.component.ts b/src-gui/ui/src/app/modules/switches/switch-flows/switch-flows.component.ts index 29b73f84c70..44d3c71c186 100644 --- a/src-gui/ui/src/app/modules/switches/switch-flows/switch-flows.component.ts +++ b/src-gui/ui/src/app/modules/switches/switch-flows/switch-flows.component.ts @@ -28,7 +28,7 @@ export class SwitchFlowsComponent implements OnDestroy, OnInit, OnChanges, After pingFlowIndex = {}; pingFlowList: any = []; selectedFlowList: any = []; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); wrapperHide = true; srcSwitch: string; diff --git a/src-gui/ui/src/app/modules/switches/switch-list/switch-list.component.ts b/src-gui/ui/src/app/modules/switches/switch-list/switch-list.component.ts index d3da146f1d9..622ad556c7c 100644 --- a/src-gui/ui/src/app/modules/switches/switch-list/switch-list.component.ts +++ b/src-gui/ui/src/app/modules/switches/switch-list/switch-list.component.ts @@ -6,7 +6,6 @@ import { ViewChild, Renderer2 } from '@angular/core'; -import { DataTableDirective } from 'angular-datatables'; import { SwitchService } from '../../../common/services/switch.service'; import { ToastrService } from 'ngx-toastr'; import { Subject } from 'rxjs'; diff --git a/src-gui/ui/src/app/modules/topology/failed-isl/failed-isl.component.ts b/src-gui/ui/src/app/modules/topology/failed-isl/failed-isl.component.ts index bb44b9f4096..9b34be0a0b7 100644 --- a/src-gui/ui/src/app/modules/topology/failed-isl/failed-isl.component.ts +++ b/src-gui/ui/src/app/modules/topology/failed-isl/failed-isl.component.ts @@ -13,7 +13,7 @@ export class FailedIslComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild(DataTableDirective, { static: true }) datatableElement: DataTableDirective; dtOptions: any = {}; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); failedISL: any; diff --git a/src-gui/ui/src/app/modules/topology/topology.component.ts b/src-gui/ui/src/app/modules/topology/topology.component.ts index 46b5b63ad2c..eaf40ec3c6e 100644 --- a/src-gui/ui/src/app/modules/topology/topology.component.ts +++ b/src-gui/ui/src/app/modules/topology/topology.component.ts @@ -1,11 +1,8 @@ import { Component, OnInit, - ViewChild, AfterViewInit, HostListener, - ElementRef, - ViewContainerRef, Renderer2, OnDestroy } from '@angular/core'; @@ -15,7 +12,6 @@ import { UserService } from '../../common/services/user.service'; import { ISL } from '../../common/enums/isl.enum'; import { CommonService } from '../../common/services/common.service'; import * as d3 from 'd3'; -import { NgbTypeahead } from '@ng-bootstrap/ng-bootstrap'; import { TopologyView } from '../../common/data-models/topology-view'; import { FlowsService } from '../../common/services/flows.service'; import { Observable } from 'rxjs'; @@ -24,7 +20,6 @@ import { environment } from '../../../environments/environment'; import { LoaderService } from '../../common/services/loader.service'; import { ToastrService } from 'ngx-toastr'; import { Title } from '@angular/platform-browser'; -import { scaleBand } from 'd3'; import { Router } from '@angular/router'; declare var jQuery: any; import { MessageObj } from 'src/app/common/constants/constants'; @@ -229,21 +224,21 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { .zoom() .scaleExtent([this.scaleLimit, this.max_zoom]) .extent([[0, 0], [this.width, this.height]]) - .on('zoom', () => { + .on('zoom', (event) => { // this.forceSimulation.stop(); this.g.attr( 'transform', 'translate(' + - d3.event.transform.x + + event.transform.x + ',' + - d3.event.transform.y + + event.transform.y + ') scale(' + - d3.event.transform.k + + event.transform.k + ')' ); - this.zoomLevel = Math.round(d3.event.transform.k * 100) / 100; - this.translateX = d3.event.transform.x; - this.translateY = d3.event.transform.y; + this.zoomLevel = Math.round(event.transform.k * 100) / 100; + this.translateX = event.transform.x; + this.translateY = event.transform.y; this.isDragMove = true; $('#topology-hover-txt, #switch_hover').css('display', 'none'); $('#topology-click-txt').css('display', 'none'); @@ -527,7 +522,7 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { return 'image_' + index; }) .attr('cursor', 'pointer') - .on('mouseover', function(d, index) { + .on('mouseover', function(event, d) { $('#isl_hover').css('display', 'none'); const element = document.getElementById('circle_' + d.switch_id); @@ -574,7 +569,7 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { } }) - .on('mouseout', function(d, index) { + .on('mouseout', function(event, d) { if (this.flagHover == false) { this.flagHover = true; } else { @@ -592,7 +587,7 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { } }) - .on('click', function(d, index) { + .on('click', function(event, d) { $('#topology-hover-txt').css('display', 'none'); const cName = document.getElementById('circle_' + d.switch_id).className; @@ -698,7 +693,8 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { .attr('id', (d, index) => { return 'link' + index; }) - .on('mouseover', function(d, index) { + .on('mouseover', function(event, d) { + const index = d.index; $('#switch_hover').css('display', 'none'); const element = $('#link' + index)[0]; const availbandwidth = d.available_bandwidth; @@ -866,9 +862,9 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { ); } }) - .on('mouseout', function(d, index) { + .on('mouseout', function(event, d) { $('#topology-hover-txt, #isl_hover').css('display', 'none'); - const element = $('#link' + index)[0]; + const element = $('#link' + d.index)[0]; const availbandwidth = d.available_bandwidth; const max_bandwidth = d.max_bandwidth; const percentage = ref.commonService.getPercentage(availbandwidth, max_bandwidth); @@ -925,8 +921,8 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { $('#topology-hover-txt, #isl_hover').css('display', 'none'); } }) - .on('click', function(d, index) { - const element = $('#link' + index)[0]; + .on('click', function(event, d) { + const element = $('#link' + d.index)[0]; const availbandwidth = d.available_bandwidth; const max_bandwidth = d.max_bandwidth; const percentage = ref.commonService.getPercentage(availbandwidth, max_bandwidth); @@ -1058,7 +1054,8 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { return r; } }) - .on('mouseover', function(d, index) { + .on('mouseover', function(event, d) { + const index = d.index; const element = $('#link' + index)[0]; const availbandwidth = d.available_bandwidth; let classes = ''; @@ -1075,8 +1072,8 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { } element.setAttribute('class', classes); }) - .on('mouseout', function(d, index) { - const element = $('#link' + index)[0]; + .on('mouseout', function(event, d) { + const element = $('#link' + d.index)[0]; const availbandwidth = d.available_bandwidth; let classes = ''; const max_bandwidth = d.max_bandwidth; @@ -1095,7 +1092,7 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { } element.setAttribute('class', classes); }) - .on('click', function(d, index) { + .on('click', function(event, d) { ref.showFlowDetails(d); }) .attr('class', 'linecircle') @@ -1908,24 +1905,24 @@ export class TopologyComponent implements OnInit, AfterViewInit, OnDestroy { this.syncUserCoordinatesChanges(); } - dragStart = () => { - if (!d3.event.active) { this.forceSimulation.alphaTarget(1).stop(); } + dragStart = (event, d) => { + if (!event.active) { this.forceSimulation.alphaTarget(1).stop(); } jQuery('#topology-hover-txt').hide(); jQuery('#topology-click-txt').hide(); } - dragging = (d: any, i) => { + dragging = (event, d) => { jQuery('#topology-hover-txt').hide(); jQuery('#topology-click-txt').hide(); this.isDragMove = true; - d.py += d3.event.dy; - d.x += d3.event.dx; - d.y += d3.event.dy; + d.py += event.dy; + d.x += event.dx; + d.y += event.dy; this.tick(); } - dragEnd = (d: any, i) => { - if (!d3.event.active) { this.forceSimulation.alphaTarget(0); } + dragEnd = (event, d) => { + if (!event.active) { this.forceSimulation.alphaTarget(0); } this.flagHover = false; d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff this.tick(); diff --git a/src-gui/ui/src/app/modules/topology/unidirectional-isl/unidirectional-isl.component.ts b/src-gui/ui/src/app/modules/topology/unidirectional-isl/unidirectional-isl.component.ts index efcf5e52ac2..d5ebf54387f 100644 --- a/src-gui/ui/src/app/modules/topology/unidirectional-isl/unidirectional-isl.component.ts +++ b/src-gui/ui/src/app/modules/topology/unidirectional-isl/unidirectional-isl.component.ts @@ -13,7 +13,7 @@ export class UnidirectionalIslComponent implements OnInit, AfterViewInit, OnDest @ViewChild(DataTableDirective, { static: true }) datatableElement: DataTableDirective; dtOptions: any = {}; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); unidirectionalISL: any; uexpandedSrcSwitchName = false; diff --git a/src-gui/ui/src/app/modules/topology/world-map-view/world-map-view.component.ts b/src-gui/ui/src/app/modules/topology/world-map-view/world-map-view.component.ts index 50274c27e4e..5f0a4f3fb09 100644 --- a/src-gui/ui/src/app/modules/topology/world-map-view/world-map-view.component.ts +++ b/src-gui/ui/src/app/modules/topology/world-map-view/world-map-view.component.ts @@ -323,16 +323,18 @@ export class WorldMapViewComponent implements OnInit, AfterViewInit, OnChanges, initMap() { this.overlay = new Overlay({ element: this.container, - autoPan: true, - autoPanAnimation: { - duration: 250, + autoPan: { + animation: { + duration: 250 + } }, }); this.popInfoOverlay = new Overlay({ element: this.popinfocontainer, - autoPan: true, - autoPanAnimation: { - duration: 250, + autoPan: { + animation: { + duration: 250 + } }, }); this.map = new Map({ @@ -667,7 +669,7 @@ export class WorldMapViewComponent implements OnInit, AfterViewInit, OnChanges, }, }); this.map.addLayer(vectorLayer); - vectorLayer.setZIndex(5, 10); + vectorLayer.setZIndex(5); setTimeout(() => { this.loadCLusterLinks(); }, 500); @@ -836,7 +838,7 @@ export class WorldMapViewComponent implements OnInit, AfterViewInit, OnChanges, } }); this.map.addLayer(this.clusterLinkLayer); - this.clusterLinkLayer.setZIndex(2, 10); + this.clusterLinkLayer.setZIndex(2); }, 100); } } @@ -938,7 +940,7 @@ export class WorldMapViewComponent implements OnInit, AfterViewInit, OnChanges, } }); this.map.addLayer(this.linkLayer); - this.linkLayer.setZIndex(2, 10); + this.linkLayer.setZIndex(2); }, 100); } diff --git a/src-gui/ui/src/app/modules/useractivity/useractivity-list/useractivity-list.component.ts b/src-gui/ui/src/app/modules/useractivity/useractivity-list/useractivity-list.component.ts index 4f99bed6dd2..27abfcdf7a0 100644 --- a/src-gui/ui/src/app/modules/useractivity/useractivity-list/useractivity-list.component.ts +++ b/src-gui/ui/src/app/modules/useractivity/useractivity-list/useractivity-list.component.ts @@ -13,7 +13,7 @@ export class UseractivityListComponent implements OnInit, OnChanges { @Input() data = []; dtOptions = {}; wrapperHide = true; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); expandedActivityTime = false; expandedClientIpAddress = false; expandedUserId = false; diff --git a/src-gui/ui/src/app/modules/useractivity/useractivity.component.ts b/src-gui/ui/src/app/modules/useractivity/useractivity.component.ts index 112d2755c40..e75e1d7a558 100644 --- a/src-gui/ui/src/app/modules/useractivity/useractivity.component.ts +++ b/src-gui/ui/src/app/modules/useractivity/useractivity.component.ts @@ -1,14 +1,11 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms'; import { NgOption } from '@ng-select/ng-select'; -import { Select2Data } from 'ng-select2-component/lib/select2-utils'; import { UserActivityService } from '../../common/services/user-activity.service'; import { ToastrService } from 'ngx-toastr'; -import { NgxSpinnerService } from 'ngx-spinner'; import * as _moment from 'moment'; import { LoaderService } from '../../common/services/loader.service'; import { Title } from '@angular/platform-browser'; -import { tickStep } from 'd3'; import { CommonService } from 'src/app/common/services/common.service'; import { Router } from '@angular/router'; import { MessageObj } from 'src/app/common/constants/constants'; diff --git a/src-gui/ui/src/app/modules/usermanagement/permissions/permission-edit/permission-edit.component.ts b/src-gui/ui/src/app/modules/usermanagement/permissions/permission-edit/permission-edit.component.ts index 8c50a338cab..b1854923ce8 100644 --- a/src-gui/ui/src/app/modules/usermanagement/permissions/permission-edit/permission-edit.component.ts +++ b/src-gui/ui/src/app/modules/usermanagement/permissions/permission-edit/permission-edit.component.ts @@ -1,13 +1,13 @@ import { Component, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; import { FormGroup, FormControl, Validators } from '@angular/forms'; -import { Select2Data } from 'ng-select2-component/lib/select2-utils'; import { TabService } from '../../../../common/services/tab.service'; import { PermissionService } from '../../../../common/services/permission.service'; import { ToastrService } from 'ngx-toastr'; import { Title } from '@angular/platform-browser'; import { LoaderService } from '../../../../common/services/loader.service'; import { MessageObj } from 'src/app/common/constants/constants'; +import {Select2Data} from 'ng-select2-component'; @Component({ selector: 'app-permission-edit', @@ -54,8 +54,8 @@ export class PermissionEditComponent implements OnInit { */ private createAssignForm() { this.permissionEditForm = new FormGroup({ - name: new FormControl({value: ''}, Validators.required), - description: new FormControl({value: ''}) + name: new FormControl({value: '', disabled: false}, Validators.required), + description: new FormControl({value: '', disabled: false}) }); } diff --git a/src-gui/ui/src/app/modules/usermanagement/permissions/permission-list/permission-list.component.ts b/src-gui/ui/src/app/modules/usermanagement/permissions/permission-list/permission-list.component.ts index e19425c3789..fbe4ffc76eb 100644 --- a/src-gui/ui/src/app/modules/usermanagement/permissions/permission-list/permission-list.component.ts +++ b/src-gui/ui/src/app/modules/usermanagement/permissions/permission-list/permission-list.component.ts @@ -22,7 +22,7 @@ export class PermissionListComponent implements OnDestroy, OnInit, AfterViewInit datatableElement: DataTableDirective; dtOptions: any = {}; allPermissions: any; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); changeStatus: any; hide = false; loadCount = 0; diff --git a/src-gui/ui/src/app/modules/usermanagement/permissions/permission-view/permission-view.component.ts b/src-gui/ui/src/app/modules/usermanagement/permissions/permission-view/permission-view.component.ts index 77565820923..23adf1b1d67 100644 --- a/src-gui/ui/src/app/modules/usermanagement/permissions/permission-view/permission-view.component.ts +++ b/src-gui/ui/src/app/modules/usermanagement/permissions/permission-view/permission-view.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; import { FormGroup, FormControl, Validators } from '@angular/forms'; -import { Select2Data } from 'ng-select2-component/lib/select2-utils'; import { TabService } from '../../../../common/services/tab.service'; import { PermissionService } from '../../../../common/services/permission.service'; import { Title } from '@angular/platform-browser'; +import {Select2Data} from 'ng-select2-component'; @Component({ selector: 'app-permission-view', diff --git a/src-gui/ui/src/app/modules/usermanagement/roles/role-add/role-add.component.ts b/src-gui/ui/src/app/modules/usermanagement/roles/role-add/role-add.component.ts index e5628ce76fd..4cf052a56d5 100644 --- a/src-gui/ui/src/app/modules/usermanagement/roles/role-add/role-add.component.ts +++ b/src-gui/ui/src/app/modules/usermanagement/roles/role-add/role-add.component.ts @@ -1,7 +1,6 @@ import { Component, OnInit, Input, Output, EventEmitter, HostBinding, AfterViewInit } from '@angular/core'; import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms'; import { NgOption } from '@ng-select/ng-select'; -import { Select2Data } from 'ng-select2-component/lib/select2-utils'; import { TabService } from '../../../../common/services/tab.service'; import { PermissionService } from '../../../../common/services/permission.service'; import { RoleService } from '../../../../common/services/role.service'; diff --git a/src-gui/ui/src/app/modules/usermanagement/roles/role-edit/role-edit.component.ts b/src-gui/ui/src/app/modules/usermanagement/roles/role-edit/role-edit.component.ts index 2c841190375..56b08e816aa 100644 --- a/src-gui/ui/src/app/modules/usermanagement/roles/role-edit/role-edit.component.ts +++ b/src-gui/ui/src/app/modules/usermanagement/roles/role-edit/role-edit.component.ts @@ -83,9 +83,9 @@ export class RoleEditComponent implements OnInit, AfterViewInit { */ private createEditForm() { this.roleEditForm = new FormGroup({ - name: new FormControl({value: ''}, Validators.required), - description: new FormControl({value: ''}, Validators.required), - permission: new FormControl({value: ''}, Validators.required) + name: new FormControl({value: '', disabled: false}, Validators.required), + description: new FormControl({value: '', disabled: false}, Validators.required), + permission: new FormControl({value: '', disabled: false}, Validators.required) }); } diff --git a/src-gui/ui/src/app/modules/usermanagement/roles/role-list/role-list.component.ts b/src-gui/ui/src/app/modules/usermanagement/roles/role-list/role-list.component.ts index a6633842d26..87d99a5dbc6 100644 --- a/src-gui/ui/src/app/modules/usermanagement/roles/role-list/role-list.component.ts +++ b/src-gui/ui/src/app/modules/usermanagement/roles/role-list/role-list.component.ts @@ -22,7 +22,7 @@ export class RoleListComponent implements OnDestroy, OnInit, AfterViewInit { datatableElement: DataTableDirective; dtOptions: any = {}; roleData: any; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); hide = false; loadCount = 0; expandedName = false; diff --git a/src-gui/ui/src/app/modules/usermanagement/users/user-list/user-list.component.ts b/src-gui/ui/src/app/modules/usermanagement/users/user-list/user-list.component.ts index bbabd97a037..b6b5fd20d56 100644 --- a/src-gui/ui/src/app/modules/usermanagement/users/user-list/user-list.component.ts +++ b/src-gui/ui/src/app/modules/usermanagement/users/user-list/user-list.component.ts @@ -25,7 +25,7 @@ export class UserListComponent implements OnDestroy, OnInit, AfterViewInit { dtOptions: any = {}; users: any; - dtTrigger: Subject = new Subject(); + dtTrigger: Subject = new Subject(); changeStatus: any; loggedInUserId: any; hide = false; diff --git a/src-gui/ui/src/main.ts b/src-gui/ui/src/main.ts index 91ec6da5f07..f6d2763c330 100644 --- a/src-gui/ui/src/main.ts +++ b/src-gui/ui/src/main.ts @@ -1,3 +1,5 @@ +/// + import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; diff --git a/src-gui/ui/src/polyfills.ts b/src-gui/ui/src/polyfills.ts index a088390e02e..616565be16a 100644 --- a/src-gui/ui/src/polyfills.ts +++ b/src-gui/ui/src/polyfills.ts @@ -27,7 +27,7 @@ * Zone JS is required by default for Angular itself. */ import 'zone.js/dist/zone'; // Included with Angular CLI. - +import '@angular/localize/init'; /*************************************************************************************************** diff --git a/src-gui/ui/src/styles.css b/src-gui/ui/src/styles.css index 08afd5f2f4d..faa5bc98787 100644 --- a/src-gui/ui/src/styles.css +++ b/src-gui/ui/src/styles.css @@ -168,12 +168,12 @@ h1 { padding: 30px 15px; font-family: "Telstra-Regular", Arial, Helvetica, sans-serif; font-size: 13px; - min-height: 500px; + min-height: 500px; z-index: 1; } #switchdetails_div .tab-content { - min-height: 450; + min-height: 450; } .tab-wrapper { @@ -700,19 +700,19 @@ div.switch5 > input.switch:focus ~ label:before { } .onoffswitch-flow-ping { - right: 93px; + right: 93px; } .onoffflow-ping { width: 120px; } .onoffswitch-switch-meter { - right: 82px; + right: 82px; } .onoffswitch-meter { width: 110px; } .onoffswitch-switch-connected-devices { - right: 85px; + right: 85px; } .onoffswitch-connected-devices { width: 110px; @@ -1371,7 +1371,7 @@ path.link { stroke-width:2.5px; } .orange_percentage{ - stroke-width: 5!important; + stroke-width: 5!important; stroke:#FF8C00; } .diff_bandwidth { @@ -1638,7 +1638,7 @@ tbody tr.maintenance_isl td, tbody tr.maintenance_switch td{ font-size: 12px !important; } -.ng-dygraphs .ng-dygraphs-chart-container { +.app-custom-dygraphs .dygraphs-chart-container { padding-top: 24px; padding-bottom: 0; padding-left: 0; @@ -1670,7 +1670,7 @@ tbody tr.maintenance_isl td, tbody tr.maintenance_switch td{ cursor: pointer; } -.ng-dygraphs .loader-holder { +.app-custom-dygraphs .loader-holder { position: absolute; display: -ms-flexbox; display: -webkit-box; @@ -1685,7 +1685,7 @@ tbody tr.maintenance_isl td, tbody tr.maintenance_switch td{ opacity: 0.9; } -.ng-dygraphs .loader { +.app-custom-dygraphs .loader { border: 5px solid #f3f3f3 !important; border-top: 5px solid #3498db !important; border-radius: 50% !important; @@ -1709,7 +1709,7 @@ table.dataTable thead .sorting, table.dataTable thead .sorting_asc, table.dataTa } table.dataTable thead .sorting { - /* background-image: url('../images/sort_both.png'); + /* background-image: url('../images/sort_both.png'); background-image: url(assets/images/sort_both.png);*/ background-image: url(assets/images/sort_both_white.png); } @@ -1775,7 +1775,7 @@ table.dataTable thead .sorting, table.dataTable thead .sorting_asc, table.dataTa .modal-header .close {padding: 0; margin: 0;} -.control-label.required:after { +.control-label.required:after { color: #d00; content: "*"; position: absolute; @@ -1974,6 +1974,7 @@ label.btn.kilda_btn > span.copy_to_clipBoard { .modal.show { top: 0; + z-index: 1060; } .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value { @@ -2405,7 +2406,7 @@ width:100%; color: rgb(27, 31, 38); font-size: 18px; text-align: center; - z-index: 3; + z-index: 3; transition: all 0.5s ease; } @@ -2422,7 +2423,7 @@ width:100%; display: inline-block; width: 100%; cursor: pointer; - z-index:1; + z-index:1; } .sidebar-toggle:hover .icon-group .fa { @@ -2578,7 +2579,7 @@ a.badge.badge-dark.custom-button { .islPath:hover { background: #00baff!important; height:4px!important; - + } /** path css end ****/ @@ -2780,7 +2781,7 @@ table.network-path-tbl{ -webkit-overflow-scrolling: touch; -ms-overflow-style: -ms-autohiding-scrollbar; } -table.network-path-tbl thead { +table.network-path-tbl thead { background-color: #343a40; border-color: #343a40; color: #FFF; @@ -3076,7 +3077,7 @@ left: calc(100% - 16px); left: 0; text-align:center; background: #FFF; -} +} .my-custom-scrollbar { position: relative; height: 300px; @@ -3088,8 +3089,8 @@ left: calc(100% - 16px); #popup-content .tableLinks table th{ background: #CCC; width:10%; - } - + } + .islLink a:hover { color: #212529!important; text-decoration: none!important; diff --git a/src-gui/ui/src/tsconfig.app.json b/src-gui/ui/src/tsconfig.app.json index 190fd300b60..589c072598b 100644 --- a/src-gui/ui/src/tsconfig.app.json +++ b/src-gui/ui/src/tsconfig.app.json @@ -2,7 +2,9 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/app", - "types": [] + "types": [ + "@angular/localize" + ] }, "exclude": [ "test.ts", diff --git a/src-gui/ui/src/tsconfig.spec.json b/src-gui/ui/src/tsconfig.spec.json index de7733630eb..bceb363ce5f 100644 --- a/src-gui/ui/src/tsconfig.spec.json +++ b/src-gui/ui/src/tsconfig.spec.json @@ -4,7 +4,8 @@ "outDir": "../out-tsc/spec", "types": [ "jasmine", - "node" + "node", + "@angular/localize" ] }, "files": [ diff --git a/src-gui/ui/tsconfig.json b/src-gui/ui/tsconfig.json index 91b4bfb2eb5..2401b25e5f8 100644 --- a/src-gui/ui/tsconfig.json +++ b/src-gui/ui/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, - "target": "es2015", + "target": "es2022", "typeRoots": [ "node_modules/@types" ], diff --git a/src-gui/ui/tslint.json b/src-gui/ui/tslint.json deleted file mode 100644 index f5f06e9e8e8..00000000000 --- a/src-gui/ui/tslint.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "rulesDirectory": [ - "node_modules/codelyzer" - ], - "rules": { - "arrow-return-shorthand": true, - "callable-types": true, - "class-name": true, - "comment-format": [ - true, - "check-space" - ], - "curly": true, - "deprecation": { - "severity": "warn" - }, - "eofline": true, - "forin": true, - "import-blacklist": [ - true, - "rxjs/Rx" - ], - "import-spacing": true, - "indent": [ - true, - "spaces" - ], - "interface-over-type-literal": true, - "label-position": true, - "max-line-length": [ - true, - 140 - ], - "member-access": false, - "member-ordering": [ - true, - { - "order": [ - "static-field", - "instance-field", - "static-method", - "instance-method" - ] - } - ], - "no-arg": true, - "no-bitwise": true, - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-construct": true, - "no-debugger": true, - "no-duplicate-super": true, - "no-empty": false, - "no-empty-interface": true, - "no-eval": true, - "no-inferrable-types": [ - true, - "ignore-params" - ], - "no-misused-new": true, - "no-non-null-assertion": true, - "no-shadowed-variable": true, - "no-string-literal": false, - "no-string-throw": true, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": true, - "no-unnecessary-initializer": true, - "no-unused-expression": true, - "no-use-before-declare": true, - "no-var-keyword": true, - "object-literal-sort-keys": false, - "one-line": [ - true, - "check-open-brace", - "check-catch", - "check-else", - "check-whitespace" - ], - "prefer-const": true, - "quotemark": [ - true, - "single" - ], - "radix": true, - "semicolon": [ - true, - "always" - ], - "triple-equals": [ - true, - "allow-null-check" - ], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "unified-signatures": true, - "variable-name": false, - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type" - ], - "no-output-on-prefix": true, - "no-inputs-metadata-property": true, - "no-outputs-metadata-property": true, - "no-host-metadata-property": true, - "no-input-rename": true, - "no-output-rename": true, - "use-lifecycle-interface": true, - "use-pipe-transform-interface": true, - "component-class-suffix": true, - "directive-class-suffix": true - } -} diff --git a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/history/model/HaFlowEventData.java b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/history/model/HaFlowEventData.java index 5cffb2eddd0..f7177fe07f2 100644 --- a/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/history/model/HaFlowEventData.java +++ b/src-java/base-topology/base-storm-topology/src/main/java/org/openkilda/wfm/share/history/model/HaFlowEventData.java @@ -55,7 +55,8 @@ public enum Event { PARTIAL_UPDATE("HA-Flow partial update"), REROUTE("HA-Flow reroute"), DELETE("HA-Flow delete"), - PATH_SWAP("HA-flow path swap"); + PATH_SWAP("HA-Flow path swap"), + FLOW_SYNC("HA-Flow sync"); private final String description; } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/FlowProcessingWithHistorySupportFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/FlowProcessingWithHistorySupportFsm.java index ccad2ec143c..8984b639d3a 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/FlowProcessingWithHistorySupportFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/FlowProcessingWithHistorySupportFsm.java @@ -142,7 +142,8 @@ public void saveNewEventToHistory(String action, FlowEventData.Event event) { } /** - * Add a history record on the new event. + * Add a history record on the new event. Pay attention that this method prepends the Flow ID to the task ID, + * which is later used for fetching the history. If other methods in an FSM don't do the same, the history is lost. */ public void saveNewEventToHistory(String flowId, String action, FlowEventData.Event event) { String taskId = KeyProvider.joinKeys(flowId, getCommandContext().getCorrelationId()); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/actions/CreateNewHistoryEventAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/actions/CreateNewHistoryEventAction.java new file mode 100644 index 00000000000..8fde7db41e7 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/actions/CreateNewHistoryEventAction.java @@ -0,0 +1,52 @@ +/* Copyright 2023 Telstra Open Source + * + * 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. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.common.actions; + +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.share.history.model.FlowEventData; +import org.openkilda.wfm.topology.flowhs.fsm.common.FlowProcessingWithHistorySupportFsm; + +/** + * This action is useful to execute before any other actions in an FSM. This way you don't need to worry about + * creating a new history event, and you can focus on the business logic. + * @param State machine type must support sending history, the persistenceManager and the Flow ID must be available + * @param State type is generic + * @param Event type is generic + * @param Context type is generic + */ +public class CreateNewHistoryEventAction, S, E, C> + extends FlowProcessingWithHistorySupportAction { + private final FlowEventData.Event historyEvent; + private final String actionTitle; + + public CreateNewHistoryEventAction(PersistenceManager persistenceManager, FlowEventData.Event historyEvent) { + super(persistenceManager); + this.historyEvent = historyEvent; + this.actionTitle = historyEvent.getDescription() + " operation has been started."; + } + + public CreateNewHistoryEventAction(PersistenceManager persistenceManager, FlowEventData.Event historyEvent, + String actionTitle) { + super(persistenceManager); + this.historyEvent = historyEvent; + this.actionTitle = actionTitle; + } + + @Override + protected void perform(S from, S to, E event, C context, T stateMachine) { + stateMachine.saveNewEventToHistory(actionTitle, historyEvent); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/actions/haflow/CreateNewHaFlowHistoryEventAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/actions/haflow/CreateNewHaFlowHistoryEventAction.java new file mode 100644 index 00000000000..797b7c9aae7 --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/common/actions/haflow/CreateNewHaFlowHistoryEventAction.java @@ -0,0 +1,57 @@ +/* Copyright 2023 Telstra Open Source + * + * 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. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow; + +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.share.history.model.HaFlowEventData; +import org.openkilda.wfm.topology.flowhs.fsm.common.HaFlowProcessingFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.context.SpeakerResponseContext; +import org.openkilda.wfm.topology.flowhs.service.history.FlowHistoryService; + +public class CreateNewHaFlowHistoryEventAction + , S, E, C extends SpeakerResponseContext> + extends HaFlowProcessingWithHistorySupportAction { + + private final HaFlowEventData.Event historyEvent; + private final String actionTitle; + + public CreateNewHaFlowHistoryEventAction(PersistenceManager persistenceManager, + HaFlowEventData.Event historyEvent) { + super(persistenceManager); + this.historyEvent = historyEvent; + this.actionTitle = historyEvent.getDescription() + " operation has been started."; + } + + public CreateNewHaFlowHistoryEventAction(PersistenceManager persistenceManager, + HaFlowEventData.Event historyEvent, + String actionTitle) { + super(persistenceManager); + this.historyEvent = historyEvent; + this.actionTitle = actionTitle; + } + + @Override + protected void perform(S from, S to, E event, C context, T stateMachine) { + FlowHistoryService flowHistoryService = FlowHistoryService.using(stateMachine.getCarrier()); + + flowHistoryService.saveNewHaFlowEvent(HaFlowEventData.builder() + .action(actionTitle) + .event(historyEvent) + .taskId(stateMachine.getCommandContext().getCorrelationId()) + .haFlowId(stateMachine.getHaFlowId()) + .build()); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/FlowCreateFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/FlowCreateFsm.java index 8231cf726c6..711ada8e0ba 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/FlowCreateFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/FlowCreateFsm.java @@ -26,10 +26,12 @@ import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResources; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.FlowProcessingWithHistorySupportFsm; import org.openkilda.wfm.topology.flowhs.fsm.common.SpeakerCommandFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NotifyFlowMonitorAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.ReportErrorAction; import org.openkilda.wfm.topology.flowhs.fsm.create.FlowCreateFsm.Event; @@ -206,6 +208,12 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager final ReportErrorAction reportErrorAction = new ReportErrorAction<>(Event.TIMEOUT); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, FlowEventData.Event.CREATE)); + // validate the flow builder.transition() .from(State.INITIALIZED) @@ -411,7 +419,7 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager public FlowCreateFsm newInstance(@NonNull CommandContext commandContext, @NonNull String flowId, @NonNull Collection eventListeners) { - FlowCreateFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, + FlowCreateFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, flowId, eventListeners, config); fsm.addTransitionCompleteListener(event -> @@ -466,6 +474,7 @@ public static class Config implements Serializable { } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, RESOURCES_ALLOCATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/actions/FlowValidateAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/actions/FlowValidateAction.java index 7aedbc9402a..b776a8344dd 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/actions/FlowValidateAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/create/actions/FlowValidateAction.java @@ -21,7 +21,6 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -79,12 +78,8 @@ protected Optional performWithResponse(State from, State to, Event even stateMachine.setTargetFlow(request); - if (event != Event.RETRY) { - stateMachine.saveNewEventToHistory("Flow was validated successfully", FlowEventData.Event.CREATE); - } else { - // no need to save a new event into DB, it should already exist there. - stateMachine.saveActionToHistory("Flow was validated successfully"); - } + stateMachine.saveActionToHistory("Flow was validated successfully", + event == Event.RETRY ? "Retrying the operation" : null); return Optional.empty(); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/delete/FlowDeleteFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/delete/FlowDeleteFsm.java index 7c33275b94f..48ba91a2d14 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/delete/FlowDeleteFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/delete/FlowDeleteFsm.java @@ -25,9 +25,11 @@ import org.openkilda.wfm.share.flow.resources.FlowMirrorPathResources; import org.openkilda.wfm.share.flow.resources.FlowResources; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.FlowProcessingWithHistorySupportFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NotifyFlowMonitorAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.ReportErrorAction; import org.openkilda.wfm.topology.flowhs.fsm.delete.FlowDeleteFsm.Event; @@ -143,6 +145,12 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager final ReportErrorAction reportErrorAction = new ReportErrorAction<>(Event.TIMEOUT); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, FlowEventData.Event.DELETE)); + builder.transition().from(State.INITIALIZED).to(State.FLOW_VALIDATED).on(Event.NEXT) .perform(new ValidateFlowAction(persistenceManager, dashboardLogger)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -221,7 +229,7 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager public FlowDeleteFsm newInstance(@NonNull CommandContext commandContext, @NonNull String flowId, @NonNull Collection eventListeners) { - FlowDeleteFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, + FlowDeleteFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, flowId, eventListeners); fsm.addTransitionCompleteListener(event -> @@ -263,6 +271,7 @@ public FlowDeleteFsm newInstance(@NonNull CommandContext commandContext, @NonNul } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/delete/actions/ValidateFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/delete/actions/ValidateFlowAction.java index b3d69b20621..b7fc43bf671 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/delete/actions/ValidateFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/delete/actions/ValidateFlowAction.java @@ -24,7 +24,6 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -78,7 +77,7 @@ protected Optional performWithResponse(State from, State to, Event even stateMachine.setDstSwitchId(resultFlow.getDestSwitchId()); stateMachine.setSrcSwitchId(resultFlow.getSrcSwitchId()); - stateMachine.saveNewEventToHistory("Flow was validated successfully", FlowEventData.Event.DELETE); + stateMachine.saveActionToHistory("Flow was validated successfully"); return Optional.of(buildResponseMessage(resultFlow, stateMachine.getCommandContext())); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/create/HaFlowCreateFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/create/HaFlowCreateFsm.java index 2017f1292ce..c88ca4a55ba 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/create/HaFlowCreateFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/create/HaFlowCreateFsm.java @@ -28,10 +28,12 @@ import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; import org.openkilda.wfm.share.flow.resources.HaFlowResources; +import org.openkilda.wfm.share.history.model.HaFlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.HaFlowProcessingFsm; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.ReportErrorAction; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.CreateNewHaFlowHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.NotifyHaFlowMonitorAction; import org.openkilda.wfm.topology.flowhs.fsm.haflow.create.HaFlowCreateFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.haflow.create.HaFlowCreateFsm.State; @@ -185,6 +187,12 @@ public Factory(@NonNull HaFlowGenericCarrier carrier, @NonNull PersistenceManage final ReportErrorAction reportErrorAction = new ReportErrorAction<>(Event.TIMEOUT); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHaFlowHistoryEventAction<>(persistenceManager, HaFlowEventData.Event.CREATE)); + // validate the ha-flow builder.transition() .from(State.INITIALIZED) @@ -340,8 +348,8 @@ public Factory(@NonNull HaFlowGenericCarrier carrier, @NonNull PersistenceManage public HaFlowCreateFsm newInstance(@NonNull CommandContext commandContext, @NonNull String haFlowId, @NonNull Collection eventListeners) { - HaFlowCreateFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, haFlowId, - eventListeners, config); + HaFlowCreateFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + haFlowId, eventListeners, config); fsm.addTransitionCompleteListener(event -> log.debug("HaFlowCreateFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -395,6 +403,7 @@ public static class Config implements Serializable { } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, HA_FLOW_VALIDATED, RESOURCES_ALLOCATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/create/actions/HaFlowValidateAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/create/actions/HaFlowValidateAction.java index b8622ec41a2..65fc52e4250 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/create/actions/HaFlowValidateAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/create/actions/HaFlowValidateAction.java @@ -24,7 +24,6 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.HaFlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -32,7 +31,6 @@ import org.openkilda.wfm.topology.flowhs.fsm.haflow.create.HaFlowCreateFsm; import org.openkilda.wfm.topology.flowhs.fsm.haflow.create.HaFlowCreateFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.haflow.create.HaFlowCreateFsm.State; -import org.openkilda.wfm.topology.flowhs.service.history.FlowHistoryService; import org.openkilda.wfm.topology.flowhs.validation.HaFlowValidator; import org.openkilda.wfm.topology.flowhs.validation.UnavailableFlowEndpointException; @@ -88,12 +86,6 @@ protected Optional performWithResponse( request.getMaximumBandwidth(), request.getPathComputationStrategy(), request.getMaxLatency(), request.getMaxLatencyTier2()); - FlowHistoryService.using(stateMachine.getCarrier()).saveNewHaFlowEvent(HaFlowEventData.builder() - .details("HA-flow has been validated successfully") - .event(HaFlowEventData.Event.CREATE) - .taskId(stateMachine.getCommandContext().getCorrelationId()) - .haFlowId(stateMachine.getHaFlowId()) - .build()); return Optional.empty(); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/delete/HaFlowDeleteFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/delete/HaFlowDeleteFsm.java index 37f9ee1b4fc..629cbd4f943 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/delete/HaFlowDeleteFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/delete/HaFlowDeleteFsm.java @@ -22,10 +22,12 @@ import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; import org.openkilda.wfm.share.flow.resources.HaFlowResources; +import org.openkilda.wfm.share.history.model.HaFlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.HaFlowProcessingFsm; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.ReportErrorAction; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.CreateNewHaFlowHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.NotifyHaFlowMonitorAction; import org.openkilda.wfm.topology.flowhs.fsm.haflow.delete.HaFlowDeleteFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.haflow.delete.HaFlowDeleteFsm.State; @@ -96,6 +98,12 @@ public Factory(@NonNull HaFlowGenericCarrier carrier, @NonNull PersistenceManage final ReportErrorAction reportErrorAction = new ReportErrorAction<>(Event.TIMEOUT); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHaFlowHistoryEventAction<>(persistenceManager, HaFlowEventData.Event.DELETE)); + builder.transition().from(State.INITIALIZED).to(State.HA_FLOW_VALIDATED).on(Event.NEXT) .perform(new ValidateHaFlowAction(persistenceManager, dashboardLogger)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -172,8 +180,8 @@ public Factory(@NonNull HaFlowGenericCarrier carrier, @NonNull PersistenceManage public HaFlowDeleteFsm newInstance(@NonNull CommandContext commandContext, @NonNull String haFlowId, @NonNull Collection eventListeners) { - HaFlowDeleteFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, haFlowId, - eventListeners); + HaFlowDeleteFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + haFlowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("HaFlowDeleteFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -214,6 +222,7 @@ public HaFlowDeleteFsm newInstance(@NonNull CommandContext commandContext, @NonN } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, HA_FLOW_VALIDATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/delete/actions/ValidateHaFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/delete/actions/ValidateHaFlowAction.java index cd8d5592a7a..08806446ae8 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/delete/actions/ValidateHaFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/delete/actions/ValidateHaFlowAction.java @@ -24,7 +24,6 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.HaFlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -58,13 +57,6 @@ protected Optional performWithResponse(State from, State to, Event even String flowId = stateMachine.getFlowId(); dashboardLogger.onHaFlowDelete(flowId); - FlowHistoryService.using(stateMachine.getCarrier()).saveNewHaFlowEvent(HaFlowEventData.builder() - .haFlowId(stateMachine.getHaFlowId()) - .action("HA-flow deletion is invoked") - .taskId(stateMachine.getCommandContext().getCorrelationId()) - .event(HaFlowEventData.Event.DELETE) - .build()); - boolean isOperationAllowed = featureTogglesRepository.getOrDefault().getDeleteHaFlowEnabled(); if (!isOperationAllowed) { throw new FlowProcessingException(ErrorType.NOT_PERMITTED, "HA-flow delete feature is disabled"); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/pathswap/HaFlowPathSwapFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/pathswap/HaFlowPathSwapFsm.java index f4a39bf8656..6ca2958ef0c 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/pathswap/HaFlowPathSwapFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/pathswap/HaFlowPathSwapFsm.java @@ -15,6 +15,8 @@ package org.openkilda.wfm.topology.flowhs.fsm.haflow.pathswap; +import static org.openkilda.wfm.share.history.model.HaFlowEventData.Event.PATH_SWAP; + import org.openkilda.persistence.PersistenceManager; import org.openkilda.rulemanager.RuleManager; import org.openkilda.wfm.CommandContext; @@ -22,6 +24,7 @@ import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.HaFlowPathSwappingFsm; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.ReportErrorAction; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.CreateNewHaFlowHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.HandleNotCompletedCommandsAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.NotifyHaFlowMonitorAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.OnReceivedInstallResponseAction; @@ -94,6 +97,12 @@ public Factory(@NonNull FlowPathSwapHubCarrier carrier, @NonNull PersistenceMana FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHaFlowHistoryEventAction<>(persistenceManager, PATH_SWAP)); + builder.transition().from(State.INITIALIZED).to(State.FLOW_VALIDATED).on(Event.NEXT) .perform(new HaFlowValidateAction(persistenceManager, dashboardLogger)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -189,8 +198,8 @@ public Factory(@NonNull FlowPathSwapHubCarrier carrier, @NonNull PersistenceMana public HaFlowPathSwapFsm newInstance( @NonNull CommandContext commandContext, @NonNull String haFlowId, @NonNull Collection eventListeners) { - HaFlowPathSwapFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, haFlowId, - eventListeners); + HaFlowPathSwapFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + haFlowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("HaFlowPathSwapFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -215,6 +224,7 @@ public HaFlowPathSwapFsm newInstance( } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, FLOW_UPDATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/pathswap/actions/HaFlowValidateAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/pathswap/actions/HaFlowValidateAction.java index 90935beb842..c573c70ba83 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/pathswap/actions/HaFlowValidateAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/pathswap/actions/HaFlowValidateAction.java @@ -25,7 +25,6 @@ import org.openkilda.model.HaFlow; import org.openkilda.model.HaFlowPath; import org.openkilda.persistence.PersistenceManager; -import org.openkilda.wfm.share.history.model.HaFlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -34,6 +33,7 @@ import org.openkilda.wfm.topology.flowhs.fsm.haflow.pathswap.HaFlowPathSwapFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.haflow.pathswap.HaFlowPathSwapFsm.State; import org.openkilda.wfm.topology.flowhs.service.history.FlowHistoryService; +import org.openkilda.wfm.topology.flowhs.service.history.HaFlowHistory; import lombok.extern.slf4j.Slf4j; @@ -80,7 +80,7 @@ protected Optional performWithResponse(State from, State to, Event even saveAndSetInProgressStatuses(haFlow.getProtectedForwardPath(), stateMachine); saveAndSetInProgressStatuses(haFlow.getProtectedReversePath(), stateMachine); }); - saveNewEventToHistory(stateMachine); + saveNewActionToHistory(stateMachine); return Optional.empty(); } @@ -98,12 +98,10 @@ protected String getGenericErrorMessage() { return "Could not swap paths for flow"; } - private void saveNewEventToHistory(HaFlowPathSwapFsm stateMachine) { - FlowHistoryService.using(stateMachine.getCarrier()).saveNewHaFlowEvent(HaFlowEventData.builder() - .action("HA-flow has been validated successfully") - .event(HaFlowEventData.Event.PATH_SWAP) - .haFlowId(stateMachine.getHaFlowId()) - .taskId(stateMachine.getCommandContext().getCorrelationId()) - .build()); + private void saveNewActionToHistory(HaFlowPathSwapFsm stateMachine) { + FlowHistoryService.using(stateMachine.getCarrier()).save( + HaFlowHistory.of(stateMachine.getCommandContext().getCorrelationId()) + .withAction("HA-flow has been validated successfully") + .withHaFlowId(stateMachine.getHaFlowId())); } } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/HaFlowRerouteFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/HaFlowRerouteFsm.java index 60aa4d841d4..0a837ef3dac 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/HaFlowRerouteFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/HaFlowRerouteFsm.java @@ -51,6 +51,7 @@ import org.openkilda.wfm.topology.flowhs.fsm.haflow.reroute.actions.BuildNewRulesAction; import org.openkilda.wfm.topology.flowhs.fsm.haflow.reroute.actions.CompleteFlowPathInstallationAction; import org.openkilda.wfm.topology.flowhs.fsm.haflow.reroute.actions.CompleteFlowPathRemovalAction; +import org.openkilda.wfm.topology.flowhs.fsm.haflow.reroute.actions.CreateNewHaHistoryEventForRerouteAction; import org.openkilda.wfm.topology.flowhs.fsm.haflow.reroute.actions.InstallIngressRulesAction; import org.openkilda.wfm.topology.flowhs.fsm.haflow.reroute.actions.InstallNonIngressRulesAction; import org.openkilda.wfm.topology.flowhs.fsm.haflow.reroute.actions.OnFinishedAction; @@ -159,6 +160,12 @@ public Factory(@NonNull HaFlowRerouteHubCarrier carrier, @NonNull Config config, final ReportErrorAction reportErrorAction = new ReportErrorAction<>(Event.TIMEOUT); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHaHistoryEventForRerouteAction<>(persistenceManager)); + builder.transition().from(State.INITIALIZED).to(State.FLOW_VALIDATED).on(Event.NEXT) .perform(new ValidateHaFlowAction(persistenceManager, dashboardLogger)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -379,8 +386,8 @@ public Factory(@NonNull HaFlowRerouteHubCarrier carrier, @NonNull Config config, public HaFlowRerouteFsm newInstance(@NonNull String flowId, @NonNull CommandContext commandContext, @NonNull Collection eventListeners) { - HaFlowRerouteFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, - eventListeners); + HaFlowRerouteFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + flowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("HaFlowRerouteFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -425,6 +432,7 @@ public HaFlowRerouteFsm newInstance(@NonNull String flowId, @NonNull CommandCont } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, PRIMARY_RESOURCES_ALLOCATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/actions/CreateNewHaHistoryEventForRerouteAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/actions/CreateNewHaHistoryEventForRerouteAction.java new file mode 100644 index 00000000000..fe26e7404eb --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/actions/CreateNewHaHistoryEventForRerouteAction.java @@ -0,0 +1,49 @@ +/* Copyright 2023 Telstra Open Source + * + * 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. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.haflow.reroute.actions; + +import static org.openkilda.wfm.share.history.model.HaFlowEventData.Initiator.AUTO; +import static org.openkilda.wfm.share.history.model.HaFlowEventData.Initiator.NB; + +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.share.history.model.HaFlowEventData; +import org.openkilda.wfm.topology.flowhs.fsm.common.HaFlowPathSwappingFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.HaFlowProcessingWithHistorySupportAction; +import org.openkilda.wfm.topology.flowhs.fsm.haflow.reroute.HaFlowRerouteContext; +import org.openkilda.wfm.topology.flowhs.service.history.FlowHistoryService; + +public class CreateNewHaHistoryEventForRerouteAction + , S, E, C extends HaFlowRerouteContext> + extends HaFlowProcessingWithHistorySupportAction { + + public CreateNewHaHistoryEventForRerouteAction(PersistenceManager persistenceManager) { + super(persistenceManager); + } + + @Override + protected void perform(S from, S to, E event, C context, T stateMachine) { + String rerouteReason = context.getRerouteReason(); + + FlowHistoryService.using(stateMachine.getCarrier()).saveNewHaFlowEvent(HaFlowEventData.builder() + .taskId(stateMachine.getCommandContext().getCorrelationId()) + .event(HaFlowEventData.Event.REROUTE) + .haFlowId(stateMachine.getHaFlowId()) + .action(HaFlowEventData.Event.REROUTE + " operation has been started.") + .initiator(rerouteReason == null ? NB : AUTO) + .details(rerouteReason == null ? null : "Reason: " + rerouteReason) + .build()); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/actions/ValidateHaFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/actions/ValidateHaFlowAction.java index 981a33fb8c2..6536a901cd9 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/actions/ValidateHaFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/reroute/actions/ValidateHaFlowAction.java @@ -17,8 +17,6 @@ import static java.lang.String.format; import static java.util.Collections.emptySet; -import static org.openkilda.wfm.share.history.model.HaFlowEventData.Initiator.AUTO; -import static org.openkilda.wfm.share.history.model.HaFlowEventData.Initiator.NB; import org.openkilda.messaging.Message; import org.openkilda.messaging.error.ErrorType; @@ -35,7 +33,6 @@ import org.openkilda.persistence.repositories.KildaConfigurationRepository; import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.HaFlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.TimedExecution; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; @@ -78,18 +75,7 @@ protected Optional performWithResponse(State from, State to, Event even new HashSet<>(Optional.ofNullable(context.getAffectedIsl()).orElse(emptySet())); dashboardLogger.onHaFlowReroute(flowId, affectedIsl); - String rerouteReason = context.getRerouteReason(); - - FlowHistoryService.using(stateMachine.getCarrier()).saveNewHaFlowEvent(HaFlowEventData.builder() - .taskId(stateMachine.getCommandContext().getCorrelationId()) - .event(HaFlowEventData.Event.REROUTE) - .haFlowId(stateMachine.getHaFlowId()) - .action("Started HA-flow validation") - .initiator(rerouteReason == null ? NB : AUTO) - .details(rerouteReason == null ? null : "Reason: " + rerouteReason) - .build()); - - stateMachine.setRerouteReason(rerouteReason); + stateMachine.setRerouteReason(context.getRerouteReason()); HaFlow haFlow = transactionManager.doInTransaction(() -> { HaFlow foundHaFlow = getHaFlow(flowId); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/sync/HaFlowSyncFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/sync/HaFlowSyncFsm.java index f87c0551eea..a48b9640491 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/sync/HaFlowSyncFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/sync/HaFlowSyncFsm.java @@ -15,6 +15,8 @@ package org.openkilda.wfm.topology.flowhs.fsm.haflow.sync; +import static org.openkilda.wfm.share.history.model.HaFlowEventData.Event.FLOW_SYNC; + import org.openkilda.messaging.Message; import org.openkilda.messaging.error.ErrorData; import org.openkilda.messaging.error.ErrorMessage; @@ -27,6 +29,7 @@ import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.HaFlowProcessingFsm; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.ReportErrorAction; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.CreateNewHaFlowHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.haflow.sync.HaFlowSyncFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.haflow.sync.HaFlowSyncFsm.State; import org.openkilda.wfm.topology.flowhs.fsm.haflow.sync.actions.EmitSyncRuleRequestsAction; @@ -116,6 +119,12 @@ public Factory(@NonNull HaFlowGenericCarrier carrier, @NonNull PersistenceManage final ReportErrorAction reportErrorAction = new ReportErrorAction<>(Event.TIMEOUT); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHaFlowHistoryEventAction<>(persistenceManager, FLOW_SYNC)); + builder.transition() .from(State.INITIALIZED) .to(State.SETUP) @@ -188,8 +197,8 @@ public Factory(@NonNull HaFlowGenericCarrier carrier, @NonNull PersistenceManage public HaFlowSyncFsm newInstance(@NonNull CommandContext commandContext, @NonNull String haFlowId, @NonNull Collection eventListeners) { - HaFlowSyncFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, haFlowId, - eventListeners); + HaFlowSyncFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + haFlowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("HaFlowSyncFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -237,6 +246,7 @@ public static class Config implements Serializable { } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, SETUP, SYNCING_RULES, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/sync/actions/HaFlowSyncSetupAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/sync/actions/HaFlowSyncSetupAction.java index e17823d22e2..91d5eac08d0 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/sync/actions/HaFlowSyncSetupAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/sync/actions/HaFlowSyncSetupAction.java @@ -58,10 +58,6 @@ protected Optional performWithResponse( protected void transaction(HaFlowSyncFsm stateMachine) { HaFlow haFlow = getHaFlow(stateMachine.getHaFlowId()); dashboardLogger.onHaFlowSync(haFlow.getHaFlowId()); - // TODO save history https://github.com/telstra/open-kilda/issues/5169 - // stateMachine.saveNewEventToHistory( - // "Started HA-flow paths sync", FlowEventData.Event.SYNC, FlowEventData.Initiator.NB, - // "Performing HA-flow paths sync operation on NB request"); haFlowValidator.validateHaFlowStatusIsNotInProgress(haFlow); haFlow.setStatus(FlowStatus.IN_PROGRESS); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/update/HaFlowUpdateFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/update/HaFlowUpdateFsm.java index f803229d20f..8c044255d00 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/update/HaFlowUpdateFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/update/HaFlowUpdateFsm.java @@ -22,10 +22,12 @@ import org.openkilda.rulemanager.RuleManager; import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.HaFlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.HaFlowPathSwappingFsm; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.ReportErrorAction; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.CreateNewHaFlowHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.DeallocateResourcesAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.HandleNotCompletedCommandsAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.haflow.HandleNotDeallocatedResourcesAction; @@ -120,6 +122,12 @@ public Factory(@NonNull HaFlowGenericCarrier carrier, @NonNull Config config, final ReportErrorAction reportErrorAction = new ReportErrorAction<>(Event.TIMEOUT); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHaFlowHistoryEventAction<>(persistenceManager, HaFlowEventData.Event.UPDATE)); + builder.transition().from(State.INITIALIZED).to(State.FLOW_VALIDATED).on(Event.NEXT) .perform(new ValidateFlowAction(persistenceManager, dashboardLogger)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -344,8 +352,8 @@ public Factory(@NonNull HaFlowGenericCarrier carrier, @NonNull Config config, public HaFlowUpdateFsm newInstance( @NonNull String flowId, @NonNull CommandContext commandContext, @NonNull Collection eventListeners) { - HaFlowUpdateFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, - eventListeners); + HaFlowUpdateFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + flowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("HaFlowUpdateFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -370,6 +378,7 @@ public HaFlowUpdateFsm newInstance( } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, FLOW_UPDATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/update/actions/ValidateFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/update/actions/ValidateFlowAction.java index 71bda7c998f..e3a60961d9f 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/update/actions/ValidateFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/haflow/update/actions/ValidateFlowAction.java @@ -28,7 +28,6 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.HaFlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -118,7 +117,7 @@ protected Optional performWithResponse( stateMachine.saveOldPathIds(stateMachine.getOriginalHaFlow()); - saveNewHistoryEventWithDump(stateMachine, haFlow); + saveHistoryActionWithDump(stateMachine, haFlow); return Optional.empty(); } @@ -136,17 +135,8 @@ protected void handleError(HaFlowUpdateFsm stateMachine, Exception ex, ErrorType stateMachine.notifyEventListenersOnError(errorType, stateMachine.getErrorReason()); } - private void saveNewHistoryEventWithDump(HaFlowUpdateFsm stateMachine, HaFlow haFlow) { - FlowHistoryService flowHistoryService = FlowHistoryService.using(stateMachine.getCarrier()); - - flowHistoryService.saveNewHaFlowEvent(HaFlowEventData.builder() - .action("HA-flow has been validated successfully") - .event(HaFlowEventData.Event.UPDATE) - .taskId(stateMachine.getCommandContext().getCorrelationId()) - .haFlowId(stateMachine.getHaFlowId()) - .build()); - - flowHistoryService.save(HaFlowHistory + private void saveHistoryActionWithDump(HaFlowUpdateFsm stateMachine, HaFlow haFlow) { + FlowHistoryService.using(stateMachine.getCarrier()).save(HaFlowHistory .of(stateMachine.getCommandContext().getCorrelationId()) .withHaFlowId(haFlow.getHaFlowId()) .withAction("HA-flow has been validated successfully") diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/create/FlowMirrorPointCreateFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/create/FlowMirrorPointCreateFsm.java index 71b6f3c6433..d0471226e52 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/create/FlowMirrorPointCreateFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/create/FlowMirrorPointCreateFsm.java @@ -24,8 +24,10 @@ import org.openkilda.rulemanager.SpeakerData; import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.fsm.common.FlowProcessingWithSpeakerCommandsFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.mirrorpoint.create.FlowMirrorPointCreateFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.mirrorpoint.create.FlowMirrorPointCreateFsm.State; import org.openkilda.wfm.topology.flowhs.fsm.mirrorpoint.create.actions.EmitRemoveRulesRequestsAction; @@ -101,6 +103,13 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager String.class); FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, + FlowEventData.Event.FLOW_MIRROR_POINT_CREATE)); + builder.transition().from(State.INITIALIZED).to(State.FLOW_VALIDATED).on(Event.NEXT) .perform(new ValidateRequestAction(persistenceManager, dashboardLogger)); @@ -188,11 +197,12 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager } public FlowMirrorPointCreateFsm newInstance(@NonNull CommandContext commandContext, @NonNull String flowId) { - return builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId); + return builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, flowId); } } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, ALLOCATING_RESOURCES, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/create/actions/ValidateRequestAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/create/actions/ValidateRequestAction.java index d7d7dbe764d..692b832131c 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/create/actions/ValidateRequestAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/create/actions/ValidateRequestAction.java @@ -27,7 +27,6 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.FlowMirrorPathRepository; import org.openkilda.persistence.repositories.PhysicalPortRepository; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -122,8 +121,7 @@ protected Optional performWithResponse(State from, State to, Event even throw new FlowProcessingException(ErrorType.DATA_INVALID, e.getMessage(), e); } - stateMachine.saveNewEventToHistory("Flow was validated successfully", - FlowEventData.Event.FLOW_MIRROR_POINT_CREATE); + stateMachine.saveActionToHistory("Flow was validated successfully"); return Optional.empty(); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/delete/FlowMirrorPointDeleteFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/delete/FlowMirrorPointDeleteFsm.java index afeee19312e..4c898a54936 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/delete/FlowMirrorPointDeleteFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/delete/FlowMirrorPointDeleteFsm.java @@ -24,8 +24,10 @@ import org.openkilda.rulemanager.SpeakerData; import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.fsm.common.FlowProcessingWithSpeakerCommandsFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.mirrorpoint.delete.FlowMirrorPointDeleteFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.mirrorpoint.delete.FlowMirrorPointDeleteFsm.State; import org.openkilda.wfm.topology.flowhs.fsm.mirrorpoint.delete.actions.DeallocateFlowMirrorPathResourcesAction; @@ -93,6 +95,13 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, + FlowEventData.Event.FLOW_MIRROR_POINT_DELETE)); + builder.transition().from(State.INITIALIZED).to(State.FLOW_VALIDATED).on(Event.NEXT) .perform(new ValidateRequestAction(persistenceManager, dashboardLogger)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -150,11 +159,12 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager } public FlowMirrorPointDeleteFsm newInstance(@NonNull CommandContext commandContext, @NonNull String flowId) { - return builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId); + return builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, flowId); } } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/delete/actions/ValidateRequestAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/delete/actions/ValidateRequestAction.java index 7812c515f68..da5f2a7c70f 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/delete/actions/ValidateRequestAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/mirrorpoint/delete/actions/ValidateRequestAction.java @@ -31,7 +31,6 @@ import org.openkilda.persistence.repositories.FlowMirrorPathRepository; import org.openkilda.persistence.repositories.RepositoryFactory; import org.openkilda.wfm.CommandContext; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -103,8 +102,7 @@ protected Optional performWithResponse(State from, State to, Event even .build(); }); - stateMachine.saveNewEventToHistory("Flow was validated successfully", - FlowEventData.Event.FLOW_MIRROR_POINT_DELETE); + stateMachine.saveActionToHistory("Flow was validated successfully"); CommandContext commandContext = stateMachine.getCommandContext(); return Optional.of(new InfoMessage(response, commandContext.getCreateTime(), diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/pathswap/FlowPathSwapFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/pathswap/FlowPathSwapFsm.java index c7477a9846c..54f7a3f25a5 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/pathswap/FlowPathSwapFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/pathswap/FlowPathSwapFsm.java @@ -22,9 +22,11 @@ import org.openkilda.rulemanager.RuleManager; import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.FlowPathSwappingFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NotifyFlowMonitorAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.ReportErrorAction; import org.openkilda.wfm.topology.flowhs.fsm.pathswap.FlowPathSwapFsm.Event; @@ -123,6 +125,12 @@ public Factory(@NonNull FlowPathSwapHubCarrier carrier, @NonNull PersistenceMana FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, FlowEventData.Event.PATH_SWAP)); + builder.transition().from(State.INITIALIZED).to(State.FLOW_VALIDATED).on(Event.NEXT) .perform(new FlowValidateAction(persistenceManager, dashboardLogger)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -229,8 +237,8 @@ public Factory(@NonNull FlowPathSwapHubCarrier carrier, @NonNull PersistenceMana public FlowPathSwapFsm newInstance(@NonNull CommandContext commandContext, @NonNull String flowId, @NonNull Collection eventListeners) { - FlowPathSwapFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, - eventListeners); + FlowPathSwapFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + flowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("FlowPathSwapFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -271,6 +279,7 @@ public FlowPathSwapFsm newInstance(@NonNull CommandContext commandContext, @NonN } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, FLOW_UPDATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/pathswap/actions/FlowValidateAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/pathswap/actions/FlowValidateAction.java index 82a5aba531a..4102191b595 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/pathswap/actions/FlowValidateAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/pathswap/actions/FlowValidateAction.java @@ -25,7 +25,6 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.FlowRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -92,7 +91,7 @@ protected Optional performWithResponse(State from, State to, Event even flow.getProtectedReversePath().setStatus(FlowPathStatus.IN_PROGRESS); }); - stateMachine.saveNewEventToHistory("Flow was validated successfully", FlowEventData.Event.PATH_SWAP); + stateMachine.saveActionToHistory("Flow was validated successfully"); return Optional.empty(); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/FlowRerouteFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/FlowRerouteFsm.java index 2366851f8b7..fa85055d23d 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/FlowRerouteFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/FlowRerouteFsm.java @@ -15,6 +15,8 @@ package org.openkilda.wfm.topology.flowhs.fsm.reroute; +import static org.openkilda.wfm.share.history.model.FlowEventData.Event.REROUTE; + import org.openkilda.messaging.Message; import org.openkilda.messaging.error.ErrorData; import org.openkilda.messaging.error.ErrorMessage; @@ -42,6 +44,7 @@ import org.openkilda.wfm.topology.flowhs.fsm.reroute.actions.AllocateProtectedResourcesAction; import org.openkilda.wfm.topology.flowhs.fsm.reroute.actions.CompleteFlowPathInstallationAction; import org.openkilda.wfm.topology.flowhs.fsm.reroute.actions.CompleteFlowPathRemovalAction; +import org.openkilda.wfm.topology.flowhs.fsm.reroute.actions.CreateNewHistoryEventForRerouteAction; import org.openkilda.wfm.topology.flowhs.fsm.reroute.actions.DeallocateResourcesAction; import org.openkilda.wfm.topology.flowhs.fsm.reroute.actions.EmitIngressRulesVerifyRequestsAction; import org.openkilda.wfm.topology.flowhs.fsm.reroute.actions.EmitNonIngressRulesVerifyRequestsAction; @@ -173,6 +176,12 @@ public Factory(@NonNull FlowRerouteHubCarrier carrier, @NonNull Config config, final ReportErrorAction reportErrorAction = new ReportErrorAction<>(Event.TIMEOUT); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventForRerouteAction<>(persistenceManager, REROUTE)); + builder.transition().from(State.INITIALIZED).to(State.FLOW_VALIDATED).on(Event.NEXT) .perform(new ValidateFlowAction(persistenceManager, dashboardLogger)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -424,8 +433,8 @@ public Factory(@NonNull FlowRerouteHubCarrier carrier, @NonNull Config config, public FlowRerouteFsm newInstance(@NonNull String flowId, @NonNull CommandContext commandContext, @NonNull Collection eventListeners) { - FlowRerouteFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, - eventListeners); + FlowRerouteFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + flowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("FlowRerouteFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -480,6 +489,7 @@ private ErrorType extractErrorType(FlowRerouteFsm fsm) { } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, PRIMARY_RESOURCES_ALLOCATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/actions/CreateNewHistoryEventForRerouteAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/actions/CreateNewHistoryEventForRerouteAction.java new file mode 100644 index 00000000000..50d4a7e32be --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/actions/CreateNewHistoryEventForRerouteAction.java @@ -0,0 +1,53 @@ +/* Copyright 2023 Telstra Open Source + * + * 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. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.reroute.actions; + +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.share.history.model.FlowEventData; +import org.openkilda.wfm.topology.flowhs.fsm.common.FlowProcessingWithHistorySupportFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.FlowProcessingWithHistorySupportAction; +import org.openkilda.wfm.topology.flowhs.fsm.reroute.FlowRerouteContext; + +public class CreateNewHistoryEventForRerouteAction + , S, E, C extends FlowRerouteContext> + extends FlowProcessingWithHistorySupportAction { + private final FlowEventData.Event historyEvent; + private final String actionTitle; + + public CreateNewHistoryEventForRerouteAction(PersistenceManager persistenceManager, + FlowEventData.Event historyEvent) { + super(persistenceManager); + this.historyEvent = historyEvent; + this.actionTitle = historyEvent.getDescription() + " operation has been started."; + } + + public CreateNewHistoryEventForRerouteAction(PersistenceManager persistenceManager, + FlowEventData.Event historyEvent, + String actionTitle) { + super(persistenceManager); + this.historyEvent = historyEvent; + this.actionTitle = actionTitle; + } + + @Override + protected void perform(S from, S to, E event, C context, T stateMachine) { + String rerouteReason = context.getRerouteReason(); + + stateMachine.saveNewEventToHistory(actionTitle, FlowEventData.Event.REROUTE, + rerouteReason == null ? FlowEventData.Initiator.NB : FlowEventData.Initiator.AUTO, + rerouteReason == null ? null : "Reason: " + rerouteReason); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/actions/ValidateFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/actions/ValidateFlowAction.java index 037ec78f79b..9afd15cf16b 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/actions/ValidateFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/reroute/actions/ValidateFlowAction.java @@ -31,7 +31,6 @@ import org.openkilda.persistence.repositories.KildaConfigurationRepository; import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.TimedExecution; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; @@ -73,11 +72,7 @@ protected Optional performWithResponse(State from, State to, Event even new HashSet<>(Optional.ofNullable(context.getAffectedIsl()).orElse(emptySet())); dashboardLogger.onFlowPathReroute(flowId, affectedIsl); - String rerouteReason = context.getRerouteReason(); - stateMachine.saveNewEventToHistory("Started flow validation", FlowEventData.Event.REROUTE, - rerouteReason == null ? FlowEventData.Initiator.NB : FlowEventData.Initiator.AUTO, - rerouteReason == null ? null : "Reason: " + rerouteReason); - stateMachine.setRerouteReason(rerouteReason); + stateMachine.setRerouteReason(context.getRerouteReason()); Flow flow = transactionManager.doInTransaction(() -> { Flow foundFlow = getFlow(flowId); diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/FlowSwapEndpointsFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/FlowSwapEndpointsFsm.java index 80460c47ea2..095b74c9ea3 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/FlowSwapEndpointsFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/FlowSwapEndpointsFsm.java @@ -28,6 +28,7 @@ import org.openkilda.wfm.topology.flowhs.fsm.common.FlowProcessingWithHistorySupportFsm; import org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.FlowSwapEndpointsFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.FlowSwapEndpointsFsm.State; +import org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.actions.CreateNewHistoryEventForSwapEndpointsAction; import org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.actions.OnFinishedAction; import org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.actions.OnFinishedWithErrorAction; import org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.actions.OnReceivedUpdateResponseAction; @@ -151,6 +152,12 @@ public Factory(@NonNull FlowSwapEndpointsHubCarrier carrier, @NonNull Persistenc FlowSwapEndpointsContext.class, CommandContext.class, FlowSwapEndpointsHubCarrier.class, RequestedFlow.class, RequestedFlow.class); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventForSwapEndpointsAction(persistenceManager)); + builder.transition().from(State.INITIALIZED).to(State.FLOWS_VALIDATED).on(Event.NEXT) .perform(new ValidateFlowsAction(persistenceManager)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -195,12 +202,13 @@ public Factory(@NonNull FlowSwapEndpointsHubCarrier carrier, @NonNull Persistenc public FlowSwapEndpointsFsm newInstance(@NonNull CommandContext commandContext, @NonNull RequestedFlow firstTargetFlow, @NonNull RequestedFlow secondTargetFlow) { - return builder.newStateMachine(FlowSwapEndpointsFsm.State.INITIALIZED, commandContext, carrier, + return builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, firstTargetFlow, secondTargetFlow); } } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOWS_VALIDATED, SEND_UPDATE_REQUESTS, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/actions/CreateNewHistoryEventForSwapEndpointsAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/actions/CreateNewHistoryEventForSwapEndpointsAction.java new file mode 100644 index 00000000000..770479efb9f --- /dev/null +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/actions/CreateNewHistoryEventForSwapEndpointsAction.java @@ -0,0 +1,46 @@ +/* Copyright 2023 Telstra Open Source + * + * 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. + */ + +package org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.actions; + +import org.openkilda.persistence.PersistenceManager; +import org.openkilda.wfm.share.history.model.FlowEventData; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.FlowProcessingWithHistorySupportAction; +import org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.FlowSwapEndpointsContext; +import org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.FlowSwapEndpointsFsm; + +public class CreateNewHistoryEventForSwapEndpointsAction extends FlowProcessingWithHistorySupportAction + { + + public CreateNewHistoryEventForSwapEndpointsAction(PersistenceManager persistenceManager) { + super(persistenceManager); + } + + @Override + protected void perform(FlowSwapEndpointsFsm.State from, + FlowSwapEndpointsFsm.State to, + FlowSwapEndpointsFsm.Event event, + FlowSwapEndpointsContext context, + FlowSwapEndpointsFsm stateMachine) { + stateMachine.saveNewEventToHistory(stateMachine.getFirstFlowId(), + "Swap end points operation has been started.", + FlowEventData.Event.SWAP_ENDPOINTS); + stateMachine.saveNewEventToHistory(stateMachine.getSecondFlowId(), + "Swap end points operation has been started.", + FlowEventData.Event.SWAP_ENDPOINTS); + + stateMachine.fireNext(); + } +} diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/actions/ValidateFlowsAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/actions/ValidateFlowsAction.java index 476f9ad508c..0273aa69154 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/actions/ValidateFlowsAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/swapendpoints/actions/ValidateFlowsAction.java @@ -25,7 +25,6 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.FlowProcessingWithHistorySupportAction; import org.openkilda.wfm.topology.flowhs.fsm.swapendpoints.FlowSwapEndpointsContext; @@ -92,12 +91,10 @@ protected void perform(State from, State to, Event event, FlowSwapEndpointsConte return; } - stateMachine.saveNewEventToHistory(stateMachine.getFirstFlowId(), - format("Current flow and flow %s were validated successfully", stateMachine.getSecondFlowId()), - FlowEventData.Event.SWAP_ENDPOINTS); - stateMachine.saveNewEventToHistory(stateMachine.getSecondFlowId(), - format("Current flow and flow %s were validated successfully", stateMachine.getFirstFlowId()), - FlowEventData.Event.SWAP_ENDPOINTS); + stateMachine.saveActionToHistory(stateMachine.getFirstFlowId(), + format("Current flow and flow %s were validated successfully", stateMachine.getSecondFlowId())); + stateMachine.saveActionToHistory(stateMachine.getSecondFlowId(), + format("Current flow and flow %s were validated successfully", stateMachine.getFirstFlowId())); stateMachine.fireNext(); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/update/FlowUpdateFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/update/FlowUpdateFsm.java index b7cd832d87f..40e53a52d6b 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/update/FlowUpdateFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/update/FlowUpdateFsm.java @@ -25,9 +25,11 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.FlowPathSwappingFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NotifyFlowMonitorAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NotifyFlowStatsOnNewPathsAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NotifyFlowStatsOnRemovedPathsAction; @@ -146,6 +148,12 @@ public Factory(@NonNull FlowUpdateHubCarrier carrier, @NonNull Config config, final ReportErrorAction reportErrorAction = new ReportErrorAction<>(Event.TIMEOUT); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, FlowEventData.Event.UPDATE)); + builder.transition().from(State.INITIALIZED).to(State.FLOW_VALIDATED).on(Event.NEXT) .perform(new ValidateFlowAction(persistenceManager, dashboardLogger)); builder.transition().from(State.INITIALIZED).to(State.FINISHED_WITH_ERROR).on(Event.TIMEOUT); @@ -409,7 +417,7 @@ public Factory(@NonNull FlowUpdateHubCarrier carrier, @NonNull Config config, public FlowUpdateFsm newInstance(@NonNull String flowId, @NonNull CommandContext commandContext, @NonNull Collection eventListeners) { - FlowUpdateFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, + FlowUpdateFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, flowId, eventListeners); fsm.addTransitionCompleteListener(event -> @@ -478,6 +486,7 @@ public enum FlowLoopOperation { } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, FLOW_VALIDATED, FLOW_UPDATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/YFlowCreateFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/YFlowCreateFsm.java index 141e4d68e54..6e22896a6a7 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/YFlowCreateFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/YFlowCreateFsm.java @@ -21,10 +21,12 @@ import org.openkilda.rulemanager.RuleManager; import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.YFlowProcessingFsm; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.AllocateYFlowResourcesAction; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.yflow.create.YFlowCreateFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.yflow.create.YFlowCreateFsm.State; import org.openkilda.wfm.topology.flowhs.fsm.yflow.create.actions.CompleteYFlowCreatingAction; @@ -161,6 +163,12 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, FlowEventData.Event.CREATE)); + builder.transition() .from(State.INITIALIZED) .to(State.YFLOW_VALIDATED) @@ -359,8 +367,8 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager public YFlowCreateFsm newInstance(@NonNull CommandContext commandContext, @NonNull String yFlowId, @NonNull Collection eventListeners) { - YFlowCreateFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, yFlowId, - eventListeners); + YFlowCreateFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + yFlowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("YFlowCreateFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -385,6 +393,7 @@ public YFlowCreateFsm newInstance(@NonNull CommandContext commandContext, @NonNu } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, YFLOW_VALIDATED, DRAFT_YFLOW_CREATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/actions/ValidateYFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/actions/ValidateYFlowAction.java index aef589f9e6f..c0f4bd6b11f 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/actions/ValidateYFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/create/actions/ValidateYFlowAction.java @@ -24,7 +24,6 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -85,7 +84,7 @@ protected Optional performWithResponse(State from, State to, Event even targetFlow.getMaximumBandwidth(), targetFlow.getPathComputationStrategy(), targetFlow.getMaxLatency(), targetFlow.getMaxLatencyTier2()); - stateMachine.saveNewEventToHistory("Y-flow was validated successfully", FlowEventData.Event.CREATE); + stateMachine.saveActionToHistory("Y-flow was validated successfully"); return Optional.empty(); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/delete/YFlowDeleteFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/delete/YFlowDeleteFsm.java index 9c397f75cd7..956539fcf96 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/delete/YFlowDeleteFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/delete/YFlowDeleteFsm.java @@ -21,9 +21,11 @@ import org.openkilda.rulemanager.RuleManager; import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.YFlowProcessingFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.RevertYFlowStatusAction; import org.openkilda.wfm.topology.flowhs.fsm.yflow.delete.YFlowDeleteFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.yflow.delete.YFlowDeleteFsm.State; @@ -126,6 +128,13 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, FlowEventData.Event.DELETE)); + + builder.transition() .from(State.INITIALIZED) .to(State.YFLOW_VALIDATED) @@ -219,8 +228,8 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager public YFlowDeleteFsm newInstance(@NonNull CommandContext commandContext, @NonNull String yFlowId, @NonNull Collection eventListeners) { - YFlowDeleteFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, yFlowId, - eventListeners); + YFlowDeleteFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + yFlowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("YFlowDeleteFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -245,6 +254,7 @@ public YFlowDeleteFsm newInstance(@NonNull CommandContext commandContext, @NonNu } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, YFLOW_VALIDATED, YFLOW_DELETE_STARTED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/delete/actions/ValidateYFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/delete/actions/ValidateYFlowAction.java index b6c6ea32cae..defb604d1e8 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/delete/actions/ValidateYFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/delete/actions/ValidateYFlowAction.java @@ -28,7 +28,6 @@ import org.openkilda.persistence.repositories.RepositoryFactory; import org.openkilda.persistence.repositories.YFlowRepository; import org.openkilda.wfm.CommandContext; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -84,7 +83,7 @@ protected Optional performWithResponse(State from, State to, Event even return yFlow; }); - stateMachine.saveNewEventToHistory("Y-flow was validated successfully", FlowEventData.Event.DELETE); + stateMachine.saveActionToHistory("Y-flow was validated successfully"); return Optional.of(buildResponseMessage(result, stateMachine.getCommandContext())); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/pathswap/YFlowPathSwapFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/pathswap/YFlowPathSwapFsm.java index 0220f4e33a5..7df33afb9ce 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/pathswap/YFlowPathSwapFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/pathswap/YFlowPathSwapFsm.java @@ -22,9 +22,11 @@ import org.openkilda.persistence.PersistenceManager; import org.openkilda.rulemanager.RuleManager; import org.openkilda.wfm.CommandContext; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.YFlowProcessingFsm; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.yflow.pathswap.YFlowPathSwapFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.yflow.pathswap.YFlowPathSwapFsm.State; import org.openkilda.wfm.topology.flowhs.fsm.yflow.pathswap.actions.CompleteYFlowSwappingAction; @@ -160,6 +162,12 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, FlowEventData.Event.PATH_SWAP)); + builder.transition() .from(State.INITIALIZED) .to(State.YFLOW_VALIDATED) @@ -318,8 +326,8 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager public YFlowPathSwapFsm newInstance(@NonNull CommandContext commandContext, @NonNull String flowId, @NonNull Collection eventListeners) { - YFlowPathSwapFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, - eventListeners); + YFlowPathSwapFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + flowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("YFlowPathSwapFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -344,6 +352,7 @@ public YFlowPathSwapFsm newInstance(@NonNull CommandContext commandContext, @Non } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, YFLOW_VALIDATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/pathswap/actions/ValidateYFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/pathswap/actions/ValidateYFlowAction.java index 21ab3ead66d..19994edac7a 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/pathswap/actions/ValidateYFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/pathswap/actions/ValidateYFlowAction.java @@ -29,7 +29,6 @@ import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; import org.openkilda.persistence.repositories.YFlowRepository; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -134,7 +133,7 @@ protected Optional performWithResponse(State from, State to, Event even dashboardLogger.onYFlowPathsSwap(yFlowId); - stateMachine.saveNewEventToHistory("Y-flow was validated successfully", FlowEventData.Event.PATH_SWAP); + stateMachine.saveActionToHistory("Y-flow was validated successfully"); return Optional.empty(); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/YFlowRerouteFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/YFlowRerouteFsm.java index ef0d5325340..d16bcecb804 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/YFlowRerouteFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/YFlowRerouteFsm.java @@ -27,10 +27,12 @@ import org.openkilda.rulemanager.RuleManager; import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.YFlowProcessingFsm; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.AllocateYFlowResourcesAction; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.RevertYFlowStatusAction; import org.openkilda.wfm.topology.flowhs.fsm.yflow.reroute.YFlowRerouteFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.yflow.reroute.YFlowRerouteFsm.State; @@ -172,6 +174,12 @@ public Factory(@NonNull YFlowRerouteHubCarrier carrier, @NonNull PersistenceMana FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, FlowEventData.Event.REROUTE)); + builder.transition() .from(State.INITIALIZED) .to(State.YFLOW_VALIDATED) @@ -353,8 +361,8 @@ public Factory(@NonNull YFlowRerouteHubCarrier carrier, @NonNull PersistenceMana public YFlowRerouteFsm newInstance(@NonNull CommandContext commandContext, @NonNull String flowId, @NonNull Collection eventListeners) { - YFlowRerouteFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, - eventListeners); + YFlowRerouteFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + flowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("YFlowRerouteFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -379,6 +387,7 @@ public YFlowRerouteFsm newInstance(@NonNull CommandContext commandContext, @NonN } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, YFLOW_VALIDATED, YFLOW_REROUTE_STARTED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/ValidateYFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/ValidateYFlowAction.java index 21f81c4c6ce..33e12da2fc6 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/ValidateYFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/reroute/actions/ValidateYFlowAction.java @@ -33,7 +33,6 @@ import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; import org.openkilda.persistence.repositories.YFlowRepository; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -142,10 +141,9 @@ protected Optional performWithResponse(State from, State to, Event even }); if (yFlow != null) { - stateMachine.saveNewEventToHistory("Y-flow was validated successfully", FlowEventData.Event.REROUTE); + stateMachine.saveActionToHistory("Y-flow was validated successfully"); } else { - stateMachine.saveNewEventToHistory("Y-flow was validated, no sub-flows to be rerouted", - FlowEventData.Event.REROUTE); + stateMachine.saveActionToHistory("Y-flow was validated, no sub-flows to be rerouted"); stateMachine.fire(Event.YFLOW_REROUTE_SKIPPED); } diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/update/YFlowUpdateFsm.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/update/YFlowUpdateFsm.java index cb6eb069e04..5f0817facea 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/update/YFlowUpdateFsm.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/update/YFlowUpdateFsm.java @@ -22,10 +22,12 @@ import org.openkilda.rulemanager.RuleManager; import org.openkilda.wfm.CommandContext; import org.openkilda.wfm.share.flow.resources.FlowResourcesManager; +import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.share.metrics.MeterRegistryHolder; import org.openkilda.wfm.topology.flowhs.fsm.common.YFlowProcessingFsm; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.AllocateYFlowResourcesAction; +import org.openkilda.wfm.topology.flowhs.fsm.common.actions.CreateNewHistoryEventAction; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.RevertYFlowStatusAction; import org.openkilda.wfm.topology.flowhs.fsm.yflow.update.YFlowUpdateFsm.Event; import org.openkilda.wfm.topology.flowhs.fsm.yflow.update.YFlowUpdateFsm.State; @@ -163,6 +165,11 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager Collection.class); FlowOperationsDashboardLogger dashboardLogger = new FlowOperationsDashboardLogger(log); + builder.transition() + .from(State.CREATE_NEW_HISTORY_EVENT) + .to(State.INITIALIZED) + .on(Event.NEXT) + .perform(new CreateNewHistoryEventAction<>(persistenceManager, FlowEventData.Event.UPDATE)); builder.transition() .from(State.INITIALIZED) @@ -453,8 +460,8 @@ public Factory(@NonNull FlowGenericCarrier carrier, @NonNull PersistenceManager public YFlowUpdateFsm newInstance(@NonNull CommandContext commandContext, @NonNull String flowId, @NonNull Collection eventListeners) { - YFlowUpdateFsm fsm = builder.newStateMachine(State.INITIALIZED, commandContext, carrier, flowId, - eventListeners); + YFlowUpdateFsm fsm = builder.newStateMachine(State.CREATE_NEW_HISTORY_EVENT, commandContext, carrier, + flowId, eventListeners); fsm.addTransitionCompleteListener(event -> log.debug("YFlowUpdateFsm, transition to {} on {}", event.getTargetState(), event.getCause())); @@ -479,6 +486,7 @@ public YFlowUpdateFsm newInstance(@NonNull CommandContext commandContext, @NonNu } public enum State { + CREATE_NEW_HISTORY_EVENT, INITIALIZED, YFLOW_VALIDATED, YFLOW_UPDATED, diff --git a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/update/actions/ValidateYFlowAction.java b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/update/actions/ValidateYFlowAction.java index 5ca63fe4839..a1b11c98191 100644 --- a/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/update/actions/ValidateYFlowAction.java +++ b/src-java/flowhs-topology/flowhs-storm-topology/src/main/java/org/openkilda/wfm/topology/flowhs/fsm/yflow/update/actions/ValidateYFlowAction.java @@ -31,7 +31,6 @@ import org.openkilda.persistence.repositories.KildaFeatureTogglesRepository; import org.openkilda.persistence.repositories.RepositoryFactory; import org.openkilda.persistence.repositories.YFlowRepository; -import org.openkilda.wfm.share.history.model.FlowEventData; import org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger; import org.openkilda.wfm.topology.flowhs.exception.FlowProcessingException; import org.openkilda.wfm.topology.flowhs.fsm.common.actions.NbTrackableWithHistorySupportAction; @@ -138,7 +137,7 @@ protected Optional performWithResponse(State from, State to, Event even stateMachine.setTargetFlow(targetFlow); - stateMachine.saveNewEventToHistory("Y-flow was validated successfully", FlowEventData.Event.UPDATE); + stateMachine.saveActionToHistory("Y-flow was validated successfully"); return Optional.empty(); } diff --git a/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/FlowHelperV2.groovy b/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/FlowHelperV2.groovy index 9c152f370d5..4bb89104b2a 100644 --- a/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/FlowHelperV2.groovy +++ b/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/FlowHelperV2.groovy @@ -163,7 +163,7 @@ class FlowHelperV2 { Wrappers.wait(FLOW_CRUD_TIMEOUT) { assert northboundV2.getFlowStatus(flow.flowId).status == expectedFlowState if (expectedFlowState != IN_PROGRESS) { - assert northbound.getFlowHistory(flow.flowId).last().payload.last().action == CREATE_SUCCESS + assert northbound.getFlowHistory(flow.flowId).any {it.payload.last().action == CREATE_SUCCESS} } } return response diff --git a/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/YFlowHelper.groovy b/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/YFlowHelper.groovy index 23ecc9f6b60..29bbaf5ae0a 100644 --- a/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/YFlowHelper.groovy +++ b/src-java/testing/functional-tests/src/main/groovy/org/openkilda/functionaltests/helpers/YFlowHelper.groovy @@ -73,7 +73,7 @@ class YFlowHelper { .portNumber(randomEndpointPort(sharedSwitch, useTraffgenPorts, busyEndpoints)) .build() def subFlows = [firstSwitch, secondSwitch].collect {sw -> - def seVlan = randomVlan() + def seVlan = randomVlan(busyEndpoints*.vlan) busyEndpoints << new SwitchPortVlan(se.switchId, se.portNumber, seVlan) def ep = SubFlowUpdatePayload.builder() .sharedEndpoint(YFlowSharedEndpointEncapsulation.builder().vlanId(seVlan).build()) @@ -117,11 +117,11 @@ class YFlowHelper { def subFlows = (0..1).collect { def payload = Wrappers.retry(3, 0) { - def seVlan = randomVlan() + def seVlan = randomVlan(busyEndpoints*.vlan) if (busyEndpoints.contains(new SwitchPortVlan(sw.dpId, sePort, seVlan))) { throw new Exception("Generated sub-flow conflicts with existing endpoints.") } - def epVlan = randomVlan(); + def epVlan = randomVlan(busyEndpoints*.vlan); if (busyEndpoints.contains(new SwitchPortVlan(sw.dpId, epPort, epVlan))) { throw new Exception("Generated sub-flow conflicts with existing endpoints.") } @@ -264,7 +264,7 @@ class YFlowHelper { */ private FlowEndpointV2 randomEndpoint(Switch sw, boolean useTraffgenPorts = true, List busyEps) { return new FlowEndpointV2( - sw.dpId, randomEndpointPort(sw, useTraffgenPorts, busyEps), randomVlan(), + sw.dpId, randomEndpointPort(sw, useTraffgenPorts, busyEps), randomVlan(busyEps*.vlan), new DetectConnectedDevicesV2(false, false)) } @@ -291,8 +291,8 @@ class YFlowHelper { return port } - private int randomVlan() { - return KILDA_ALLOWED_VLANS.shuffled().first() + private int randomVlan(List busyVlans = []) { + return (KILDA_ALLOWED_VLANS - busyVlans).shuffled().first() } private String generateDescription() { diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/SwapEndpointSpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/SwapEndpointSpec.groovy index f55a59d2798..2edc89c70e0 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/SwapEndpointSpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/SwapEndpointSpec.groovy @@ -52,7 +52,7 @@ class SwapEndpointSpec extends HealthCheckSpecification { given: "Some flows in the system according to preconditions" flows.each { flowHelper.addFlow(it) } - when: "Try to swap endpoints with #data.descirption" + when: "Try to swap endpoints with #data.description" def response = northbound.swapFlowEndpoint(firstSwap, secondSwap) then: "Endpoints are successfully swapped" diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/VxlanFlowSpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/VxlanFlowSpec.groovy index 4b03903570f..3a23aa8d862 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/VxlanFlowSpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/flows/VxlanFlowSpec.groovy @@ -140,10 +140,12 @@ class VxlanFlowSpec extends HealthCheckSpecification { northbound.validateFlow(flow.flowId).each { direction -> assert direction.asExpected } } - and: "Flow is pingable" - verifyAll(northbound.pingFlow(flow.flowId, new PingInput())) { - forward.pingSuccess - reverse.pingSuccess + and: "Flow is pingable (though sometimes we have to wait)" + Wrappers.wait(WAIT_OFFSET) { + verifyAll(northbound.pingFlow(flow.flowId, new PingInput())) { + forward.pingSuccess + reverse.pingSuccess + } } and: "Rules are recreated" diff --git a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/server42/Server42FlowRttSpec.groovy b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/server42/Server42FlowRttSpec.groovy index 885318b7ba1..3a855c8dfb4 100644 --- a/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/server42/Server42FlowRttSpec.groovy +++ b/src-java/testing/functional-tests/src/test/groovy/org/openkilda/functionaltests/spec/server42/Server42FlowRttSpec.groovy @@ -1,9 +1,5 @@ package org.openkilda.functionaltests.spec.server42 -import org.openkilda.functionaltests.model.stats.FlowStats -import org.openkilda.functionaltests.model.stats.Origin -import org.springframework.beans.factory.annotation.Autowired - import static groovyx.gpars.GParsPool.withPool import static java.util.concurrent.TimeUnit.SECONDS import static org.assertj.core.api.Assertions.assertThat @@ -22,6 +18,7 @@ import static org.openkilda.model.cookie.Cookie.SERVER_42_FLOW_RTT_OUTPUT_VLAN_C import static org.openkilda.model.cookie.Cookie.SERVER_42_FLOW_RTT_OUTPUT_VXLAN_COOKIE import static org.openkilda.testing.Constants.RULES_DELETION_TIME import static org.openkilda.testing.Constants.RULES_INSTALLATION_TIME +import static org.openkilda.testing.Constants.SERVER42_STATS_LAG import static org.openkilda.testing.Constants.STATS_FROM_SERVER42_LOGGING_TIMEOUT import static org.openkilda.testing.Constants.WAIT_OFFSET @@ -29,6 +26,7 @@ import org.openkilda.functionaltests.HealthCheckSpecification import org.openkilda.functionaltests.extension.tags.Tags import org.openkilda.functionaltests.helpers.Wrappers import org.openkilda.functionaltests.helpers.model.SwitchPair +import org.openkilda.functionaltests.model.stats.FlowStats import org.openkilda.messaging.model.system.FeatureTogglesDto import org.openkilda.messaging.payload.flow.FlowState import org.openkilda.model.FlowEncapsulationType @@ -44,6 +42,7 @@ import org.openkilda.northbound.dto.v2.switches.LagPortRequest import org.openkilda.testing.model.topology.TopologyDefinition.Switch import groovy.time.TimeCategory +import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import spock.lang.Ignore import spock.lang.Isolated @@ -52,8 +51,6 @@ import spock.lang.ResourceLock import spock.lang.Shared import spock.util.mop.Use -import java.util.concurrent.TimeUnit - @Use(TimeCategory) @Narrative("Verify that statistic is collected from server42 Rtt") /* On local environment these tests will use stubs without sending real rtt packets across the network. @@ -93,9 +90,8 @@ class Server42FlowRttSpec extends HealthCheckSpecification { flowHelperV2.addFlow(flow) then: "Check if stats for forward are available" - def statsData = null Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT, 1) { - flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValues() + flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValues() } cleanup: "Revert system to original state" @@ -199,8 +195,8 @@ class Server42FlowRttSpec extends HealthCheckSpecification { and: "Check if stats for forward and reverse flows are available" Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT, 1) { - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValues() - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValues() } cleanup: "Revert system to original state" @@ -299,10 +295,10 @@ class Server42FlowRttSpec extends HealthCheckSpecification { SECONDS.sleep(statsWaitSeconds) then: "Expect no flow rtt stats for forward flow" - !flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValuesAfter(checkpointTime) + !flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValuesAfter(checkpointTime) and: "Expect no flow rtt stats for reversed flow" - !flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE).hasNonZeroValuesAfter(checkpointTime) + !flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE, SERVER_42).hasNonZeroValuesAfter(checkpointTime) cleanup: "Revert system to original state" revertToOrigin([flow, reversedFlow], flowRttFeatureStartState, initialSwitchRtt) @@ -340,14 +336,16 @@ class Server42FlowRttSpec extends HealthCheckSpecification { and: "Stats for both directions are available" Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT, 1) { - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValues() - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE, SERVER_42).hasNonZeroValues() } when: "Disable flow rtt on dst switch" changeFlowRttSwitch(switchPair.dst, false) - sleep(1000) - checkpointTime = new Date().getTime() + Wrappers.wait(RULES_INSTALLATION_TIME, 3) { + northboundV2.validateSwitch(switchPair.dst.dpId).isAsExpected() + } + checkpointTime = new Date().getTime() + SERVER42_STATS_LAG * 1000 then: "Stats are available in forward direction" Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT, 1) { @@ -380,8 +378,8 @@ class Server42FlowRttSpec extends HealthCheckSpecification { flowHelperV2.addFlow(flow) Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT, 1) { - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValues() - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE, SERVER_42).hasNonZeroValues() } when: "Delete ingress server42 rule related to the flow on the src switch" @@ -410,11 +408,11 @@ class Server42FlowRttSpec extends HealthCheckSpecification { northbound.getFlowStatus(flow.flowId).status == FlowState.UP and: "server42 stats for forward direction are not increased" - !flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValuesAfter(timeWhenMissingRuleIsDetected) + !flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValuesAfter(timeWhenMissingRuleIsDetected) and: "server42 stats for reverse direction are increased" Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT + WAIT_OFFSET) { - flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE).hasNonZeroValuesAfter(timeWhenMissingRuleIsDetected) + flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE, SERVER_42).hasNonZeroValuesAfter(timeWhenMissingRuleIsDetected) } when: "Synchronize the flow" @@ -431,7 +429,7 @@ class Server42FlowRttSpec extends HealthCheckSpecification { then: "server42 stats for forward direction are available again" Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT + WAIT_OFFSET, 1) { - flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValuesAfter(timeWhenMissingRuleIsReinstalled) + flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValuesAfter(timeWhenMissingRuleIsReinstalled) } cleanup: "Revert system to original state" @@ -468,8 +466,8 @@ class Server42FlowRttSpec extends HealthCheckSpecification { //make sure stats for the flow1 in forward directions are available and not available for the flow2 Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT, 1) { - assert flowStats.rttOf(flow1.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValues() - assert flowStats.rttOf(flow2.getFlowId()).get(FLOW_RTT, FORWARD) == null + assert flowStats.rttOf(flow1.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValues() + assert flowStats.rttOf(flow2.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42) == null } when: "Try to swap src endpoints for two flows" @@ -512,12 +510,12 @@ class Server42FlowRttSpec extends HealthCheckSpecification { and: "server42 stats are available for the flow2 in the forward direction" Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT, 1) { - assert flowStats.rttOf(flow2.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValues() + assert flowStats.rttOf(flow2.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValues() } and: "server42 stats are not available any more for the flow1 in the forward direction" //give one second extra after swap - !flowStats.rttOf(flow1.getFlowId()).get(FLOW_RTT, FORWARD) + !flowStats.rttOf(flow1.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42) .hasNonZeroValuesAfter(timeWhenEndpointWereSwapped + 1000) cleanup: @@ -543,7 +541,6 @@ class Server42FlowRttSpec extends HealthCheckSpecification { changeFlowRttSwitch(switchPair.src, true) and: "Create a flow" - def flowCreateTime = new Date() def flow = flowHelperV2.randomFlow(switchPair) flowHelperV2.addFlow(flow) @@ -612,8 +609,8 @@ class Server42FlowRttSpec extends HealthCheckSpecification { then: "Check if stats for forward/reverse directions are available" Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT + WAIT_OFFSET, 1) { - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValuesAfter(flowUpdateTime) - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE).hasNonZeroValuesAfter(flowUpdateTime) + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValuesAfter(flowUpdateTime) + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE, SERVER_42).hasNonZeroValuesAfter(flowUpdateTime) } and: "Flow is valid" @@ -700,8 +697,8 @@ class Server42FlowRttSpec extends HealthCheckSpecification { then: "Flow rtt stats are not available due to incorrect s42 port on the src switch" Wrappers.timedLoop(STATS_FROM_SERVER42_LOGGING_TIMEOUT / 2) { - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD) == null - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE) == null + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42) == null + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE, SERVER_42) == null } when: "Set correct config for the server42 on the src switch" @@ -731,8 +728,8 @@ class Server42FlowRttSpec extends HealthCheckSpecification { and: "Flow rtt stats are available" Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT, 1) { - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValues() - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE, SERVER_42).hasNonZeroValues() } cleanup: @@ -774,8 +771,8 @@ class Server42FlowRttSpec extends HealthCheckSpecification { then: "Stats from server42 for forward/reverse directions are available" Wrappers.wait(STATS_FROM_SERVER42_LOGGING_TIMEOUT, 1) { - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD).hasNonZeroValues() - assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, FORWARD, SERVER_42).hasNonZeroValues() + assert flowStats.rttOf(flow.getFlowId()).get(FLOW_RTT, REVERSE, SERVER_42).hasNonZeroValues() } cleanup: "Revert system to original state" diff --git a/src-java/testing/test-library/src/main/java/org/openkilda/testing/Constants.java b/src-java/testing/test-library/src/main/java/org/openkilda/testing/Constants.java index 6c552eb4b0f..b36d615cbe5 100644 --- a/src-java/testing/test-library/src/main/java/org/openkilda/testing/Constants.java +++ b/src-java/testing/test-library/src/main/java/org/openkilda/testing/Constants.java @@ -33,6 +33,7 @@ public final class Constants { public static final Integer STATS_LOGGING_TIMEOUT = 60; public static final Integer FL_DUMP_INTERVAL = 60; //floodlight.dump.interval defaults to 60 public static final Integer STATS_FROM_SERVER42_LOGGING_TIMEOUT = 60; + public static final Integer SERVER42_STATS_LAG = 15; public static final String NON_EXISTENT_FLOW_ID = "non-existent-" + UUID.randomUUID().toString(); public static final Integer SINGLE_TABLE_ID = 0; public static final Integer INGRESS_RULE_MULTI_TABLE_ID = 2; diff --git a/src-java/testing/test-library/src/main/java/org/openkilda/testing/service/tsdb/model/StatsResult.java b/src-java/testing/test-library/src/main/java/org/openkilda/testing/service/tsdb/model/StatsResult.java index 1423623fbf0..acded768717 100644 --- a/src-java/testing/test-library/src/main/java/org/openkilda/testing/service/tsdb/model/StatsResult.java +++ b/src-java/testing/test-library/src/main/java/org/openkilda/testing/service/tsdb/model/StatsResult.java @@ -62,7 +62,7 @@ public boolean hasNonZeroValues() { public boolean hasNonZeroValuesAfter(long timestamp) { return dataPoints.keySet().stream() - .anyMatch(tstamp -> tstamp >= timestamp && dataPoints.get(tstamp) > 0); + .anyMatch(tstamp -> tstamp >= timestamp && dataPoints.get(tstamp) != 0); } public boolean hasValue(long expectedValue) {