Added Dependency Queue which gets processed upon config and op events.
Any object ( mac / port ) whose dependencies are not met gets pushed the
queue with an expiry timeout.
Added the following apis in UnMetDependencyGetter
getInTransitDependencies returns list of keys in json rpc transaction
which are needed by this object to be processed.
getUnMetConfigDependencies returns list of missing config keys
Added the following apis in HwvtepDeviceInfo
onConfigDataAvailable processes config dependency queue
onOpDataAvailable processes in transit dependency queue , gets called
after every json rpc transaction is done
Change-Id: I012958a40e0ab0aa0e0db14dc670f9c4dacbdd09
Signed-off-by: K.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
<failsOnError>true</failsOnError>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <forkCount>1</forkCount>
+ <reuseForks>false</reuseForks>
+ </configuration>
+ </plugin>
</plugins>
</build>
package org.opendaylight.ovsdb.hwvtepsouthbound;
-import static org.opendaylight.ovsdb.lib.operations.Operations.op;
-
-import java.net.ConnectException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.ovsdb.hwvtepsouthbound.reconciliation.ReconciliationTask;
import org.opendaylight.ovsdb.hwvtepsouthbound.reconciliation.configuration.HwvtepReconciliationTask;
import org.opendaylight.ovsdb.hwvtepsouthbound.reconciliation.connection.ConnectionReconciliationTask;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependencyQueue;
import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.HwvtepGlobalRemoveCommand;
import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionCommand;
import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
-import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchAttributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.net.ConnectException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoCloseable{
private Map<ConnectionInfo, HwvtepConnectionInstance> clients = new ConcurrentHashMap<>();
for (HwvtepConnectionInstance client: clients.values()) {
client.disconnect();
}
+ DependencyQueue.close();
}
@Override
changesByConnectionInstance(changes).entrySet()) {
HwvtepConnectionInstance connectionInstance = changesEntry.getKey();
connectionInstance.transact(new TransactCommandAggregator(
- new HwvtepOperationalState(db, changesEntry.getValue()),changesEntry.getValue()));
+ new HwvtepOperationalState(db, connectionInstance, changesEntry.getValue()),changesEntry.getValue()));
+ connectionInstance.getDeviceInfo().onConfigDataAvailable();
}
}
package org.opendaylight.ovsdb.hwvtepsouthbound;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependencyQueue;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependentJob;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocator;
private final Object data;
private final DeviceDataStatus status;
- public DeviceData(InstanceIdentifier key, UUID uuid, Object data, DeviceDataStatus status) {
+ DeviceData(InstanceIdentifier key, UUID uuid, Object data, DeviceDataStatus status) {
this.data = data;
this.key = key;
this.status = status;
private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> configKeyVsData = new ConcurrentHashMap<>();
private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> opKeyVsData = new ConcurrentHashMap<>();
private Map<Class<? extends Identifiable>, Map<UUID, Object>> uuidVsData = new ConcurrentHashMap<>();
+ private DependencyQueue dependencyQueue;
public HwvtepDeviceInfo(HwvtepConnectionInstance hwvtepConnectionInstance) {
this.connectionInstance = hwvtepConnectionInstance;
this.physicalSwitches = new HashMap<>();
this.physicalLocators = new HashMap<>();
this.mapTunnelToPhysicalSwitch = new HashMap<>();
+ this.dependencyQueue = new DependencyQueue(this);
}
public void putLogicalSwitch(UUID uuid, LogicalSwitch lSwitch) {
}
return null;
}
+
+ public <T extends Identifiable> void addJobToQueue(DependentJob<T> job) {
+ dependencyQueue.addToQueue(job);
+ }
+
+ public void onConfigDataAvailable() {
+ dependencyQueue.processReadyJobsFromConfigQueue(connectionInstance);
+ }
+
+ public void onOpDataAvailable() {
+ dependencyQueue.processReadyJobsFromOpQueue(connectionInstance);
+ }
}
= new ImmutableMap.Builder<String,List<String>>()
.put("Manager", Arrays.asList(new String[]{"_version", "status"}))
.build();
+ public static final int WAITING_QUEUE_CAPACITY = 1000;
+ public static final long WAITING_JOB_EXPIRY_TIME_MILLIS = 90000;
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
map.get(cls).remove(key);
}
}
+
+ public static <T> boolean isEmpty(List<T> list) {
+ return list == null || list.isEmpty();
+ }
}
}
private void transactChangesToDevice(Collection<DataTreeModification<Node>> changes) {
- HwvtepOperationalState hwvtepOperationalState = new HwvtepOperationalState(db, changes);
+ HwvtepOperationalState hwvtepOperationalState = new HwvtepOperationalState(db, connectionInstance, changes);
connectionInstance.transact(new TransactCommandAggregator(hwvtepOperationalState,changes));
}
package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
-import java.util.Collection;
-
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.Collection;
+import java.util.Map;
-public abstract class AbstractTransactCommand implements TransactCommand {
+public abstract class AbstractTransactCommand<T extends Identifiable> implements TransactCommand<T> {
private HwvtepOperationalState operationalState;
private Collection<DataTreeModification<Node>> changes;
public Collection<DataTreeModification<Node>> getChanges() {
return changes;
}
+
+ void updateCurrentTxData(Class<? extends Identifiable> cls, InstanceIdentifier key, UUID uuid, Object data) {
+ operationalState.updateCurrentTxData(cls, key, uuid);
+ operationalState.getDeviceInfo().markKeyAsInTransit(cls, key);
+ operationalState.getDeviceInfo().updateConfigData(cls, key, data);
+ }
+
+ void processDependencies(UnMetDependencyGetter<T> unMetDependencyGetter,
+ TransactionBuilder transaction,
+ final InstanceIdentifier<Node> nodeIid,
+ final InstanceIdentifier key,
+ final T data) {
+
+ HwvtepDeviceInfo deviceInfo = operationalState.getDeviceInfo();
+ Map inTransitDependencies = unMetDependencyGetter.getInTransitDependencies(operationalState, data);
+ Map confingDependencies = unMetDependencyGetter.getUnMetConfigDependencies(operationalState, data);
+ //we can skip the config termination point dependency as we can create them in device as part of this tx
+ confingDependencies.remove(TerminationPoint.class);
+
+ if (confingDependencies.isEmpty() && inTransitDependencies.isEmpty()) {
+ doDeviceTransaction(transaction, nodeIid, data);
+ }
+ if (!confingDependencies.isEmpty()) {
+ DependentJob<T> configWaitingJob = new DependentJob.ConfigWaitingJob(
+ key, data, confingDependencies) {
+
+ @Override
+ public void onDependencyResolved(HwvtepOperationalState operationalState,
+ TransactionBuilder transactionBuilder) {
+ AbstractTransactCommand.this.operationalState = operationalState;
+ onConfigUpdate(transactionBuilder, nodeIid, data);
+ }
+ };
+ deviceInfo.addJobToQueue(configWaitingJob);
+ }
+ if (inTransitDependencies.size() > 0) {
+ DependentJob<T> opWaitingJob = new DependentJob.OpWaitingJob(
+ key, data, inTransitDependencies) {
+
+ @Override
+ public void onDependencyResolved(HwvtepOperationalState operationalState,
+ TransactionBuilder transactionBuilder) {
+ AbstractTransactCommand.this.operationalState = operationalState;
+ onConfigUpdate(transactionBuilder, nodeIid, data);
+ }
+ };
+ deviceInfo.addJobToQueue(opWaitingJob);
+ }
+ }
+
+ public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier<Node> nodeIid, T data) {
+ //tobe removed as part of refactoring patch
+ }
+
+ public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier<Node> nodeIid, T data) {
+ //tobe removed as part of refactoring patch
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.transact;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+
+public class DependencyQueue {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DependencyQueue.class);
+ private static final ThreadFactory threadFact = new ThreadFactoryBuilder().setNameFormat("hwvtep-waiting-job-%d").
+ build();
+ private static final ExecutorService executorService = Executors.newSingleThreadScheduledExecutor(threadFact);
+
+ private final LinkedBlockingQueue<DependentJob> configWaitQueue = new LinkedBlockingQueue<>(
+ HwvtepSouthboundConstants.WAITING_QUEUE_CAPACITY);
+ private final LinkedBlockingQueue<DependentJob> opWaitQueue = new LinkedBlockingQueue<>(
+ HwvtepSouthboundConstants.WAITING_QUEUE_CAPACITY);
+ private final HwvtepDeviceInfo deviceInfo;
+
+ public DependencyQueue(HwvtepDeviceInfo hwvtepDeviceInfo) {
+ this.deviceInfo = hwvtepDeviceInfo;
+ }
+
+ /**
+ * Tries to add the job to the waiting queue
+ * @param waitingJob The job to be enqueued
+ * @return true if it is successfully added to the queue
+ */
+ public boolean addToQueue(DependentJob waitingJob) {
+ boolean addedToQueue;
+ if (waitingJob instanceof DependentJob.ConfigWaitingJob) {
+ addedToQueue = configWaitQueue.offer(waitingJob);
+ } else {
+ addedToQueue = opWaitQueue.offer(waitingJob);
+ }
+ if (addedToQueue) {
+ LOG.debug("Added the waiting job {} to queue", waitingJob.getKey());
+ } else {
+ LOG.error("Failed to add the waiting job to queue {}", waitingJob.getKey());
+ }
+ return addedToQueue;
+ }
+
+ /**
+ * Checks if any config data dependent jobs are ready to be processed and process them
+ * @param connectionInstance The connection instance
+ */
+ public void processReadyJobsFromConfigQueue(HwvtepConnectionInstance connectionInstance) {
+ processReadyJobs(connectionInstance, configWaitQueue);
+ }
+
+ /**
+ * Checks if any operational data dependent jobs are ready to be processed and process them
+ * @param connectionInstance The connection instance
+ */
+ public void processReadyJobsFromOpQueue(HwvtepConnectionInstance connectionInstance) {
+ processReadyJobs(connectionInstance, opWaitQueue);
+ }
+
+ private void processReadyJobs(final HwvtepConnectionInstance hwvtepConnectionInstance,
+ LinkedBlockingQueue<DependentJob> queue) {
+ final List<DependentJob> readyJobs = getReadyJobs(queue);
+ if (readyJobs.size() > 0) {
+ executorService.submit(new Runnable() {
+ @Override
+ public void run() {
+ hwvtepConnectionInstance.transact(new TransactCommand() {
+ @Override
+ public void execute(TransactionBuilder transactionBuilder) {
+ HwvtepOperationalState operationalState = new HwvtepOperationalState(hwvtepConnectionInstance);
+ for (DependentJob job : readyJobs) {
+ job.onDependencyResolved(operationalState, transactionBuilder);
+ }
+ }
+
+ @Override
+ public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier nodeIid,
+ Identifiable data) {
+ }
+
+ @Override
+ public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier nodeIid,
+ Identifiable data) {
+ }
+ });
+ }
+ });
+ }
+ }
+
+ private List<DependentJob> getReadyJobs(LinkedBlockingQueue<DependentJob> queue) {
+ List<DependentJob> readyJobs = new ArrayList<>();
+ Iterator<DependentJob> jobIterator = queue.iterator();
+ while(jobIterator.hasNext()) {
+ DependentJob job = jobIterator.next();
+ long currentTime = System.currentTimeMillis();
+ if (job.isExpired(currentTime)) {
+ jobIterator.remove();
+ continue;
+ }
+ if (job.areDependenciesMet(deviceInfo)) {
+ jobIterator.remove();
+ readyJobs.add(job);
+ }
+ }
+ return readyJobs;
+ }
+
+ public static void close() {
+ executorService.shutdown();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 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.transact;
+
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.List;
+import java.util.Map;
+
+public abstract class DependentJob<T extends Identifiable> {
+
+ private final long expiryTime;
+ private final InstanceIdentifier key;
+ private final T data;
+ private final Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies;
+
+ DependentJob(InstanceIdentifier key,
+ T data, Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies) {
+ this.expiryTime = System.currentTimeMillis() + HwvtepSouthboundConstants.WAITING_JOB_EXPIRY_TIME_MILLIS;
+ this.key = key;
+ this.data = data;
+ this.dependencies = dependencies;
+ }
+
+ /**
+ * This call back method gets called when all its dependencies are resolved
+ * @param operationalState new current operational state
+ * @param transactionBuilder transaction builder to create device transaction
+ */
+ protected abstract void onDependencyResolved(HwvtepOperationalState operationalState,
+ TransactionBuilder transactionBuilder);
+
+ /**
+ * This method is to check if all the given dependency of this job or not
+ * @param deviceInfo The device info of tis job
+ * @param cls dependency type to be checked for
+ * @param iid instance identifier to be checked for
+ * @return true if the dependency is met
+ */
+ protected abstract boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class<? extends DataObject> cls,
+ InstanceIdentifier iid);
+
+ boolean isExpired(long currentTime) {
+ return currentTime > expiryTime;
+ }
+
+ /**
+ * This method checks if all the dependencies of this job or met or not
+ * @param deviceInfo The device info of this job
+ * @return true if all the dependencies are met
+ */
+ boolean areDependenciesMet(HwvtepDeviceInfo deviceInfo) {
+ for (Class<? extends DataObject> cls : dependencies.keySet()) {
+ for (InstanceIdentifier iid : dependencies.get(cls)) {
+ if (!isDependencyMet(deviceInfo, cls, iid)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public InstanceIdentifier getKey() {
+ return key;
+ }
+
+ public T getData() {
+ return data;
+ }
+
+ public abstract static class ConfigWaitingJob<T extends Identifiable> extends DependentJob {
+
+ public ConfigWaitingJob(InstanceIdentifier key, T data, Map dependencies) {
+ super(key, data, dependencies);
+ }
+
+ @Override
+ protected boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, InstanceIdentifier iid) {
+ return deviceInfo.isConfigDataAvailable(cls, iid);
+ }
+ }
+
+ public abstract static class OpWaitingJob<T extends Identifiable> extends DependentJob {
+
+ public OpWaitingJob(InstanceIdentifier key, T data, Map dependencies) {
+ super(key, data, dependencies);
+ }
+
+ @Override
+ protected boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, InstanceIdentifier iid) {
+ HwvtepDeviceInfo.DeviceData deviceData = deviceInfo.getDeviceOpData(cls, iid);
+ return deviceData == null || deviceData.getStatus() != HwvtepDeviceInfo.DeviceDataStatus.IN_TRANSIT;
+ }
+ }
+}
private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, UUID>> currentTxUUIDs = new ConcurrentHashMap<>();
private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, Boolean>> currentTxDeletedKeys = new ConcurrentHashMap<>();
- public HwvtepOperationalState(DataBroker db, Collection<DataTreeModification<Node>> changes) {
+ public HwvtepOperationalState(DataBroker db, HwvtepConnectionInstance connectionInstance,
+ Collection<DataTreeModification<Node>> changes) {
+ this.connectionInstance = connectionInstance;
+ this.deviceInfo = connectionInstance.getDeviceInfo();
Map<InstanceIdentifier<Node>, Node> nodeCreateOrUpdate =
TransactUtils.extractCreatedOrUpdatedOrRemoved(changes, Node.class);
if (nodeCreateOrUpdate != null) {
public void updateCurrentTxData(Class<? extends Identifiable> cls, InstanceIdentifier key, UUID uuid) {
HwvtepSouthboundUtil.updateData(currentTxUUIDs, cls, key, uuid);
- deviceInfo.markKeyAsInTransit(cls, key);
}
public void updateCurrentTxDeleteData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
+import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
private void updateLogicalSwitch(TransactionBuilder transaction,
InstanceIdentifier<Node> instanceIdentifier, List<LogicalSwitches> lswitchList) {
for (LogicalSwitches lswitch: lswitchList) {
+ InstanceIdentifier<LogicalSwitches> lsKey = instanceIdentifier.
+ augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class, lswitch.getKey());
LOG.debug("Creating logcial switch named: {}", lswitch.getHwvtepNodeName());
Optional<LogicalSwitches> operationalSwitchOptional =
getOperationalState().getLogicalSwitches(instanceIdentifier, lswitch.getKey());
.build());
transaction.add(op.comment("Logical Switch: Updating " + existingLogicalSwitchName));
}
+ UUID lsUuid = new UUID(TransactUtils.getLogicalSwitchId(lswitch));
+ updateCurrentTxData(LogicalSwitches.class, lsKey, lsUuid, lswitch);
}
}
package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
-import static org.opendaylight.ovsdb.lib.operations.Operations.op;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
public class McastMacsRemoteUpdateCommand extends AbstractTransactCommand {
private static final Logger LOG = LoggerFactory.getLogger(McastMacsRemoteUpdateCommand.class);
+ private static final McastMacUnMetDependencyGetter MCAST_MAC_DATA_VALIDATOR = new McastMacUnMetDependencyGetter();
public McastMacsRemoteUpdateCommand(HwvtepOperationalState state,
Collection<DataTreeModification<Node>> changes) {
}
return result;
}
+
+ static class McastMacUnMetDependencyGetter extends UnMetDependencyGetter<RemoteMcastMacs> {
+
+ public List<InstanceIdentifier<?>> getLogicalSwitchDependencies(RemoteMcastMacs data) {
+ if (data == null) {
+ return Collections.EMPTY_LIST;
+ }
+ return Lists.newArrayList(data.getLogicalSwitchRef().getValue());
+ }
+
+ public List<InstanceIdentifier<?>> getTerminationPointDependencies(RemoteMcastMacs data) {
+ if (data == null || HwvtepSouthboundUtil.isEmpty(data.getLocatorSet())) {
+ return Collections.EMPTY_LIST;
+ }
+ List<InstanceIdentifier<?>> locators = new ArrayList<>();
+ for (LocatorSet locator: data.getLocatorSet()) {
+ locators.add(locator.getLocatorRef().getValue());
+ }
+ return locators;
+ }
+ }
}
package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-public interface TransactCommand {
+public interface TransactCommand<T extends Identifiable> {
void execute(TransactionBuilder transaction);
+ void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier<Node> nodeIid, T data);
+
+ void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier<Node> nodeIid, T data);
}
package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
public class TransactCommandAggregator implements TransactCommand {
command.execute(transaction);
}
}
+
+ @Override
+ public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data) {
+ }
+
+ @Override
+ public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data) {
+ }
}
package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
-import static org.opendaylight.ovsdb.lib.operations.Operations.op;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
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.RemoteUcastMacs;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
-public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand {
+public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand<RemoteUcastMacs> {
private static final Logger LOG = LoggerFactory.getLogger(UcastMacsRemoteUpdateCommand.class);
+ private static final UcastMacUnMetDependencyGetter UCAST_MAC_DATA_VALIDATOR = new UcastMacUnMetDependencyGetter();
public UcastMacsRemoteUpdateCommand(HwvtepOperationalState state,
Collection<DataTreeModification<Node>> changes) {
}
private void updateUcastMacsRemote(TransactionBuilder transaction,
- InstanceIdentifier<Node> instanceIdentifier, List<RemoteUcastMacs> remoteUcastMacs) {
- for (RemoteUcastMacs remoteUcastMac: remoteUcastMacs) {
+ InstanceIdentifier<Node> instanceIdentifier,
+ List<RemoteUcastMacs> remoteUcastMacs) {
+ if (remoteUcastMacs == null) {
+ return;
+ }
+ for (RemoteUcastMacs remoteUcastMac : remoteUcastMacs) {
+ onConfigUpdate(transaction, instanceIdentifier, remoteUcastMac);
+ }
+ }
+
+ @Override
+ public void onConfigUpdate(TransactionBuilder transaction,
+ InstanceIdentifier<Node> nodeIid,
+ RemoteUcastMacs remoteUcastMacs) {
+ InstanceIdentifier<RemoteUcastMacs> macIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
+ child(RemoteUcastMacs.class, remoteUcastMacs.getKey());
+ //TODO uncommet in next commit
+ //processDependencies(UCAST_MAC_DATA_VALIDATOR, transaction, nodeIid, macIid, remoteUcastMacs);
+ doDeviceTransaction(transaction, nodeIid, remoteUcastMacs);
+ }
+
+ @Override
+ public void doDeviceTransaction(TransactionBuilder transaction,
+ InstanceIdentifier<Node> instanceIdentifier, RemoteUcastMacs remoteUcastMac) {
LOG.debug("Creating remoteUcastMacs, mac address: {}", remoteUcastMac.getMacEntryKey().getValue());
Optional<RemoteUcastMacs> operationalMacOptional =
getOperationalState().getRemoteUcastMacs(instanceIdentifier, remoteUcastMac.getKey());
setLogicalSwitch(ucastMacsRemote, remoteUcastMac);
if (!operationalMacOptional.isPresent()) {
setMac(ucastMacsRemote, remoteUcastMac, operationalMacOptional);
- LOG.trace("execute: creating RemotUcastMac entry: {}", ucastMacsRemote);
+ LOG.trace("doDeviceTransaction: creating RemotUcastMac entry: {}", ucastMacsRemote);
transaction.add(op.insert(ucastMacsRemote));
transaction.add(op.comment("UcastMacRemote: Creating " + remoteUcastMac.getMacEntryKey().getValue()));
} else if (operationalMacOptional.get().getMacEntryUuid() != null) {
UcastMacsRemote extraMac = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
UcastMacsRemote.class, null);
extraMac.getUuidColumn().setData(macEntryUUID);
- LOG.trace("execute: updating RemotUcastMac entry: {}", ucastMacsRemote);
+ LOG.trace("doDeviceTransaction: updating RemotUcastMac entry: {}", ucastMacsRemote);
transaction.add(op.update(ucastMacsRemote)
.where(extraMac.getUuidColumn().getSchema().opEqual(macEntryUUID))
.build());
LOG.warn("Unable to update remoteMcastMacs {} because uuid not found in the operational store",
remoteUcastMac.getMacEntryKey().getValue());
}
- }
}
private void setLogicalSwitch(UcastMacsRemote ucastMacsRemote, RemoteUcastMacs inputMac) {
}
return result;
}
+
+ static class UcastMacUnMetDependencyGetter extends UnMetDependencyGetter<RemoteUcastMacs> {
+
+ public List<InstanceIdentifier<?>> getLogicalSwitchDependencies(RemoteUcastMacs data) {
+ if (data == null) {
+ return Collections.EMPTY_LIST;
+ }
+ return Lists.newArrayList(data.getLogicalSwitchRef().getValue());
+ }
+
+ public List<InstanceIdentifier<?>> getTerminationPointDependencies(RemoteUcastMacs data) {
+ if (data == null) {
+ return Collections.EMPTY_LIST;
+ }
+ return Lists.newArrayList(data.getLocatorRef().getValue());
+ }
+ }
}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 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.transact;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+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.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Utility class to retrieve the unmet dependencies (config/operational) of the given object
+ * @param <T>
+ */
+public abstract class UnMetDependencyGetter<T extends Identifiable> {
+
+ private final ConfigDependencyGetter configDependencyGetter = new ConfigDependencyGetter();
+ private final InTransitDependencyGetter inTransitDependencyGetter = new InTransitDependencyGetter();
+
+ /**
+ * Returns the iids this data depends upon
+ * which are already intransit in the previous transaction if any
+ * @param opState The operatonal state
+ * @param data The data object
+ * @return The depenencies
+ */
+ public Map<Class<? extends Identifiable>, List<InstanceIdentifier>> getInTransitDependencies(
+ HwvtepOperationalState opState, T data) {
+ return inTransitDependencyGetter.retrieveUnMetDependencies(opState, opState.getDeviceInfo(), data);
+ }
+
+ /**
+ * Returns the iids this data depends upon
+ * which are not yet present in the config data store if any
+ * @param opState The operatonal state
+ * @param data The data object
+ * @return the depenencies
+ */
+ public Map<Class<? extends Identifiable>, List<InstanceIdentifier>> getUnMetConfigDependencies(
+ HwvtepOperationalState opState, T data) {
+ return configDependencyGetter.retrieveUnMetDependencies(opState, opState.getDeviceInfo(), data);
+ }
+
+ abstract class DependencyGetter {
+
+ Map<Class<? extends Identifiable>, List<InstanceIdentifier>> retrieveUnMetDependencies(
+ HwvtepOperationalState opState, HwvtepDeviceInfo deviceInfo, T data) {
+
+ Map<Class<? extends Identifiable>, List<InstanceIdentifier>> result = new HashMap<>();
+ Map<Class<? extends Identifiable>, List<InstanceIdentifier<?>>> allKeys = new HashMap<>();
+ allKeys.put(LogicalSwitches.class, getLogicalSwitchDependencies(data));
+ allKeys.put(TerminationPoint.class, getTerminationPointDependencies(data));
+
+ for (Class<? extends Identifiable> cls : allKeys.keySet()) {
+ List<InstanceIdentifier<? extends DataObject>> keysToCheck = allKeys.get(cls);
+ for (InstanceIdentifier<? extends DataObject> key : keysToCheck) {
+ if (!isDependencyMet(opState, deviceInfo, cls, key)) {
+ result = addToResultMap(result, cls, key);
+ }
+ }
+ }
+ return result;
+ }
+
+ Map<Class<? extends Identifiable>, List<InstanceIdentifier>> addToResultMap(
+ Map<Class<? extends Identifiable>, List<InstanceIdentifier>> result,
+ Class<? extends Identifiable> cls, InstanceIdentifier<? extends DataObject> key) {
+ if (null == result) {
+ result = new HashMap<>();
+ }
+ if (!result.containsKey(cls)) {
+ result.put(cls, new ArrayList<>());
+ }
+ result.get(cls).add(key);
+ return result;
+ }
+
+ abstract boolean isDependencyMet(HwvtepOperationalState opState, HwvtepDeviceInfo deviceInfo,
+ Class<? extends Identifiable> cls, InstanceIdentifier<? extends DataObject> key);
+ }
+
+ class ConfigDependencyGetter extends DependencyGetter {
+ boolean isDependencyMet(HwvtepOperationalState opState, HwvtepDeviceInfo deviceInfo,
+ Class<? extends Identifiable> cls, InstanceIdentifier<? extends DataObject> key) {
+ return deviceInfo.isConfigDataAvailable(cls, key) || isConfigDataAvailable(opState, key);
+ }
+
+ boolean isConfigDataAvailable(HwvtepOperationalState opState, InstanceIdentifier<? extends DataObject> key) {
+ DataBroker db = opState.getConnectionInstance().getDataBroker();
+ MdsalUtils mdsalUtils = new MdsalUtils(db);
+ return mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, key) != null;
+ }
+ }
+
+ class InTransitDependencyGetter extends DependencyGetter {
+ boolean isDependencyMet(HwvtepOperationalState opState, HwvtepDeviceInfo deviceInfo,
+ Class<? extends Identifiable> cls, InstanceIdentifier<? extends DataObject> key) {
+ return opState.isKeyPartOfCurrentTx(cls, key) || !deviceInfo.isKeyInTransit(cls, key);
+ }
+ }
+
+ public abstract List<InstanceIdentifier<?>> getLogicalSwitchDependencies(T data);
+
+ public abstract List<InstanceIdentifier<?>> getTerminationPointDependencies(T data);
+}
\ No newline at end of file
public class HwvtepOperationalCommandAggregator implements TransactionCommand {
private List<TransactionCommand> commands = new ArrayList<>();
+ private final HwvtepConnectionInstance connectionInstance;
public HwvtepOperationalCommandAggregator(HwvtepConnectionInstance key,TableUpdates updates,
DatabaseSchema dbSchema) {
+ this.connectionInstance = key;
commands.add(new GlobalUpdateCommand(key, updates, dbSchema));
commands.add(new HwvtepPhysicalSwitchUpdateCommand(key, updates, dbSchema));
commands.add(new HwvtepPhysicalSwitchRemoveCommand(key, updates, dbSchema));
for (TransactionCommand command: commands) {
command.execute(transaction);
}
+ connectionInstance.getDeviceInfo().onOpDataAvailable();
}
}
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
connectionInfo = mock(OvsdbConnectionInfo.class);
ovsdbClient = mock(OvsdbClient.class);
transactionInvoker = new TransactionInvokerImpl(dataBroker);
+
connectionInstance = PowerMockito.mock(HwvtepConnectionInstance.class, Mockito.CALLS_REAL_METHODS);
field(HwvtepConnectionInstance.class, "instanceIdentifier").set(connectionInstance, nodeIid);
field(HwvtepConnectionInstance.class, "txInvoker").set(connectionInstance, transactionInvoker);
--- /dev/null
+/*
+ * Copyright (c) 2016 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 com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependencyQueue;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependentJob;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.HwvtepOperationalState;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.McastMacsRemoteUpdateCommand;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.UnMetDependencyGetter;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.Operations;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+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.LogicalSwitchesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+import static org.junit.Assert.assertEquals;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({HwvtepConnectionInstance.class, HwvtepConnectionManager.class, Operations.class, DependencyQueue.class})
+public class DependencyQueueTest extends DataChangeListenerTestBase {
+
+ String[][] terminationPoints = new String[][]{
+ {"192.168.122.20"},
+ {"192.168.122.30"}
+ };
+
+ UnMetDependencyGetter<RemoteMcastMacs> MCAST_MAC_DATA_VALIDATOR;
+ HwvtepOperationalState opState;
+ RemoteMcastMacs mac;
+ InstanceIdentifier<RemoteMcastMacs> macIid;
+ InstanceIdentifier<LogicalSwitches> lsIid;
+ Map<Class<? extends Identifiable>, List<InstanceIdentifier>> unMetDependencies;
+
+ void setupForTest() {
+ MCAST_MAC_DATA_VALIDATOR = Whitebox.getInternalState(McastMacsRemoteUpdateCommand.class, UnMetDependencyGetter.class);
+ opState = new HwvtepOperationalState(connectionInstance);
+ mac = TestBuilders.buildRemoteMcastMacs(nodeIid,"FF:FF:FF:FF:FF:FF", "ls0",
+ new String[]{"192.168.122.20", "192.168.122.30"});
+ lsIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
+ child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName("ls0")));
+ macIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
+ child(RemoteMcastMacs.class, new RemoteMcastMacsKey(mac.getKey()));
+ Whitebox.setInternalState(DependencyQueue.class, "executorService", MoreExecutors.sameThreadExecutor());
+ }
+
+ @Test
+ public void testLogicalSwitchConfigDependency() throws Exception {
+ setupForTest();
+ unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getUnMetConfigDependencies(opState, mac);
+ unMetDependencies.remove(TerminationPoint.class);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ opState.getDeviceInfo().addJobToQueue(new DependentJob.ConfigWaitingJob(macIid, mac, unMetDependencies) {
+ @Override
+ protected void onDependencyResolved(HwvtepOperationalState operationalState, TransactionBuilder transactionBuilder) {
+ latch.countDown();
+ }
+ });
+ assertEquals(1, latch.getCount());
+ addData(CONFIGURATION, LogicalSwitches.class, new String[]{"ls0", "100"});
+ addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
+ assertEquals(0, latch.getCount());
+ }
+
+ @Test
+ public void testLogicalSwitchInTransitDependency() throws Exception {
+ setupForTest();
+ opState.getDeviceInfo().markKeyAsInTransit(LogicalSwitches.class, lsIid);
+ unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ opState.getDeviceInfo().addJobToQueue(new DependentJob.OpWaitingJob<RemoteMcastMacs>(macIid, mac, unMetDependencies) {
+ @Override
+ protected void onDependencyResolved(HwvtepOperationalState operationalState, TransactionBuilder transactionBuilder) {
+ latch.countDown();
+ }
+ });
+ opState.getDeviceInfo().onOpDataAvailable();
+ assertEquals(1, latch.getCount());
+
+ opState.getDeviceInfo().updateDeviceOpData(LogicalSwitches.class, lsIid, new UUID("ls0"), "ls0");
+ opState.getDeviceInfo().onOpDataAvailable();
+ assertEquals(0, latch.getCount());
+
+ }
+}
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitchesKey;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
assertEquals(uuid, resultUuid);
boolean result = opState.getDeviceInfo().isKeyInTransit(LogicalSwitches.class, lsIid);
+ assertFalse(result);
+
+ opState.getDeviceInfo().markKeyAsInTransit(LogicalSwitches.class, lsIid);
+ result = opState.getDeviceInfo().isKeyInTransit(LogicalSwitches.class, lsIid);
assertTrue(result);
opState.getDeviceInfo().updateDeviceOpData(LogicalSwitches.class, lsIid, uuid, lsIid);
--- /dev/null
+/*
+ * Copyright (c) 2016 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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.HwvtepOperationalState;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.McastMacsRemoteUpdateCommand;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.UnMetDependencyGetter;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.Operations;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+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.LogicalSwitchesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({HwvtepConnectionInstance.class, HwvtepConnectionManager.class, Operations.class})
+public class UnMetDependencyGetterTest extends DataChangeListenerTestBase {
+
+ UnMetDependencyGetter<RemoteMcastMacs> MCAST_MAC_DATA_VALIDATOR;
+ HwvtepOperationalState opState;
+ RemoteMcastMacs mac;
+ InstanceIdentifier<LogicalSwitches> lsIid;
+ Map<Class<? extends Identifiable>, List<InstanceIdentifier>> unMetDependencies;
+
+ void setupForTest() {
+ MCAST_MAC_DATA_VALIDATOR = Whitebox.getInternalState(McastMacsRemoteUpdateCommand.class, UnMetDependencyGetter.class);
+ opState = new HwvtepOperationalState(connectionInstance);
+ mac = TestBuilders.buildRemoteMcastMacs(nodeIid,"FF:FF:FF:FF:FF:FF", "ls0",
+ new String[]{"192.168.122.20", "192.168.122.30"});
+ lsIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
+ child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName("ls0")));
+ }
+
+ @Test
+ public void testLogicalSwitchConfigDependency() throws Exception {
+ setupForTest();
+ unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac);
+ assertEquals(0, unMetDependencies.size());
+
+ unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getUnMetConfigDependencies(opState, mac);
+ assertEquals(1, unMetDependencies.get(LogicalSwitches.class).size());
+ assertEquals(2, unMetDependencies.get(TerminationPoint.class).size());
+
+ opState.getDeviceInfo().updateConfigData(LogicalSwitches.class, lsIid, "ls0");
+ unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getUnMetConfigDependencies(opState, mac);
+ assertNull(unMetDependencies.get(LogicalSwitches.class));
+ }
+
+ @Test
+ public void testLogicalSwitchInTransitDependency() throws Exception {
+ setupForTest();
+ unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac);
+ assertEquals(0, unMetDependencies.size());
+
+ opState.getDeviceInfo().markKeyAsInTransit(LogicalSwitches.class, lsIid);
+ unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac);
+ assertEquals(1, unMetDependencies.size());
+
+ opState.getDeviceInfo().updateDeviceOpData(LogicalSwitches.class, lsIid, new UUID("ls0"), "ls0");
+ unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac);
+ assertEquals(0, unMetDependencies.size());
+ }
+}