bug 8712 vlan bindings update fix
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transact / PhysicalPortUpdateCommand.java
index 3ecdd600764ef8d6ee73ca44a5cc9efec61bc259..25fdfecb40b190c8872fbc939deaa57eb73a4ca2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016 China Telecom Beijing Research Institute and others.  All rights reserved.
+ * Copyright © 2015, 2017 China Telecom Beijing Research Institute 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,
@@ -12,36 +12,45 @@ import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
 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 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.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
 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.PhysicalPort;
 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalPortAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
 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.physical.port.attributes.VlanBindings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindingsKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
 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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
 
 public class PhysicalPortUpdateCommand extends AbstractTransactCommand {
     private static final Logger LOG = LoggerFactory.getLogger(PhysicalPortUpdateCommand.class);
+    private static final VlanBindingsUnMetDependencyGetter DEPENDENCY_GETTER = new VlanBindingsUnMetDependencyGetter();
 
     public PhysicalPortUpdateCommand(HwvtepOperationalState state,
             Collection<DataTreeModification<Node>> changes) {
@@ -57,57 +66,37 @@ public class PhysicalPortUpdateCommand extends AbstractTransactCommand {
         if (!createds.isEmpty()) {
             for (Entry<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> created:
                 createds.entrySet()) {
-                updatePhysicalPort(transaction,  created.getKey(), created.getValue(), createdPhysicalSwitches);
+                updatePhysicalPort(transaction,  created.getKey(), created.getValue());
             }
         }
         Map<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> updateds =
-                extractUpdated(getChanges(),HwvtepPhysicalPortAugmentation.class);
+                extractUpdatedPorts(getChanges(), HwvtepPhysicalPortAugmentation.class);
         if (!updateds.isEmpty()) {
             for (Entry<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> updated:
                 updateds.entrySet()) {
-                updatePhysicalPort(transaction,  updated.getKey(), updated.getValue(), createdPhysicalSwitches);
+                updatePhysicalPort(transaction,  updated.getKey(), updated.getValue());
             }
         }
     }
 
-    private void updatePhysicalPort(TransactionBuilder transaction,
-            InstanceIdentifier<Node> psNodeiid,
-            List<HwvtepPhysicalPortAugmentation> listPort,
-            Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> createdPhysicalSwitches ) {
+    public void updatePhysicalPort(final TransactionBuilder transaction,
+                                   final InstanceIdentifier<Node> psNodeiid,
+                                   final List<HwvtepPhysicalPortAugmentation> listPort) {
         //Get physical switch which the port belong to: in operation DS or new created
-        PhysicalSwitchAugmentation physicalSwitchBelong = getPhysicalSwitchBelong(psNodeiid, createdPhysicalSwitches);
         for (HwvtepPhysicalPortAugmentation port : listPort) {
             LOG.debug("Creating a physical port named: {}", port.getHwvtepNodeName().getValue());
-            Optional<HwvtepPhysicalPortAugmentation> operationalPhysicalPortOptional =
-                    getOperationalState().getPhysicalPortAugmentation(psNodeiid, port.getHwvtepNodeName());
-            PhysicalPort physicalPort = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), PhysicalPort.class);
-            //get managing global node of physicalSwitchBelong
-            InstanceIdentifier<?> globalNodeIid = physicalSwitchBelong.getManagedBy().getValue();
-            setVlanBindings(globalNodeIid, physicalPort, port);
-            setDescription(physicalPort, port);
-            if (!operationalPhysicalPortOptional.isPresent()) {
-                //create a physical port
-                setName(physicalPort, port, operationalPhysicalPortOptional);
-                String portUuid = "PhysicalPort_" + HwvtepSouthboundMapper.getRandomUUID();
-                LOG.trace("execute: creating physical port: {}", physicalPort);
-                transaction.add(op.insert(physicalPort).withId(portUuid));
-                transaction.add(op.comment("Physical Port: Creating " + port.getHwvtepNodeName().getValue()));
-                //update physical switch table
-                PhysicalSwitch physicalSwitch = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), PhysicalSwitch.class);
-                physicalSwitch.setName(physicalSwitchBelong.getHwvtepNodeName().getValue());
-                physicalSwitch.setPorts(Sets.newHashSet(new UUID(portUuid)));
-                LOG.trace("execute: mutating physical switch: {}", physicalSwitch);
-                transaction.add(op.mutate(physicalSwitch)
-                        .addMutation(physicalSwitch.getPortsColumn().getSchema(), Mutator.INSERT,
-                                physicalSwitch.getPortsColumn().getData())
-                        .where(physicalSwitch.getNameColumn().getSchema().opEqual(physicalSwitch.getNameColumn().getData()))
-                        .build());
-                transaction.add(op.comment("Physical Switch: Mutating " +
-                                port.getHwvtepNodeName().getValue() + " " + portUuid));
+            HwvtepDeviceInfo.DeviceData deviceOperdata = getDeviceInfo().getDeviceOperData(TerminationPoint.class,
+                    getTpIid(psNodeiid, port.getHwvtepNodeName().getValue()));
+            if (deviceOperdata == null) {
+                //create a physical port always happens from device
+                LOG.error("Physical port {} not present in oper datastore", port.getHwvtepNodeName().getValue());
             } else {
-                //updated physical port only
-                HwvtepPhysicalPortAugmentation updatedPhysicalPort = operationalPhysicalPortOptional.get();
-                String existingPhysicalPortName = updatedPhysicalPort.getHwvtepNodeName().getValue();
+                PhysicalPort physicalPort = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
+                        PhysicalPort.class);
+                physicalPort.setName(port.getHwvtepNodeName().getValue());
+                setVlanBindings(psNodeiid, physicalPort, port, transaction);
+                setDescription(physicalPort, port);
+                String existingPhysicalPortName = port.getHwvtepNodeName().getValue();
                 PhysicalPort extraPhyscialPort =
                         TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), PhysicalPort.class);
                 extraPhyscialPort.setName("");
