From f4cc606fe5b52061083638326cdb7c4b9759df80 Mon Sep 17 00:00:00 2001 From: "K.V Suneelu Verma" Date: Fri, 15 Dec 2017 16:36:00 +0530 Subject: [PATCH] OVSDB-438: missing operational node Handle the following scenarios client connects to only one odl controller via ha proxy 1) client disconnects and connects back to same node after some delay 2) client disconnects and connects back to same node immediately 3) client disconnects and connects to another node after some delay 4) client disconnects and connects to another node immediately 5) client disconnects and never connects back When client disconnects all the odl controllers are trying to cleanup the oper node. When client connects the owner odl controller is trying to create the oper node. When the processing of one odl controller which is trying to cleanup the opernode is delayed , then we end up client node missing in oper topology. Fix Listen for oper node removal and if some client is still connected then recreate it. Change-Id: Ib88e8385f199c2105c51ce49e01e4318c1ae1463 Signed-off-by: K.V Suneelu Verma --- .../HwvtepConnectionInstance.java | 5 + .../HwvtepConnectionManager.java | 67 ++++++--- .../HwvtepOperGlobalListener.java | 136 ++++++++++++++++++ .../HwvtepSouthboundUtil.java | 8 ++ .../hwvtepsouthbound/HwvtepTableReader.java | 77 ++++++++++ .../md/HwvtepLogicalSwitchUpdateCommand.java | 3 +- 6 files changed, 277 insertions(+), 19 deletions(-) create mode 100644 hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperGlobalListener.java diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java index 30e17d2cb..5d07adf5e 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java @@ -314,4 +314,9 @@ public class HwvtepConnectionInstance { public HwvtepTableReader getHwvtepTableReader() { return hwvtepTableReader; } + + public void refreshOperNode() throws ExecutionException, InterruptedException { + TableUpdates tableUpdates = hwvtepTableReader.readAllTables(); + callback.update(tableUpdates, getDatabaseSchema(HwvtepSchemaConstants.HARDWARE_VTEP)); + } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java index cd0c9c45b..4a07e20f7 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java @@ -60,6 +60,7 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -82,6 +83,7 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo private final ReconciliationManager reconciliationManager; private final Map, HwvtepConnectionInstance> nodeIidVsConnectionInstance = new ConcurrentHashMap<>(); + private HwvtepOperGlobalListener hwvtepOperGlobalListener; public HwvtepConnectionManager(DataBroker db, TransactionInvoker txInvoker, EntityOwnershipService entityOwnershipService) { @@ -90,6 +92,7 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo this.entityOwnershipService = entityOwnershipService; this.hwvtepDeviceEntityOwnershipListener = new HwvtepDeviceEntityOwnershipListener(this,entityOwnershipService); this.reconciliationManager = new ReconciliationManager(db); + this.hwvtepOperGlobalListener = new HwvtepOperGlobalListener(db, this); } @Override @@ -141,10 +144,13 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo // not be used as a candidate in Entity election (given that this instance is // about to disconnect as well), if current owner get disconnected from // HWVTEP device. - unregisterEntityForOwnership(hwvtepConnectionInstance); - - //TODO: remove all the hwvtep nodes - txInvoker.invoke(new HwvtepGlobalRemoveCommand(hwvtepConnectionInstance, null, null)); + if (hwvtepConnectionInstance.getHasDeviceOwnership()) { + unregisterEntityForOwnership(hwvtepConnectionInstance); + txInvoker.invoke(new HwvtepGlobalRemoveCommand(hwvtepConnectionInstance, null, null)); + } else { + unregisterEntityForOwnership(hwvtepConnectionInstance); + //Do not delete if client disconnected from follower HwvtepGlobalRemoveCommand + } removeConnectionInstance(key); @@ -319,6 +325,10 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo private void registerEntityForOwnership(HwvtepConnectionInstance hwvtepConnectionInstance) { Entity candidateEntity = getEntityFromConnectionInstance(hwvtepConnectionInstance); + if (entityConnectionMap.get(candidateEntity) != null) { + disconnected(entityConnectionMap.get(candidateEntity).getOvsdbClient()); + putConnectionInstance(hwvtepConnectionInstance.getInstanceIdentifier(), hwvtepConnectionInstance); + } entityConnectionMap.put(candidateEntity, hwvtepConnectionInstance); hwvtepConnectionInstance.setConnectedEntity(candidateEntity); @@ -330,25 +340,41 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo //If entity already has owner, it won't get notification from EntityOwnershipService //so cache the connection instances. - Optional ownershipStateOpt = - entityOwnershipService.getOwnershipState(candidateEntity); - if (ownershipStateOpt.isPresent()) { - EntityOwnershipState ownershipState = ownershipStateOpt.get(); - if (ownershipState.hasOwner() && !ownershipState.isOwner()) { - if (getConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo()) != null) { - LOG.info("OVSDB entity {} is already owned by other southbound plugin " - + "instance, so *this* instance is NOT an OWNER of the device", - hwvtepConnectionInstance.getConnectionInfo()); - putConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo(),hwvtepConnectionInstance); - } - } - } + handleOwnershipState(candidateEntity, hwvtepConnectionInstance); } catch (CandidateAlreadyRegisteredException e) { LOG.warn("OVSDB entity {} was already registered for ownership", candidateEntity, e); } } + private void handleOwnershipState(Entity candidateEntity, HwvtepConnectionInstance hwvtepConnectionInstance) { + //If entity already has owner, it won't get notification from EntityOwnershipService + //so cache the connection instances. + Optional ownershipStateOpt = + entityOwnershipService.getOwnershipState(candidateEntity); + if (ownershipStateOpt.isPresent()) { + EntityOwnershipState ownershipState = ownershipStateOpt.get(); + putConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo(), hwvtepConnectionInstance); + if (ownershipState.hasOwner()) { + hwvtepConnectionInstance.setHasDeviceOwnership(ownershipState.isOwner()); + if (!ownershipState.isOwner()) { + LOG.info("HWVTEP entity {} is already owned by other southbound plugin " + + "instance, so *this* instance is NOT an OWNER of the device", + hwvtepConnectionInstance.getConnectionInfo()); + } else { + afterTakingOwnership(hwvtepConnectionInstance); + } + } + } + } + + private void afterTakingOwnership(HwvtepConnectionInstance hwvtepConnectionInstance) { + txInvoker.invoke(new HwvtepGlobalRemoveCommand(hwvtepConnectionInstance, null, null)); + putConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo(), hwvtepConnectionInstance); + hwvtepConnectionInstance.setHasDeviceOwnership(true); + hwvtepConnectionInstance.registerCallbacks(); + } + private Global getHwvtepGlobalTableEntry(HwvtepConnectionInstance connectionInstance) { DatabaseSchema dbSchema = null; Global globalRow = null; @@ -452,6 +478,11 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo @Override public void onSuccess(@Nullable Optional node) { if (node.isPresent()) { + HwvtepGlobalAugmentation augmentation = node.get() + .getAugmentation(HwvtepGlobalAugmentation.class); + if (augmentation == null || augmentation.getConnectionInfo() == null) { + return; + } LOG.info("Disconnected/Failed connection {} was controller initiated, attempting " + "reconnection", hwvtepNode.getConnectionInfo()); reconciliationManager.enqueue(task); @@ -518,7 +549,7 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo //*this* instance of southbound plugin is owner of the device, //so register for monitor callbacks - hwvtepConnectionInstance.registerCallbacks(); + afterTakingOwnership(hwvtepConnectionInstance); } else { //You were owner of the device, but now you are not. With the current ownership diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperGlobalListener.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperGlobalListener.java new file mode 100644 index 000000000..13b71fb17 --- /dev/null +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperGlobalListener.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.ovsdb.hwvtepsouthbound; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.ovsdb.lib.message.TableUpdates; +import org.opendaylight.ovsdb.lib.schema.DatabaseSchema; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HwvtepOperGlobalListener implements ClusteredDataTreeChangeListener, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(HwvtepOperGlobalListener.class); + + private Timer timer = new Timer(); + private ListenerRegistration registration; + private HwvtepConnectionManager hcm; + private DataBroker db; + private Map connectedNodes = new ConcurrentHashMap<>(); + + HwvtepOperGlobalListener(DataBroker db, HwvtepConnectionManager hcm) { + LOG.info("Registering HwvtepOperGlobalListener"); + this.db = db; + this.hcm = hcm; + registerListener(db); + } + + private void registerListener(final DataBroker db) { + final DataTreeIdentifier treeId = + new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, getWildcardPath()); + try { + registration = db.registerDataTreeChangeListener(treeId, HwvtepOperGlobalListener.this); + } catch (final Exception e) { + LOG.error("HwvtepDataChangeListener registration failed", e); + } + } + + @Override + public void close() throws Exception { + if(registration != null) { + registration.close(); + } + } + + @Override + public void onDataTreeChanged(Collection> changes) { + changes.forEach( (change) -> { + InstanceIdentifier key = change.getRootPath().getRootIdentifier(); + DataObjectModification mod = change.getRootNode(); + InstanceIdentifier nodeIid = change.getRootPath().getRootIdentifier(); + YangInstanceIdentifier entityId = + HwvtepSouthboundUtil.getInstanceIdentifierCodec().getYangInstanceIdentifier(nodeIid); + Node node = getCreated(mod); + if (node != null) { + connectedNodes.put(entityId, node); + } + node = getRemoved(mod); + if (node != null) { + connectedNodes.remove(entityId); + HwvtepConnectionInstance connectionInstance = hcm.getConnectionInstanceFromNodeIid(nodeIid); + if (Objects.equals(connectionInstance.getConnectionInfo().getRemotePort(), + HwvtepSouthboundUtil.getRemotePort(node))) { + //Oops some one deleted the node held by me This should never happen + try { + connectionInstance.refreshOperNode(); + } catch (ExecutionException | InterruptedException e) { + LOG.error("Failed to refresh operational nodes ", e); + } + } + + } + }); + } + + private Node getCreated(DataObjectModification mod) { + if((mod.getModificationType() == ModificationType.WRITE) + && (mod.getDataBefore() == null)){ + return mod.getDataAfter(); + } + return null; + } + + private Node getRemoved(DataObjectModification mod) { + if(mod.getModificationType() == ModificationType.DELETE){ + return mod.getDataBefore(); + } + return null; + } + + public Map getConnectedNodes() { + return Collections.unmodifiableMap(connectedNodes); + } + + private InstanceIdentifier getWildcardPath() { + InstanceIdentifier path = InstanceIdentifier + .create(NetworkTopology.class) + .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID)) + .child(Node.class); + return path; + } +} diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java index d38363959..aa6804f07 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java @@ -205,4 +205,12 @@ public class HwvtepSouthboundUtil { } return physicalNodeIid.firstIdentifierOf(Topology.class).child(Node.class , new NodeKey(new NodeId(nodeId))); } + + public static Integer getRemotePort(Node node) { + HwvtepGlobalAugmentation augmentation = node.getAugmentation(HwvtepGlobalAugmentation.class); + if (augmentation != null && augmentation.getConnectionInfo() != null) { + return augmentation.getConnectionInfo().getRemotePort().getValue(); + } + return 0; + } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepTableReader.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepTableReader.java index 1ba42fa83..7e1bba3cb 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepTableReader.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepTableReader.java @@ -10,6 +10,7 @@ package org.opendaylight.ovsdb.hwvtepsouthbound; import com.google.common.collect.Lists; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -17,7 +18,10 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.function.Function; +import java.util.stream.Collectors; +import org.opendaylight.ovsdb.lib.message.TableUpdate; +import org.opendaylight.ovsdb.lib.message.TableUpdates; import org.opendaylight.ovsdb.lib.notation.Condition; import org.opendaylight.ovsdb.lib.notation.Row; import org.opendaylight.ovsdb.lib.notation.UUID; @@ -28,9 +32,22 @@ import org.opendaylight.ovsdb.lib.schema.DatabaseSchema; import org.opendaylight.ovsdb.lib.schema.GenericTableSchema; import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable; import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils; +import org.opendaylight.ovsdb.schema.hardwarevtep.ACL; +import org.opendaylight.ovsdb.schema.hardwarevtep.ACLEntry; +import org.opendaylight.ovsdb.schema.hardwarevtep.ArpSourcesLocal; +import org.opendaylight.ovsdb.schema.hardwarevtep.ArpSourcesRemote; +import org.opendaylight.ovsdb.schema.hardwarevtep.Global; +import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalRouter; import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch; +import org.opendaylight.ovsdb.schema.hardwarevtep.Manager; +import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsLocal; import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote; import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocator; +import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocatorSet; +import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalPort; +import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch; +import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel; +import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsLocal; import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs; @@ -47,6 +64,26 @@ public class HwvtepTableReader { private static final Logger LOG = LoggerFactory.getLogger(HwvtepTableReader.class); + private final Class alltables[] = new Class[] { + ACLEntry.class, + ACL.class, + ArpSourcesLocal.class, + Global.class, + ArpSourcesRemote.class, + LogicalRouter.class, + Manager.class, + LogicalSwitch.class, + McastMacsLocal.class, + PhysicalLocator.class, + McastMacsRemote.class, + PhysicalPort.class, + Tunnel.class, + PhysicalLocatorSet.class, + PhysicalSwitch.class, + UcastMacsLocal.class, + UcastMacsRemote.class + }; + private final Map>> whereClauseGetterMap = new HashMap(); private final Map tableMap = new HashMap(); private final Map tables = new HashMap<>(); @@ -258,4 +295,44 @@ public class HwvtepTableReader { } return Collections.emptyList(); } + + public TableUpdates readAllTables() throws ExecutionException, InterruptedException { + Map tableUpdates = new HashMap<>(); + DatabaseSchema dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get(); + + List operations = Arrays.asList(alltables).stream() + .map(tableClass -> TyperUtils.getTableSchema(dbSchema, tableClass)) + .map(tableSchema -> buildSelectOperationFor(tableSchema)) + .collect(Collectors.toList()); + + List results = connectionInstance.transact(dbSchema, operations).get(); + if (results != null && !results.isEmpty()) { + results.stream() + .filter(result -> result.getRows() != null) + .flatMap(result -> result.getRows().stream()) + .forEach(row -> { + tableUpdates.compute(row.getTableSchema().getName(), (tableName, tableUpdate) -> { + if (tableUpdate == null) { + tableUpdate = new TableUpdate(); + } + tableUpdate.addRow(getRowUuid(row), null, row); + return tableUpdate; + }); + }); + } + return new TableUpdates(tableUpdates); + } + + private Select buildSelectOperationFor(GenericTableSchema tableSchema) { + Select selectOpearation = op.select(tableSchema); + selectOpearation.setColumns(new ArrayList<>(tableSchema.getColumns())); + return selectOpearation; + } + + private UUID getRowUuid(Row row) { + return row.getColumns().stream() + .filter(column -> column.getSchema().getName().equals("_uuid")) + .map(column -> (UUID) column.getData()) + .findFirst().orElse(new UUID("test")); + } } \ No newline at end of file diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepLogicalSwitchUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepLogicalSwitchUpdateCommand.java index d9d21dfb6..c00f79145 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepLogicalSwitchUpdateCommand.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepLogicalSwitchUpdateCommand.java @@ -87,8 +87,9 @@ public class HwvtepLogicalSwitchUpdateCommand extends AbstractTransactionCommand if (dbVersion.compareTo(minVersion) >= 0) { if (lSwitch.getReplicationModeColumn().getData() != null && !lSwitch.getReplicationModeColumn().getData().isEmpty()) { lsBuilder.setReplicationMode(lSwitch.getReplicationModeColumn().getData().iterator().next()); + LOG.debug("setReplicationMode to: {}", + lSwitch.getReplicationModeColumn().getData().iterator().next()); } - LOG.debug("setReplicationMode to: {}", lSwitch.getReplicationModeColumn().getData().iterator().next()); } } HwvtepNodeName hwvtepName = new HwvtepNodeName(lSwitch.getName()); -- 2.36.6