diff --git a/CHANGELOG.md b/CHANGELOG.md index 14f4c9adb37..420fb4f3538 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ # Changelog +## v1.145.0 (16/10/2023) -## v1.144.0 (04/10/2023) +### Bug Fixes: +- [#5427](https://github.com/telstra/open-kilda/pull/5427) 5424 GUI: enable to get flow path if flow name contains a dot (Issue: [#5424](https://github.com/telstra/open-kilda/issues/5424)) [**gui**] + +### Improvements: +- [#5414](https://github.com/telstra/open-kilda/pull/5414) [TEST]: 5357: Improvement: Remove Tidy annotation [**tests**] +- [#5416](https://github.com/telstra/open-kilda/pull/5416) [TEST]: Fix victoria metrics key(query_path) [**tests**] +- [#5421](https://github.com/telstra/open-kilda/pull/5421) #5390: [TEST] Fix flaky VXLAN flow test (Issue: [#5390](https://github.com/telstra/open-kilda/issues/5390)) [**tests**] +- [#5433](https://github.com/telstra/open-kilda/pull/5433) Update requirements of changelog generator + +### Other changes: +- [#4667](https://github.com/telstra/open-kilda/pull/4667) Feature/create lag port (Issue: [#4666](https://github.com/telstra/open-kilda/issues/4666)) [**gui**] +- [#5404](https://github.com/telstra/open-kilda/pull/5404) [TEST] Wait for lab to become operational between test runs [**tests**] +- [#5407](https://github.com/telstra/open-kilda/pull/5407) [TEST]: 5303: Y-Flow: Reroute [**tests**] + +For the complete list of changes, check out [the commit log](https://github.com/telstra/open-kilda/compare/v1.144.0...v1.145.0). + +### Affected Components: +gui + +--- + +## v1.144.0 (09/10/2023) ### Features: - [#5340](https://github.com/telstra/open-kilda/pull/5340) Add ability to save history on flow PATCH operation. (Issues: [#5237](https://github.com/telstra/open-kilda/issues/5237) [#5385](https://github.com/telstra/open-kilda/issues/5385)) @@ -31,7 +53,7 @@ For the complete list of changes, check out [the commit log](https://github.com/ ### Affected Components: history -## v1.143.0 (28/09/2023) +## v1.143.0 (02/10/2023) ### Features: - [#5355](https://github.com/telstra/open-kilda/pull/5355) Update Flow graph in GUI for VictoriaMetrics #5295 (Issues: [#5295](https://github.com/telstra/open-kilda/issues/5295) [#5295](https://github.com/telstra/open-kilda/issues/5295)) diff --git a/confd/templates/functional-tests/kilda.properties.tmpl b/confd/templates/functional-tests/kilda.properties.tmpl index cd82b466058..7ccec82965b 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=http://{{ 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/src-gui/src/main/java/org/openkilda/constants/IConstants.java b/src-gui/src/main/java/org/openkilda/constants/IConstants.java index 4f844c17a7d..1d84e7c7664 100644 --- a/src-gui/src/main/java/org/openkilda/constants/IConstants.java +++ b/src-gui/src/main/java/org/openkilda/constants/IConstants.java @@ -169,6 +169,9 @@ private NorthBoundUrl() { public static final String UPDATE_SWITCH_LOCATION = VERSION_TWO + "/switches/{switch_id}"; public static final String GET_LINK_BFD_PROPERTIES = VERSION_TWO + "/links/{src-switch}_{src-port}/{dst-switch}_{dst-port}/bfd"; + public static final String SWITCH_LOGICAL_PORT = VERSION_TWO + "/switches/{switch_id}/lags"; + public static final String DELETE_SWITCH_LOGICAL_PORT = VERSION_TWO + + "/switches/{switch_id}/lags/{logical_port_number}"; } public static final class OpenTsDbUrl { @@ -315,6 +318,10 @@ private Permission() { public static final String ISL_UPDATE_BFD_PROPERTIES = "isl_update_bfd_properties"; public static final String ISL_DELETE_BFD = "isl_delete_bfd"; + + public static final String SW_CREATE_LOGICAL_PORT = "sw_create_logical_port"; + + public static final String SW_DELETE_LOGICAL_PORT = "sw_delete_logical_port"; } public static final class Settings { 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 9e0d74062fa..6919a74fd2d 100644 --- a/src-gui/src/main/java/org/openkilda/constants/Metrics.java +++ b/src-gui/src/main/java/org/openkilda/constants/Metrics.java @@ -15,6 +15,7 @@ package org.openkilda.constants; +import lombok.AccessLevel; import lombok.Getter; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; @@ -90,6 +91,7 @@ public enum Metrics { private final String tag; + @Getter(AccessLevel.NONE) private final String metricName; private static final Map> TAG_TO_METRICS_MAP = new HashMap<>(); @@ -117,6 +119,10 @@ public enum Metrics { this.metricName = metricName; } + public final String getMetricName(String prefix) { + return prefix + this.metricName; + } + /** * Flow value. * @@ -131,9 +137,9 @@ public static List flowValue(String tag, boolean uniDirectional, String return metricNames; } metrics.forEach(metric -> { - metricNames.add(prefix + metric.getMetricName()); + metricNames.add(metric.getMetricName(prefix)); if (uniDirectional) { - metricNames.add(prefix + metric.getMetricName()); + metricNames.add(metric.getMetricName(prefix)); } }); return metricNames; @@ -150,7 +156,7 @@ public static String flowMetricName(String metricPart, String prefix) { return StringUtils.EMPTY; } Optional metric = TAG_TO_METRICS_MAP.get("Flow_" + metricPart.toLowerCase()).stream().findFirst(); - return metric.map(metrics -> prefix + metrics.getMetricName()).orElse(StringUtils.EMPTY); + return metric.map(metrics -> metrics.getMetricName(prefix)).orElse(StringUtils.EMPTY); } /** @@ -164,7 +170,7 @@ public static String meterMetricName(String metricPart, String prefix) { return StringUtils.EMPTY; } Optional metric = TAG_TO_METRICS_MAP.get("Meter_" + metricPart.toLowerCase()).stream().findFirst(); - return metric.map(metrics -> prefix + metrics.getMetricName()).orElse(StringUtils.EMPTY); + return metric.map(metrics -> metrics.getMetricName(prefix)).orElse(StringUtils.EMPTY); } /** @@ -178,7 +184,7 @@ public static List flowRawValue(String tag, String prefix) { tag = "Flow_raw_" + tag; for (Metrics metric : values()) { if (metric.getTag().equalsIgnoreCase(tag)) { - list.add(prefix + metric.getMetricName()); + list.add(metric.getMetricName(prefix)); } } return list; @@ -202,7 +208,7 @@ public static List switchValue(String tag, String prefix) { } for (Metrics metric : values()) { if (metric.getTag().equalsIgnoreCase(tag)) { - list.add(prefix + metric.getMetricName()); + list.add(metric.getMetricName(prefix)); } } return list; @@ -218,7 +224,7 @@ public static List getStartsWith(String tag, String prefix) { List list = new ArrayList<>(); for (Metrics metric : values()) { if (metric.getTag().startsWith(tag)) { - list.add(prefix + metric.getMetricName()); + list.add(metric.getMetricName(prefix)); } } return list; @@ -236,7 +242,7 @@ public static List meterValue(String tag, String prefix) { if (CollectionUtils.isEmpty(metrics)) { return metricNames; } - metrics.forEach(metric -> metricNames.add(prefix + metric.getMetricName())); + metrics.forEach(metric -> metricNames.add(metric.getMetricName(prefix))); return metricNames; } @@ -246,7 +252,7 @@ public static List meterValue(String tag, String prefix) { * @return the list */ public static List list(String prefix) { - return Arrays.stream(values()).map(metric -> prefix + metric.getMetricName()).collect(Collectors.toList()); + return Arrays.stream(values()).map(metric -> metric.getMetricName(prefix)).collect(Collectors.toList()); } /** diff --git a/src-gui/src/main/java/org/openkilda/controller/ContractController.java b/src-gui/src/main/java/org/openkilda/controller/ContractController.java index 3626eadd04b..e4a7e3a21fa 100644 --- a/src-gui/src/main/java/org/openkilda/controller/ContractController.java +++ b/src-gui/src/main/java/org/openkilda/controller/ContractController.java @@ -63,7 +63,7 @@ public class ContractController { /** * Returns delete contract exists in the system. */ - @RequestMapping(value = "/delete/{flowId}/{contractid:.+}", method = RequestMethod.DELETE) + @RequestMapping(value = "/delete/{flowId:.+}/{contractid:.+}", method = RequestMethod.DELETE) @ResponseStatus(HttpStatus.OK) @ResponseBody public boolean deleteContract(@PathVariable(name = "flowId", required = false) String flowId, diff --git a/src-gui/src/main/java/org/openkilda/controller/FlowController.java b/src-gui/src/main/java/org/openkilda/controller/FlowController.java index 812cce7eb25..c4fc1f3ce50 100644 --- a/src-gui/src/main/java/org/openkilda/controller/FlowController.java +++ b/src-gui/src/main/java/org/openkilda/controller/FlowController.java @@ -109,7 +109,7 @@ public class FlowController extends BaseController { * id of flow path requested. * @return flow path with all nodes/switches exists in provided flow */ - @RequestMapping(value = "/path/{flowId}", method = RequestMethod.GET) + @RequestMapping(value = "/path/{flowId:.+}", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) public @ResponseBody FlowPayload getFlowPath(@PathVariable final String flowId) { LOGGER.info("Get flow path. Flow id: '" + flowId + "'"); @@ -124,7 +124,7 @@ public class FlowController extends BaseController { * id of reroute requested. * @return reroute flow of new flow path with all nodes/switches exist */ - @RequestMapping(value = "/{flowId}/reroute", method = RequestMethod.GET) + @RequestMapping(value = "/{flowId:.+}/reroute", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) public @ResponseBody FlowPath rerouteFlow(@PathVariable final String flowId) { activityLogger.log(ActivityType.FLOW_REROUTE, flowId); @@ -139,7 +139,7 @@ public class FlowController extends BaseController { * id of validate flow requested. * @return validate flow */ - @RequestMapping(value = "/{flowId}/validate", method = RequestMethod.GET) + @RequestMapping(value = "/{flowId:.+}/validate", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) public @ResponseBody String validateFlow(@PathVariable final String flowId) { activityLogger.log(ActivityType.FLOW_VALIDATE, flowId); @@ -155,7 +155,7 @@ public class FlowController extends BaseController { * @return flowInfo * @throws AccessDeniedException the access denied exception */ - @RequestMapping(value = "/{flowId}", method = RequestMethod.GET) + @RequestMapping(value = "/{flowId:.+}", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) @Permissions(values = { IConstants.Permission.MENU_FLOWS }) public @ResponseBody FlowInfo getFlowById(@PathVariable final String flowId, @@ -172,7 +172,7 @@ public class FlowController extends BaseController { * id of flow requested. * @return flow */ - @RequestMapping(value = "/{flowId}/status", method = RequestMethod.GET) + @RequestMapping(value = "/{flowId:.+}/status", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) public @ResponseBody FlowStatus getFlowStatusById(@PathVariable final String flowId) { LOGGER.info("Get flow status by id. Flow id: '" + flowId + "'"); @@ -203,7 +203,7 @@ public class FlowController extends BaseController { * the flow * @return the flow */ - @RequestMapping(value = "/{flowId}", method = RequestMethod.PUT) + @RequestMapping(value = "/{flowId:.+}", method = RequestMethod.PUT) @ResponseStatus(HttpStatus.CREATED) @Permissions(values = { IConstants.Permission.FW_FLOW_UPDATE }) public @ResponseBody FlowV2 updateFlow(@PathVariable("flowId") final String flowId, @@ -221,7 +221,7 @@ public class FlowController extends BaseController { * the flow id * @return the flow */ - @RequestMapping(value = "/{flowId}", method = RequestMethod.DELETE) + @RequestMapping(value = "/{flowId:.+}", method = RequestMethod.DELETE) @ResponseStatus(HttpStatus.OK) @Permissions(values = { IConstants.Permission.FW_FLOW_DELETE }) @ResponseBody @@ -240,7 +240,7 @@ public FlowV2 deleteFlow(@RequestBody final UserInfo userInfo, @PathVariable("fl * id of validate flow requested. * @return validate flow */ - @RequestMapping(value = "/{flowId}/sync", method = RequestMethod.PATCH) + @RequestMapping(value = "/{flowId:.+}/sync", method = RequestMethod.PATCH) @ResponseStatus(HttpStatus.OK) @Permissions(values = { IConstants.Permission.FW_FLOW_RESYNC }) public @ResponseBody String resyncFlow(@PathVariable final String flowId) { @@ -277,7 +277,7 @@ public void getAllStatusWithCron() { * @param flow the flow * @return the string */ - @RequestMapping(value = "/{flowId}/ping", method = RequestMethod.PUT) + @RequestMapping(value = "/{flowId:.+}/ping", method = RequestMethod.PUT) @ResponseStatus(HttpStatus.OK) @Permissions(values = { IConstants.Permission.FW_FLOW_PING }) public @ResponseBody String flowPing(@PathVariable final String flowId, @RequestBody final FlowV2 flow) { @@ -291,7 +291,7 @@ public void getAllStatusWithCron() { * * @return the flow history. */ - @RequestMapping(value = "/all/history/{flowId}", method = RequestMethod.GET) + @RequestMapping(value = "/all/history/{flowId:.+}", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) @Permissions(values = { IConstants.Permission.FW_FLOW_HISTORY }) public @ResponseBody List getFlowHistory(@PathVariable final String flowId, @@ -306,7 +306,7 @@ public void getAllStatusWithCron() { * id of flow. * @return FlowConnectedDevice */ - @RequestMapping(value = "/connected/devices/{flowId}", method = RequestMethod.GET) + @RequestMapping(value = "/connected/devices/{flowId:.+}", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) public @ResponseBody FlowConnectedDevice getFlowConnectedDevice(@PathVariable final String flowId, @RequestParam(name = "since", required = false) String timeLastSeen) { 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 20da00a6adb..62c8eb742d0 100644 --- a/src-gui/src/main/java/org/openkilda/controller/StatsController.java +++ b/src-gui/src/main/java/org/openkilda/controller/StatsController.java @@ -144,7 +144,7 @@ public String getPortStats(@PathVariable String switchid, @PathVariable String p * @param downsample the downsample * @return the flow stats */ - @RequestMapping(value = "flowid/{flowid}/{startDate}/{endDate}/{downsample}/{metric}", + @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}) @@ -263,7 +263,7 @@ public String getIslLossPacketStats(@PathVariable String srcSwitch, @PathVariabl * @param direction the direction * @return the flow loss packet stats */ - @RequestMapping(value = "flow/losspackets/{flowid}/{startDate}/{endDate}/{downsample}/{direction}", + @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}) @@ -325,7 +325,7 @@ public List getSwitchPortsStats(@PathVariable String switchid, @PathVa * @param metric the metric * @return the meter stats */ - @RequestMapping(value = "meter/{flowid}/{startDate}/{endDate}/{downsample}/{metric}/{direction}", + @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}) diff --git a/src-gui/src/main/java/org/openkilda/controller/SwitchController.java b/src-gui/src/main/java/org/openkilda/controller/SwitchController.java index b387f5a2223..bca05945419 100644 --- a/src-gui/src/main/java/org/openkilda/controller/SwitchController.java +++ b/src-gui/src/main/java/org/openkilda/controller/SwitchController.java @@ -34,6 +34,7 @@ import org.openkilda.model.SwitchFlowsInfoPerPort; import org.openkilda.model.SwitchInfo; import org.openkilda.model.SwitchLocation; +import org.openkilda.model.SwitchLogicalPort; import org.openkilda.model.SwitchMeter; import org.openkilda.model.SwitchProperty; import org.openkilda.service.SwitchService; @@ -491,4 +492,38 @@ public class SwitchController { + srcPort + "\nDst_SW_" + dstSwitch + "\nDst_PORT_" + dstPort); return serviceSwitch.deleteLinkBfd(srcSwitch, srcPort, dstSwitch, dstPort); } + + /** + * Creates switch logical port. + * + * @param switchId the switch id + * @param switchLogicalPort the switch logical port + * @return the SwitchLogicalPort + */ + @RequestMapping(value = "/{switch_id}/lags", method = RequestMethod.POST) + @ResponseStatus(HttpStatus.OK) + @Permissions(values = IConstants.Permission.SW_CREATE_LOGICAL_PORT) + public @ResponseBody SwitchLogicalPort createLogicalPort(@PathVariable("switch_id") final String switchId, + @RequestBody(required = true) SwitchLogicalPort switchLogicalPort) { + activityLogger.log(ActivityType.CREATE_LOGICAL_PORT, "SW_" + switchId + ", " + + "PORT_" + switchLogicalPort.getPortNumbers()); + return serviceSwitch.createLogicalPort(switchId, switchLogicalPort); + } + + /** + * Deletes switch logical port. + * + * @param switchId the switch id + * @param logicalPortNumber the switch logical port + * @return the SwitchLogicalPort + */ + @RequestMapping(value = "/{switch_id}/lags/{logical_port_number}", method = RequestMethod.DELETE) + @ResponseStatus(HttpStatus.OK) + @Permissions(values = IConstants.Permission.SW_DELETE_LOGICAL_PORT) + public @ResponseBody SwitchLogicalPort deleteLogicalPort(@PathVariable("switch_id") final String switchId, + @PathVariable("logical_port_number") final String logicalPortNumber) { + activityLogger.log(ActivityType.DELETE_LOGICAL_PORT, "SW_" + switchId + ", " + + "L-PORT_" + logicalPortNumber); + return serviceSwitch.deleteLogicalPort(switchId, logicalPortNumber); + } } 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 97f35c5cff4..a8e420969e9 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 @@ -248,7 +248,8 @@ private Query getQuery(final String downsample, final String metric, final Map getLogicalPort(String switchId) { + try { + HttpResponse response = restClientManager.invoke( + applicationProperties.getNbBaseUrl() + IConstants.NorthBoundUrl + .SWITCH_LOGICAL_PORT.replace("{switch_id}", switchId), + HttpMethod.GET, "", "application/json", + applicationService.getAuthHeader()); + if (RestClientManager.isValidResponse(response)) { + return restClientManager.getResponseList(response, SwitchLogicalPort.class); + } + } catch (InvalidResponseException e) { + LOGGER.error("Error occurred while getting switch logical port:" + switchId, e); + throw new InvalidResponseException(e.getCode(), e.getResponse()); + } + return null; + } } diff --git a/src-gui/src/main/java/org/openkilda/log/constants/ActivityType.java b/src-gui/src/main/java/org/openkilda/log/constants/ActivityType.java index dff7a2db0aa..c81d200ff72 100644 --- a/src-gui/src/main/java/org/openkilda/log/constants/ActivityType.java +++ b/src-gui/src/main/java/org/openkilda/log/constants/ActivityType.java @@ -66,7 +66,9 @@ public enum ActivityType { UNLOCK_USER_ACCOUNT(48L), UPDATE_SWITCH_LOCATION(43L), UPDATE_ISL_BFD_PROPERTIES(44L), - DELETE_ISL_BFD(45L); + DELETE_ISL_BFD(45L), + CREATE_LOGICAL_PORT(49L), + DELETE_LOGICAL_PORT(50L); private Long id; private ActivityTypeEntity activityTypeEntity; diff --git a/src-gui/src/main/java/org/openkilda/model/PortInfo.java b/src-gui/src/main/java/org/openkilda/model/PortInfo.java index bc240cdf058..9a5a3be1f78 100644 --- a/src-gui/src/main/java/org/openkilda/model/PortInfo.java +++ b/src-gui/src/main/java/org/openkilda/model/PortInfo.java @@ -26,6 +26,7 @@ import java.io.Serializable; import java.math.BigInteger; +import java.util.List; import java.util.Map; /** @@ -97,6 +98,15 @@ public class PortInfo implements Serializable, Comparable { @JsonProperty("is-active") private String isActive; + @JsonProperty("is_logical_port") + private boolean logicalPort; + + @JsonProperty("logical_group_name") + private String logicalGroupName; + + @JsonProperty("lag_group") + private List portNumbers; + @JsonProperty("discrepancy") private PortDiscrepancy discrepancy; diff --git a/src-gui/src/main/java/org/openkilda/model/SwitchLogicalPort.java b/src-gui/src/main/java/org/openkilda/model/SwitchLogicalPort.java new file mode 100644 index 00000000000..5916fb3b0ec --- /dev/null +++ b/src-gui/src/main/java/org/openkilda/model/SwitchLogicalPort.java @@ -0,0 +1,35 @@ +/* Copyright 2020 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.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import lombok.Data; + +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@Data +@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) +public class SwitchLogicalPort { + + private List portNumbers; + private Boolean lacpReply; + private String logicalPortNumber; +} 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 c649eca28de..2bf745b3cb6 100644 --- a/src-gui/src/main/java/org/openkilda/service/StatsService.java +++ b/src-gui/src/main/java/org/openkilda/service/StatsService.java @@ -15,6 +15,8 @@ package org.openkilda.service; +import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; + import org.openkilda.config.ApplicationProperties; import org.openkilda.constants.Direction; import org.openkilda.constants.IConstants.Status; @@ -32,6 +34,7 @@ import org.openkilda.model.FlowPathStats; import org.openkilda.model.PortDiscrepancy; import org.openkilda.model.PortInfo; +import org.openkilda.model.SwitchLogicalPort; import org.openkilda.model.SwitchPortStats; import org.openkilda.model.victoria.RangeQueryParams; import org.openkilda.model.victoria.VictoriaData; @@ -425,7 +428,25 @@ private double calculateHighestValue(Map dps) { */ private List getIslPorts(final Map> portStatsByPortNo, String switchid) { List portInfos = getPortInfo(portStatsByPortNo); - + String switchIdentifier = IoUtil.switchCodeToSwitchId(switchid); + List switchLogicalPorts = switchIntegrationService.getLogicalPort(switchIdentifier); + if (isNotEmpty(switchLogicalPorts)) { + for (SwitchLogicalPort logicalPort : switchLogicalPorts) { + for (String portNumber : logicalPort.getPortNumbers()) { + for (PortInfo portInfo : portInfos) { + if (portInfo.getPortNumber().equals(logicalPort.getLogicalPortNumber())) { + portInfo.setLogicalPort(true); + portInfo.setAssignmenttype("PORT"); + portInfo.setPortNumbers(logicalPort.getPortNumbers()); + } else if (portInfo.getPortNumber().equals(portNumber)) { + portInfo.setAssignmenttype("LAG_GROUP"); + portInfo.setLogicalGroupName(logicalPort.getLogicalPortNumber()); + portInfo.setLogicalPort(false); + } + } + } + } + } List islLinkPorts = switchIntegrationService.getIslLinkPortsInfo(null); String switchIdInfo = null; if (islLinkPorts != null) { @@ -433,9 +454,9 @@ private List getIslPorts(final Map> portSt for (IslPath islPath : islLink.getPath()) { switchIdInfo = ("SW" + islPath.getSwitchId().replaceAll(":", "")).toUpperCase(); if (switchIdInfo.equals(switchid)) { - for (int i = 0; i < portInfos.size(); i++) { - if (portInfos.get(i).getPortNumber().equals(islPath.getPortNo().toString())) { - portInfos.get(i).setAssignmenttype("ISL"); + for (PortInfo portInfo : portInfos) { + if (portInfo.getPortNumber().equals(islPath.getPortNo().toString())) { + portInfo.setAssignmenttype("ISL"); } } } @@ -478,7 +499,7 @@ private VictoriaData buildVictoriaData(VictoriaDbRes dbData, String metricName) LinkedHashMap timeToValueMap = new LinkedHashMap<>(); Map tags = new HashMap<>(); - if (dbData.getData() != null && CollectionUtils.isNotEmpty(dbData.getData().getResult())) { + if (dbData.getData() != null && isNotEmpty(dbData.getData().getResult())) { tags = dbData.getData().getResult().get(0).getTags(); dbData.getData().getResult().get(0).getValues() .forEach(timeToValue -> diff --git a/src-gui/src/main/java/org/openkilda/service/SwitchService.java b/src-gui/src/main/java/org/openkilda/service/SwitchService.java index 9e1b8e86dee..5603b7e247e 100644 --- a/src-gui/src/main/java/org/openkilda/service/SwitchService.java +++ b/src-gui/src/main/java/org/openkilda/service/SwitchService.java @@ -41,6 +41,7 @@ import org.openkilda.model.SwitchFlowsInfoPerPort; import org.openkilda.model.SwitchInfo; import org.openkilda.model.SwitchLocation; +import org.openkilda.model.SwitchLogicalPort; import org.openkilda.model.SwitchMeter; import org.openkilda.model.SwitchProperty; import org.openkilda.model.SwitchStatus; @@ -614,5 +615,13 @@ public LinkBfdProperties updateLinkBfdProperties(String srcSwitch, String srcPor public String deleteLinkBfd(String srcSwitch, String srcPort, String dstSwitch, String dstPort) { return switchIntegrationService.deleteLinkBfd(srcSwitch, srcPort, dstSwitch, dstPort); } + + public SwitchLogicalPort createLogicalPort(String switchId, SwitchLogicalPort switchLogicalPort) { + return switchIntegrationService.createLogicalPort(switchId, switchLogicalPort); + } + + public SwitchLogicalPort deleteLogicalPort(String switchId, String logicalPortNumber) { + return switchIntegrationService.deleteLogicalPort(switchId, logicalPortNumber); + } } diff --git a/src-gui/src/main/resources/db/import-script_33.sql b/src-gui/src/main/resources/db/import-script_33.sql new file mode 100644 index 00000000000..9acc0c1d5c0 --- /dev/null +++ b/src-gui/src/main/resources/db/import-script_33.sql @@ -0,0 +1,18 @@ +INSERT INTO VERSION_ENTITY (Version_ID, Version_Number, Version_Deployment_Date) +VALUES (33, 33, CURRENT_TIMESTAMP); + +INSERT INTO KILDA_PERMISSION (PERMISSION_ID, PERMISSION, IS_EDITABLE, IS_ADMIN_PERMISSION, STATUS_ID, CREATED_BY, CREATED_DATE, UPDATED_BY, UPDATED_DATE,DESCRIPTION) VALUES + (363, 'sw_create_logical_port', false, false, 1, 1, CURRENT_TIMESTAMP, 1, CURRENT_TIMESTAMP, 'Permission to create switch logical port'), + (364, 'sw_delete_logical_port', false, false, 1, 1, CURRENT_TIMESTAMP, 1, CURRENT_TIMESTAMP, 'Permission to delete switch logical port'); + +INSERT INTO ROLE_PERMISSION (ROLE_ID,PERMISSION_ID) VALUES + (2, 363), + (2, 364); + +INSERT INTO ACTIVITY_TYPE (activity_type_id, activity_name) VALUES + (49, 'CREATE_LOGICAL_PORT'), + (50, 'DELETE_LOGICAL_PORT'); + + + + diff --git a/src-gui/ui/src/app/app.module.ts b/src-gui/ui/src/app/app.module.ts index dbc2292e6c1..69faaf27714 100644 --- a/src-gui/ui/src/app/app.module.ts +++ b/src-gui/ui/src/app/app.module.ts @@ -111,6 +111,7 @@ import {SamlListTableComponent} from './modules/settings/saml-list-table/saml-li import {SwitchupdatemodalComponent} from './common/components/switchupdatemodal/switchupdatemodal.component'; 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'; @NgModule({ declarations: [ @@ -205,6 +206,7 @@ import {FlowPingModalComponent} from './common/components/flow-ping-modal/flow-p SwitchupdatemodalComponent, UseractivityListComponent, FlowPingModalComponent, + CreateLagPortComponent, ], imports: [ HttpClientModule, @@ -250,6 +252,7 @@ import {FlowPingModalComponent} from './common/components/flow-ping-modal/flow-p IslmaintenancemodalComponent, SwitchupdatemodalComponent, FlowPingModalComponent, + CreateLagPortComponent, ] }) export class AppModule { } diff --git a/src-gui/ui/src/app/common/constants/constants.ts b/src-gui/ui/src/app/common/constants/constants.ts index 7c2b9668bd3..614a080582b 100644 --- a/src-gui/ui/src/app/common/constants/constants.ts +++ b/src-gui/ui/src/app/common/constants/constants.ts @@ -159,6 +159,9 @@ export const MessageObj = { updating_bfd_properties_error: 'Error in updating BFD properties.', BFD_properties_deleted: 'BFD properties deleted successfully.', error_BFD_properties_delete: 'Error in deleting BFD properties.', - delete_isl_bfd_not_authorised: 'You are not authorised to delete the ISL BFD Properties.' + delete_isl_bfd_not_authorised: 'You are not authorised to delete the ISL BFD Properties.', + create_lag_port: 'Requested Lag Port Created Successfully! Port List Data will be updated in some time', + error_in_create_lag_port: 'Error in create Lag Port!', + port_deleted: 'Port deleted successfully' }; diff --git a/src-gui/ui/src/app/common/data-models/create-lag-port-model.ts b/src-gui/ui/src/app/common/data-models/create-lag-port-model.ts new file mode 100644 index 00000000000..994e2bf8047 --- /dev/null +++ b/src-gui/ui/src/app/common/data-models/create-lag-port-model.ts @@ -0,0 +1,5 @@ +interface CreateLagPortModel { + port_numbers: number[]; + lacp_rely: boolean; + logical_port_number: number; +} diff --git a/src-gui/ui/src/app/common/services/switch.service.ts b/src-gui/ui/src/app/common/services/switch.service.ts index c0a6613523b..15514a33cb3 100644 --- a/src-gui/ui/src/app/common/services/switch.service.ts +++ b/src-gui/ui/src/app/common/services/switch.service.ts @@ -118,5 +118,12 @@ getNetworkPath(source_switch, target_switch, strategy, max_latency) { } xhr.send(requestBody); } + createLagLogicalPort(data: CreateLagPortModel, switchid) { + return this.httpClient.post(`${environment.apiEndPoint}/switch/${switchid}/lags`, data); + } + + deleteLagLogicalPort(switchid, logical_port_number ) { + return this.httpClient.delete(`${environment.apiEndPoint}/switch/${switchid}/lags/${logical_port_number }`); + } } 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 e15a3b32695..9947459fab5 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 @@ -485,7 +485,7 @@ export class FlowDetailComponent implements OnInit { }, error => { const errorMsg = error && error.error && error.error['error-auxiliary-message'] ? error.error['error-auxiliary-message'] : 'No Flow found'; - // this.toaster.error(errorMsg, "Error"); + this.toaster.error(errorMsg, 'Error'); } ); } diff --git a/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.css b/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.html b/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.html new file mode 100644 index 00000000000..be77b47e5a7 --- /dev/null +++ b/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.html @@ -0,0 +1,48 @@ + + + + + diff --git a/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.spec.ts b/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.spec.ts new file mode 100644 index 00000000000..b52c45fbb02 --- /dev/null +++ b/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CreateLagPortComponent } from './create-lag-port.component'; + +describe('CreateLagPortComponent', () => { + let component: CreateLagPortComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CreateLagPortComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CreateLagPortComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.ts b/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.ts new file mode 100644 index 00000000000..aa032cf81b6 --- /dev/null +++ b/src-gui/ui/src/app/modules/switches/create-lag-port/create-lag-port.component.ts @@ -0,0 +1,50 @@ +import {Component, EventEmitter, OnInit, Output} from '@angular/core'; +import {FormBuilder, FormGroup, Validators} from '@angular/forms'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-create-lag-port', + templateUrl: './create-lag-port.component.html', + styleUrls: ['./create-lag-port.component.css'] +}) +export class CreateLagPortComponent implements OnInit { + createLogPortForm: FormGroup; + data: any; + createLagPortModel: CreateLagPortModel; + @Output() emitService = new EventEmitter(); + submitted = false; + + constructor(public activeModal: NgbActiveModal, public formBuilder: FormBuilder) { + } + + ngOnInit() { + const result = JSON.parse(localStorage.getItem('switchPortDetail')); + this.data = result.filter(element => { + return ((element.assignmenttype === 'PORT' || element.assignmenttype === 'Unallocated') && !element.is_logical_port); + }); + this.createLogPortForm = this.formBuilder.group({ + port_numbers: ['', Validators.required], + lacp_reply: [true], + }); + } + + get f() { + return this.createLogPortForm.controls; + } + + createPort() { + this.submitted = true; + if (this.createLogPortForm.invalid) { + return; + } + const portNumbers = this.createLogPortForm.controls['port_numbers'].value; + const portNumbersArray: number[] = Array.isArray(portNumbers) ? portNumbers : [portNumbers]; + + this.createLagPortModel = { + logical_port_number: null, + port_numbers: portNumbersArray.map(i => Number(i)), + lacp_rely: this.createLogPortForm.controls['lacp_reply'].value + }; + this.emitService.emit(this.createLagPortModel); + } +} diff --git a/src-gui/ui/src/app/modules/switches/port-details/port-details.component.html b/src-gui/ui/src/app/modules/switches/port-details/port-details.component.html index 69f6f63feca..8a27a6ab3a6 100644 --- a/src-gui/ui/src/app/modules/switches/port-details/port-details.component.html +++ b/src-gui/ui/src/app/modules/switches/port-details/port-details.component.html @@ -7,6 +7,7 @@ +
diff --git a/src-gui/ui/src/app/modules/switches/port-details/port-details.component.ts b/src-gui/ui/src/app/modules/switches/port-details/port-details.component.ts index 82b7bc54fec..f1bc214650f 100644 --- a/src-gui/ui/src/app/modules/switches/port-details/port-details.component.ts +++ b/src-gui/ui/src/app/modules/switches/port-details/port-details.component.ts @@ -1,292 +1,304 @@ -import { Component, OnInit, EventEmitter, Output, AfterViewInit, OnDestroy } from '@angular/core'; -import { SwitchidmaskPipe } from '../../../common/pipes/switchidmask.pipe'; -import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms'; -import * as _moment from 'moment'; -import { NgxSpinnerService } from 'ngx-spinner'; -import { ToastrService } from 'ngx-toastr'; -import { DygraphService } from '../../../common/services/dygraph.service'; -import { IslDataService } from '../../../common/services/isl-data.service'; -import { SwitchService } from '../../../common/services/switch.service'; -import { ActivatedRoute, Router, NavigationEnd} from '@angular/router'; -import { filter } from 'rxjs/operators'; -import { LoaderService } from '../../../common/services/loader.service'; -import { ClipboardService } from 'ngx-clipboard'; -import { Title } from '@angular/platform-browser'; -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 {Component, OnInit, EventEmitter, Output, AfterViewInit, OnDestroy} from '@angular/core'; +import {SwitchidmaskPipe} from '../../../common/pipes/switchidmask.pipe'; +import {FormBuilder, FormGroup, Validators, NgForm} from '@angular/forms'; +import {ToastrService} from 'ngx-toastr'; +import {SwitchService} from '../../../common/services/switch.service'; +import {ActivatedRoute, Router, NavigationEnd} from '@angular/router'; +import {filter} from 'rxjs/operators'; +import {LoaderService} from '../../../common/services/loader.service'; +import {ClipboardService} from 'ngx-clipboard'; +import {Title} from '@angular/platform-browser'; +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'; declare var moment: any; @Component({ - selector: 'app-port-details', - templateUrl: './port-details.component.html', - styleUrls: ['./port-details.component.css'] + selector: 'app-port-details', + templateUrl: './port-details.component.html', + styleUrls: ['./port-details.component.css'] }) export class PortDetailsComponent implements OnInit, OnDestroy { - portDataObject: any; - retrievedSwitchObject: any; - port_src_switch: any; - openedTab = 'graph'; - portForm: FormGroup; - portFlows: any = []; - flowBandwidthSum: any = 0; - flowBandwidthFlag = false; - switchId = null; - portId = null; - - hasStoreSetting = false; - - - currentRoute: any; - editConfigStatus = false; - currentPortState: string; - requestedPortState: string; - dateMessage: string; - discoverypackets = false; - clipBoardItems = { - sourceSwitch: '', - }; - - descrepancyData = { - assignmentType: { - controller: '-', - inventory: '-' + portDataObject: any; + retrievedSwitchObject: any; + port_src_switch: any; + openedTab = 'graph'; + portForm: FormGroup; + portFlows: any = []; + flowBandwidthSum: any = 0; + flowBandwidthFlag = false; + switchId = null; + portId = null; + + hasStoreSetting = false; + + + currentRoute: any; + editConfigStatus = false; + currentPortState: string; + requestedPortState: string; + dateMessage: string; + discoverypackets = false; + clipBoardItems = { + sourceSwitch: '', + }; + + descrepancyData = { + assignmentType: { + controller: '-', + inventory: '-' + } + }; + + assignmentTypeDescrepancy = false; + + @Output() hideToValue: EventEmitter = new EventEmitter(); + + constructor(private maskPipe: SwitchidmaskPipe, + private formBuiler: FormBuilder, + private toastr: ToastrService, + private loaderService: LoaderService, + private router: Router, + private route: ActivatedRoute, + private switchService: SwitchService, + private clipboardService: ClipboardService, + private titleService: Title, + private modalService: NgbModal, + public commonService: CommonService, + ) { + this.hasStoreSetting = localStorage.getItem('hasSwtStoreSetting') == '1' ? true : false; + if (!this.commonService.hasPermission('menu_switches')) { + this.toastr.error(MessageObj.unauthorised); + this.router.navigate(['/home']); + } + } - }; - - assignmentTypeDescrepancy = false; - - @Output() hideToValue: EventEmitter = new EventEmitter(); - constructor(private maskPipe: SwitchidmaskPipe, - private formBuiler: FormBuilder, - private toastr: ToastrService, - private loaderService: LoaderService, - private router: Router, - private dygraphService: DygraphService, - private route: ActivatedRoute, - - private switchService: SwitchService, - private clipboardService: ClipboardService, - private titleService: Title, - private modalService: NgbModal, - public commonService: CommonService, - ) { - this.hasStoreSetting = localStorage.getItem('hasSwtStoreSetting') == '1' ? true : false; - if (!this.commonService.hasPermission('menu_switches')) { - this.toastr.error(MessageObj.unauthorised); - this.router.navigate(['/home']); - } - - } - - ngOnInit() { - this.titleService.setTitle('OPEN KILDA - Port'); - this.route.parent.params.subscribe(params => this.switchId = params['id']); - this.route.params.subscribe(params => this.portId = params['port']); - - const portDataObjectKey = 'portDataObject_' + this.switchId + '_' + this.portId; - this.portDataObject = JSON.parse(localStorage.getItem(portDataObjectKey)); - this.portForm = this.formBuiler.group({ - portStatus: [this.portDataObject.status], - }); - const switchDetailsKey = 'switchDetailsKey_' + this.switchId; - this.retrievedSwitchObject = JSON.parse(localStorage.getItem(switchDetailsKey)); - this.port_src_switch = this.maskPipe.transform(this.retrievedSwitchObject.switch_id, 'legacy'); - this.clipBoardItems.sourceSwitch = this.retrievedSwitchObject.switch_id; - - if (this.portDataObject['discrepancy'] && (this.portDataObject['discrepancy']['assignment-type'])) { - if (this.portDataObject['discrepancy']['assignment-type']) { - this.assignmentTypeDescrepancy = true; - this.descrepancyData.assignmentType.controller = (typeof(this.portDataObject['discrepancy']['controller-assignment-type']) != 'undefined') ? this.portDataObject['discrepancy']['controller-assignment-type'] : '-'; - this.descrepancyData.assignmentType.inventory = (typeof(this.portDataObject['discrepancy']['inventory-assignment-type']) != 'undefined') ? this.portDataObject['discrepancy']['inventory-assignment-type'] : '-'; - } + ngOnInit() { + this.titleService.setTitle('OPEN KILDA - Port'); + this.route.parent.params.subscribe(params => this.switchId = params['id']); + this.route.params.subscribe(params => this.portId = params['port']); + + const portDataObjectKey = 'portDataObject_' + this.switchId + '_' + this.portId; + this.portDataObject = JSON.parse(localStorage.getItem(portDataObjectKey)); + this.portForm = this.formBuiler.group({ + portStatus: [this.portDataObject.status], + }); + const switchDetailsKey = 'switchDetailsKey_' + this.switchId; + this.retrievedSwitchObject = JSON.parse(localStorage.getItem(switchDetailsKey)); + this.port_src_switch = this.maskPipe.transform(this.retrievedSwitchObject.switch_id, 'legacy'); + this.clipBoardItems.sourceSwitch = this.retrievedSwitchObject.switch_id; + + if (this.portDataObject['discrepancy'] && (this.portDataObject['discrepancy']['assignment-type'])) { + if (this.portDataObject['discrepancy']['assignment-type']) { + this.assignmentTypeDescrepancy = true; + this.descrepancyData.assignmentType.controller = (typeof (this.portDataObject['discrepancy']['controller-assignment-type']) != 'undefined') ? this.portDataObject['discrepancy']['controller-assignment-type'] : '-'; + this.descrepancyData.assignmentType.inventory = (typeof (this.portDataObject['discrepancy']['inventory-assignment-type']) != 'undefined') ? this.portDataObject['discrepancy']['inventory-assignment-type'] : '-'; + } + + } + + this.router.events + .pipe(filter(event => event instanceof NavigationEnd)).pipe(filter(event => event instanceof NavigationEnd)) + .subscribe(event => { + const tempRoute: any = event; + if (tempRoute.url.includes('/port')) { + this.currentRoute = 'port-details'; + } else { + this.currentRoute = 'switch-details'; + } + }); + this.loadPortFlows(); + this.getDiscoveryPackets(); } - this.router.events - .pipe(filter(event => event instanceof NavigationEnd)) .pipe(filter(event => event instanceof NavigationEnd)) - .subscribe(event => { - const tempRoute: any = event; - if (tempRoute.url.includes('/port')) { - this.currentRoute = 'port-details'; + getDiscoveryPackets() { + this.switchService.getdiscoveryPackets(this.retrievedSwitchObject.switch_id, this.portDataObject.port_number).subscribe((response: any) => { + this.discoverypackets = response.discovery_enabled; + }, error => { + // this.toastr.error('Error in updating discovery packets mode! ','Error'); + }); + } + + maskSwitchId(switchType, e) { + if (e.target.checked) { + this.retrievedSwitchObject.switch_id = this.maskPipe.transform(this.retrievedSwitchObject.switch_id, 'legacy'); } else { - this.currentRoute = 'switch-details'; + this.retrievedSwitchObject.switch_id = this.maskPipe.transform(this.retrievedSwitchObject.switch_id, 'kilda'); } - }); - this.loadPortFlows(); - this.getDiscoveryPackets(); - } - - getDiscoveryPackets() { - this.switchService.getdiscoveryPackets(this.retrievedSwitchObject.switch_id, this.portDataObject.port_number).subscribe((response: any) => { - this.discoverypackets = response.discovery_enabled; - }, error => { - // this.toastr.error('Error in updating discovery packets mode! ','Error'); - }); - } - - maskSwitchId(switchType, e) { - if (e.target.checked) { - this.retrievedSwitchObject.switch_id = this.maskPipe.transform(this.retrievedSwitchObject.switch_id, 'legacy'); - } else { - this.retrievedSwitchObject.switch_id = this.maskPipe.transform(this.retrievedSwitchObject.switch_id, 'kilda'); - } - this.clipBoardItems.sourceSwitch = this.retrievedSwitchObject.switch_id; - } + this.clipBoardItems.sourceSwitch = this.retrievedSwitchObject.switch_id; + } - savePortDetails() { + savePortDetails() { - this.currentPortState = this.portDataObject.status; - this.requestedPortState = this.portForm.value.portStatus; - $('#old_status_val').text(this.portDataObject.status); - $('#new_status_val').text(this.portForm.value.portStatus); + this.currentPortState = this.portDataObject.status; + this.requestedPortState = this.portForm.value.portStatus; + $('#old_status_val').text(this.portDataObject.status); + $('#new_status_val').text(this.portForm.value.portStatus); - if (this.currentPortState == this.requestedPortState) { - this.toastr.info(MessageObj.nothing_changed, 'Information'); - } else { + if (this.currentPortState == this.requestedPortState) { + this.toastr.info(MessageObj.nothing_changed, 'Information'); + } else { - const modalRef = this.modalService.open(ModalconfirmationComponent); - modalRef.componentInstance.title = 'Confirmation'; - modalRef.componentInstance.content = $('#final_configure_confirm_modal')[0].innerHTML; + const modalRef = this.modalService.open(ModalconfirmationComponent); + modalRef.componentInstance.title = 'Confirmation'; + modalRef.componentInstance.content = $('#final_configure_confirm_modal')[0].innerHTML; - modalRef.result.then((response) => { - if (response && response == true) { - this.loaderService.show(MessageObj.updating_port_details); - this.commitConfig(); + modalRef.result.then((response) => { + if (response && response == true) { + this.loaderService.show(MessageObj.updating_port_details); + this.commitConfig(); + } + }); } - }); - } - } - - getPortStatus = (status) => { - if (status.toLowerCase() == 'good') { - return 'UP'; - } else if (status.toLowerCase() == 'bad') { - return 'DOWN'; } - return status; - - } - - commitConfig() { - const portStatus = this.portForm.value.portStatus; - this.switchService.configurePort(this.retrievedSwitchObject.switch_id, - this.portDataObject.port_number, - portStatus).subscribe(status => { - this.loaderService.hide(); - this.toastr.success(MessageObj.port_configured, 'Success'); - this.portDataObject.status = portStatus; - const portDataObjectKey = 'portDataObject_' + this.switchId + '_' + this.portId; - localStorage.setItem(portDataObjectKey, JSON.stringify(this.portDataObject)); - this.editConfigStatus = false; - }, error => { - this.loaderService.hide(); - this.editConfigStatus = false; - if (error.status == '500') { - this.toastr.error(error.error['error-auxiliary-message']); - } else { - this.toastr.error('Something went wrong!'); + getPortStatus = (status) => { + if (status.toLowerCase() == 'good') { + return 'UP'; + } else if (status.toLowerCase() == 'bad') { + return 'DOWN'; } - }); - } - - enableDisableDiscoveryPackets(e) { - const modalRef = this.modalService.open(ModalconfirmationComponent); - modalRef.componentInstance.title = 'Confirmation'; - modalRef.componentInstance.content = 'Are you sure you want to update discovery packets value?'; - const OldValue = this.discoverypackets; - this.discoverypackets = e.target.checked; - modalRef.result.then((response) => { - if (response && response == true) { - this.loaderService.show(MessageObj.updating_discovery_flag); - this.switchService.updatediscoveryPackets(this.retrievedSwitchObject.switch_id, this.portDataObject.port_number, this.discoverypackets).subscribe((response) => { - this.toastr.success(MessageObj.discovery_packets_updated, 'Success'); - this.loaderService.hide(); - this.discoverypackets = e.target.checked; - }, error => { - this.discoverypackets = OldValue; - this.loaderService.hide(); - this.toastr.error(MessageObj.error_updating_discovery_packets, 'Error'); - }); - } else { - this.discoverypackets = OldValue; + return status; + } - }); - } - - configurePortDetails() { - const modalRef = this.modalService.open(ModalconfirmationComponent); - modalRef.componentInstance.title = 'Confirmation'; - modalRef.componentInstance.content = 'Are you sure you want to configure the port?'; - modalRef.result.then((response) => { - if (response && response == true) { - this.editConfigStatus = true; - this.portForm = this.formBuiler.group({ - portStatus: [this.portDataObject.status], - }); - } - }); - } - - loadPortFlows() { - if (this.portDataObject['port_number'] && (this.retrievedSwitchObject['switch_id'])) { - const switchId = this.retrievedSwitchObject.switch_id; - const portnumber = this.portDataObject.port_number; - this.flowBandwidthFlag = true; - this.switchService.getSwitchFlows(switchId, false, portnumber).subscribe(data => { - this.portFlows = data; - if (this.portFlows && this.portFlows.length) { - for (const flow of this.portFlows) { - this.flowBandwidthSum = this.flowBandwidthSum + (flow.maximum_bandwidth / 1000); + + commitConfig() { + const portStatus = this.portForm.value.portStatus; + this.switchService.configurePort(this.retrievedSwitchObject.switch_id, + this.portDataObject.port_number, + portStatus).subscribe(status => { + this.loaderService.hide(); + this.toastr.success(MessageObj.port_configured, 'Success'); + this.portDataObject.status = portStatus; + const portDataObjectKey = 'portDataObject_' + this.switchId + '_' + this.portId; + localStorage.setItem(portDataObjectKey, JSON.stringify(this.portDataObject)); + this.editConfigStatus = false; + + }, error => { + this.loaderService.hide(); + this.editConfigStatus = false; + if (error.status == '500') { + this.toastr.error(error.error['error-auxiliary-message']); + } else { + this.toastr.error('Something went wrong!'); } - } else { - if (this.portFlows == null) { - this.portFlows = []; + }); + } + + enableDisableDiscoveryPackets(e) { + const modalRef = this.modalService.open(ModalconfirmationComponent); + modalRef.componentInstance.title = 'Confirmation'; + modalRef.componentInstance.content = 'Are you sure you want to update discovery packets value?'; + const OldValue = this.discoverypackets; + this.discoverypackets = e.target.checked; + modalRef.result.then((response) => { + if (response && response == true) { + this.loaderService.show(MessageObj.updating_discovery_flag); + this.switchService.updatediscoveryPackets(this.retrievedSwitchObject.switch_id, this.portDataObject.port_number, this.discoverypackets).subscribe((response) => { + this.toastr.success(MessageObj.discovery_packets_updated, 'Success'); + this.loaderService.hide(); + this.discoverypackets = e.target.checked; + }, error => { + this.discoverypackets = OldValue; + this.loaderService.hide(); + this.toastr.error(MessageObj.error_updating_discovery_packets, 'Error'); + }); + } else { + this.discoverypackets = OldValue; } - } - if (this.flowBandwidthSum) { - this.flowBandwidthSum = this.flowBandwidthSum.toFixed(3); - } + }); + } - this.flowBandwidthFlag = false; - }, error => { - this.portFlows = []; - this.flowBandwidthSum = 0; - this.flowBandwidthFlag = false; + configurePortDetails() { + const modalRef = this.modalService.open(ModalconfirmationComponent); + modalRef.componentInstance.title = 'Confirmation'; + modalRef.componentInstance.content = 'Are you sure you want to configure the port?'; + modalRef.result.then((response) => { + if (response && response == true) { + this.editConfigStatus = true; + this.portForm = this.formBuiler.group({ + portStatus: [this.portDataObject.status], + }); + } }); } - } + loadPortFlows() { + if (this.portDataObject['port_number'] && (this.retrievedSwitchObject['switch_id'])) { + const switchId = this.retrievedSwitchObject.switch_id; + const portnumber = this.portDataObject.port_number; + this.flowBandwidthFlag = true; + this.switchService.getSwitchFlows(switchId, false, portnumber).subscribe(data => { + this.portFlows = data; + if (this.portFlows && this.portFlows.length) { + for (const flow of this.portFlows) { + this.flowBandwidthSum = this.flowBandwidthSum + (flow.maximum_bandwidth / 1000); + } + } else { + if (this.portFlows == null) { + this.portFlows = []; + } + } + if (this.flowBandwidthSum) { + this.flowBandwidthSum = this.flowBandwidthSum.toFixed(3); + } + + this.flowBandwidthFlag = false; + }, error => { + this.portFlows = []; + this.flowBandwidthSum = 0; + this.flowBandwidthFlag = false; + }); + } + } - cancelConfigurePort() { - this.editConfigStatus = false; - } - copyToClip(event, copyItem) { - this.clipboardService.copyFromContent(this.clipBoardItems[copyItem]); - } + cancelConfigurePort() { + this.editConfigStatus = false; + } - toggleTab(tab) { - this.openedTab = tab; - } + copyToClip(event, copyItem) { + this.clipboardService.copyFromContent(this.clipBoardItems[copyItem]); + } - assignDate(timestamp) { - if (timestamp) { - return moment(timestamp * 1000).format('LLL'); - } else { - return '-'; + toggleTab(tab) { + this.openedTab = tab; } + assignDate(timestamp) { + if (timestamp) { + return moment(timestamp * 1000).format('LLL'); + } else { + return '-'; + } + } - } + deleteLogicalPort() { + const modalRef = this.modalService.open(ModalconfirmationComponent); + modalRef.componentInstance.title = 'Delete Port'; + modalRef.componentInstance.content = 'Are you sure you want to perform delete action ?'; + modalRef.result.then((response) => { + if (response && response == true) { + this.switchService.deleteLagLogicalPort(this.retrievedSwitchObject.switch_id, this.portDataObject.port_number).subscribe(res => { + modalRef.close(); + this.toastr.success(MessageObj.port_deleted, 'Success!'); + this.router.navigate(['/switches/details/' + this.retrievedSwitchObject.switch_id]); + }, error => { + this.loaderService.hide(); + const message = `${error.error['error-auxiliary-message'] + ','} ${error.error['error-description']}`; + this.toastr.error(message, 'Error'); + }); + } + }); + } - ngOnDestroy() { - localStorage.setItem('portLoaderEnabled', '1'); - } + ngOnDestroy() { + localStorage.setItem('portLoaderEnabled', '1'); + } } diff --git a/src-gui/ui/src/app/modules/switches/port-list/port-list.component.html b/src-gui/ui/src/app/modules/switches/port-list/port-list.component.html index a8a57d1929a..11c894dbaf2 100644 --- a/src-gui/ui/src/app/modules/switches/port-list/port-list.component.html +++ b/src-gui/ui/src/app/modules/switches/port-list/port-list.component.html @@ -20,6 +20,9 @@
+
+ +