@@ -145,43 +134,125 @@ public class PhysicalPortUpdateCommand extends AbstractTransactCommand {
 
     private void setDescription(PhysicalPort physicalPort, HwvtepPhysicalPortAugmentation inputPhysicalPort) {
         if (inputPhysicalPort.getHwvtepNodeDescription() != null) {
-            physicalPort.setDescription(inputPhysicalPort.getHwvtepNodeDescription().toString());
+            physicalPort.setDescription(inputPhysicalPort.getHwvtepNodeDescription());
         }
     }
 
-    private void setVlanBindings(InstanceIdentifier<?> globalNodeIid, PhysicalPort physicalPort,
-            HwvtepPhysicalPortAugmentation inputPhysicalPort) {
+    private void setVlanBindings(final InstanceIdentifier<Node> psNodeiid,
+                                 final PhysicalPort physicalPort,
+                                 final HwvtepPhysicalPortAugmentation inputPhysicalPort,
+                                 final TransactionBuilder transaction) {
         if (inputPhysicalPort.getVlanBindings() != null) {
             //get UUID by LogicalSwitchRef
-            Map<Long, UUID> bindingMap = new HashMap<Long, UUID>();
+            Map<Long, UUID> bindingMap = new HashMap<>();
             for (VlanBindings vlanBinding: inputPhysicalPort.getVlanBindings()) {
+                InstanceIdentifier<VlanBindings> vlanIid = getVlanBindingIid(psNodeiid, physicalPort, vlanBinding);
                 @SuppressWarnings("unchecked")
                 InstanceIdentifier<LogicalSwitches> lswitchIid =
                         (InstanceIdentifier<LogicalSwitches>) vlanBinding.getLogicalSwitchRef().getValue();
-                Optional<LogicalSwitches> operationalSwitchOptional =
-                        getOperationalState().getLogicalSwitches(lswitchIid);
-                if (operationalSwitchOptional.isPresent()) {
-                    Uuid logicalSwitchUuid = operationalSwitchOptional.get().getLogicalSwitchUuid();
-                    bindingMap.put(vlanBinding.getVlanIdKey().getValue().longValue(), new UUID(logicalSwitchUuid.getValue()));
-                }else{
-                    bindingMap.put(vlanBinding.getVlanIdKey().getValue().longValue(), TransactUtils.getLogicalSwitchUUID(lswitchIid));
+
+                Map inTransitDependencies = DEPENDENCY_GETTER.getInTransitDependencies(
+                        getOperationalState(), vlanBinding);
+                Map configDependencies = DEPENDENCY_GETTER.getUnMetConfigDependencies(
+                        getOperationalState(), vlanBinding);
+
+                if (!HwvtepSouthboundUtil.isEmptyMap(configDependencies)) {
+                    createConfigWaitJob(psNodeiid, inputPhysicalPort,
+                            vlanBinding, configDependencies, vlanIid);
+                    continue;
+                }
+                if (!HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
+                    createOperWaitingJob(psNodeiid, inputPhysicalPort,
+                            vlanBinding, inTransitDependencies, vlanIid);
+                    continue;
                 }
+
+                bindingMap.put(vlanBinding.getVlanIdKey().getValue().longValue(),
+                        TransactUtils.getLogicalSwitchUUID(transaction, getOperationalState(), lswitchIid));
             }
             physicalPort.setVlanBindings(bindingMap);
         }
     }
 
+    private void createOperWaitingJob(final InstanceIdentifier<Node> psNodeiid,
+                                      final HwvtepPhysicalPortAugmentation inputPhysicalPort,
+                                      final VlanBindings vlanBinding,
+                                      final Map inTransitDependencies,
+                                      final InstanceIdentifier<VlanBindings> vlanIid) {
+
+        DependentJob<VlanBindings> opWaitingJob = new DependentJob.OpWaitingJob(
+                vlanIid, vlanBinding, inTransitDependencies) {
+            @Override
+            public void onDependencyResolved(final HwvtepOperationalState operationalState,
+                                             final TransactionBuilder transactionBuilder) {
+                PhysicalPortUpdateCommand.this.threadLocalOperationalState.set(operationalState);
+                PhysicalPortUpdateCommand.this.threadLocalDeviceTransaction.set(transactionBuilder);
+                updatePhysicalPort(transactionBuilder, psNodeiid, Lists.newArrayList(inputPhysicalPort));
+            }
+        };
+        getDeviceInfo().addJobToQueue(opWaitingJob);
+    }
+
+    private void createConfigWaitJob(final InstanceIdentifier<Node> psNodeiid,
+                                     final HwvtepPhysicalPortAugmentation inputPhysicalPort,
+                                     final VlanBindings vlanBinding,
+                                     final Map configDependencies,
+                                     final InstanceIdentifier<VlanBindings> vlanIid) {
+
+        DependentJob<VlanBindings> configWaitingJob = new DependentJob.ConfigWaitingJob(
+                vlanIid, vlanBinding, configDependencies) {
+            @Override
+            public void onDependencyResolved(final HwvtepOperationalState operationalState,
+                                             final TransactionBuilder transactionBuilder) {
+                PhysicalPortUpdateCommand.this.threadLocalOperationalState.set(operationalState);
+                PhysicalPortUpdateCommand.this.threadLocalDeviceTransaction.set(transactionBuilder);
+                updatePhysicalPort(transactionBuilder, psNodeiid, Lists.newArrayList(inputPhysicalPort));
+            }
+        };
+        getDeviceInfo().addJobToQueue(configWaitingJob);
+    }
+
+    private InstanceIdentifier<TerminationPoint> getTpIid(final InstanceIdentifier<Node> psNodeiid,
+                                                          final String portName) {
+        return psNodeiid.child(
+                TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
+    }
+
+    private InstanceIdentifier<VlanBindings> getVlanBindingIid(
+            final InstanceIdentifier<Node> psNodeiid,
+            final PhysicalPort physicalPort,
+            final VlanBindings vlanBinding) {
+
+        return psNodeiid.child(
+                TerminationPoint.class, new TerminationPointKey(new TpId(physicalPort.getName())))
+                .augmentation(HwvtepPhysicalPortAugmentation.class)
+                .child(VlanBindings.class, new VlanBindingsKey(vlanBinding.getVlanIdKey()));
+    }
+
+    static class VlanBindingsUnMetDependencyGetter extends UnMetDependencyGetter<VlanBindings> {
+
+        public List<InstanceIdentifier<?>> getLogicalSwitchDependencies(VlanBindings data) {
+            if (data == null) {
+                return Collections.emptyList();
+            }
+            return Collections.singletonList(data.getLogicalSwitchRef().getValue());
+        }
+
+        public List<InstanceIdentifier<?>> getTerminationPointDependencies(VlanBindings data) {
+            return Collections.emptyList();
+        }
+    }
+
     private Map<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> extractCreated(
             Collection<DataTreeModification<Node>> changes, Class<HwvtepPhysicalPortAugmentation> class1) {
-        Map<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> result
-            = new HashMap<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>>();
+        Map<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> result = new HashMap<>();
         if (changes != null && !changes.isEmpty()) {
             for (DataTreeModification<Node> change : changes) {
                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
                 final DataObjectModification<Node> mod = change.getRootNode();
                 Node created = TransactUtils.getCreated(mod);
                 if (created != null) {
-                    List<HwvtepPhysicalPortAugmentation> portListUpdated = new ArrayList<HwvtepPhysicalPortAugmentation>();
+                    List<HwvtepPhysicalPortAugmentation> portListUpdated = new ArrayList<>();
                     if (created.getTerminationPoint() != null) {
                         for (TerminationPoint tp : created.getTerminationPoint()) {
                             HwvtepPhysicalPortAugmentation hppAugmentation = tp.getAugmentation(HwvtepPhysicalPortAugmentation.class);
@@ -199,8 +270,7 @@ public class PhysicalPortUpdateCommand extends AbstractTransactCommand {
 
     private Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractCreatedPhyscialSwitch(
             Collection<DataTreeModification<Node>> changes, Class<PhysicalSwitchAugmentation> class1) {
-        Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result
-            = new HashMap<InstanceIdentifier<Node>, PhysicalSwitchAugmentation>();
+        Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result = new HashMap<>();
         if (changes != null && !changes.isEmpty()) {
             for (DataTreeModification<Node> change : changes) {
                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
@@ -217,10 +287,9 @@ public class PhysicalPortUpdateCommand extends AbstractTransactCommand {
         return result;
     }
 
-    private Map<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> extractUpdated(
+    private Map<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> extractUpdatedPorts(
             Collection<DataTreeModification<Node>> changes, Class<HwvtepPhysicalPortAugmentation> class1) {
-        Map<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> result
-            = new HashMap<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>>();
+        Map<InstanceIdentifier<Node>, List<HwvtepPhysicalPortAugmentation>> result = new HashMap<>();
         if (changes != null && !changes.isEmpty()) {
             for (DataTreeModification<Node> change : changes) {
                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
@@ -228,8 +297,8 @@ public class PhysicalPortUpdateCommand extends AbstractTransactCommand {
                 Node updated = TransactUtils.getUpdated(mod);
                 Node before = mod.getDataBefore();
                 if (updated != null && before != null) {
-                    List<HwvtepPhysicalPortAugmentation> portListUpdated = new ArrayList<HwvtepPhysicalPortAugmentation>();
-                    List<HwvtepPhysicalPortAugmentation> portListBefore = new ArrayList<HwvtepPhysicalPortAugmentation>();
+                    List<HwvtepPhysicalPortAugmentation> portListUpdated = new ArrayList<>();
+                    List<HwvtepPhysicalPortAugmentation> portListBefore = new ArrayList<>();
                     if (updated.getTerminationPoint() != null) {
                         for (TerminationPoint tp : updated.getTerminationPoint()) {
                             HwvtepPhysicalPortAugmentation hppAugmentation = tp.getAugmentation(HwvtepPhysicalPortAugmentation.class);