/*
* Copyright (c) 2015 Inocybe inc. 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.southbound.transactions.md;
import static org.opendaylight.ovsdb.southbound.SouthboundUtil.schemaMismatchLog;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
import org.opendaylight.ovsdb.lib.message.TableUpdates;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
import org.opendaylight.ovsdb.southbound.InstanceIdentifierCodec;
import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
import org.opendaylight.ovsdb.southbound.SouthboundConstants;
import org.opendaylight.ovsdb.southbound.SouthboundMapper;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.DatapathTypeEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.DatapathTypeEntryBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntryBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchExternalIds;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchExternalIdsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchExternalIdsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigsKey;
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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OpenVSwitchUpdateCommand extends AbstractTransactionCommand {
private static final Logger LOG = LoggerFactory.getLogger(OpenVSwitchUpdateCommand.class);
private final InstanceIdentifierCodec instanceIdentifierCodec;
public OpenVSwitchUpdateCommand(InstanceIdentifierCodec instanceIdentifierCodec, OvsdbConnectionInstance key,
TableUpdates updates, DatabaseSchema dbSchema) {
super(key, updates, dbSchema);
this.instanceIdentifierCodec = instanceIdentifierCodec;
}
@Override
public void execute(ReadWriteTransaction transaction) {
Map<UUID, OpenVSwitch> updatedOpenVSwitchRows = TyperUtils
.extractRowsUpdated(OpenVSwitch.class, getUpdates(),
getDbSchema());
Map<UUID, OpenVSwitch> deletedOpenVSwitchRows = TyperUtils
.extractRowsOld(OpenVSwitch.class, getUpdates(),
getDbSchema());
for (Entry<UUID, OpenVSwitch> entry : updatedOpenVSwitchRows.entrySet()) {
OpenVSwitch openVSwitch = entry.getValue();
final InstanceIdentifier<Node> nodePath = getInstanceIdentifier(instanceIdentifierCodec, openVSwitch);
OvsdbNodeAugmentationBuilder ovsdbNodeBuilder = new OvsdbNodeAugmentationBuilder();
setDbVersion(ovsdbNodeBuilder, openVSwitch);
setOvsVersion(ovsdbNodeBuilder, openVSwitch);
setDataPathTypes(ovsdbNodeBuilder, openVSwitch);
setInterfaceTypes(ovsdbNodeBuilder, openVSwitch);
OpenVSwitch oldEntry = deletedOpenVSwitchRows.get(entry.getKey());
setExternalIds(instanceIdentifierCodec, transaction, ovsdbNodeBuilder, oldEntry, openVSwitch);
setOtherConfig(instanceIdentifierCodec, transaction, ovsdbNodeBuilder, oldEntry, openVSwitch);
ovsdbNodeBuilder.setConnectionInfo(getConnectionInfo());
NodeBuilder nodeBuilder = new NodeBuilder();
nodeBuilder.setNodeId(getNodeId(instanceIdentifierCodec, openVSwitch));
nodeBuilder.addAugmentation(OvsdbNodeAugmentation.class,
ovsdbNodeBuilder.build());
transaction.merge(LogicalDatastoreType.OPERATIONAL, nodePath,
nodeBuilder.build());
}
}
private void setOtherConfig(InstanceIdentifierCodec instanceIdentifierCodec, ReadWriteTransaction transaction,
OvsdbNodeAugmentationBuilder ovsdbNodeBuilder, OpenVSwitch oldEntry, OpenVSwitch openVSwitch) {
Map<String, String> oldOtherConfigs = null;
Map<String, String> otherConfigs = null;
if (openVSwitch.getOtherConfigColumn() != null) {
otherConfigs = openVSwitch.getOtherConfigColumn().getData();
}
if (oldEntry != null && oldEntry.getOtherConfigColumn() != null) {
oldOtherConfigs = oldEntry.getOtherConfigColumn().getData();
}
if ((oldOtherConfigs != null) && (!oldOtherConfigs.isEmpty())) {
removeOldConfigs(instanceIdentifierCodec, transaction, oldOtherConfigs, openVSwitch);
}
if ((otherConfigs != null) && (!otherConfigs.isEmpty())) {
setNewOtherConfigs(ovsdbNodeBuilder, otherConfigs);
}
}
private void removeOldConfigs(InstanceIdentifierCodec instanceIdentifierCodec, ReadWriteTransaction transaction,
Map<String, String> oldOtherConfigs, OpenVSwitch ovs) {
InstanceIdentifier<OvsdbNodeAugmentation> nodeAugmentataionIid = InstanceIdentifier
.create(NetworkTopology.class)
.child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
.child(Node.class, new NodeKey(getNodeId(instanceIdentifierCodec, ovs)))
.augmentation(OvsdbNodeAugmentation.class);
Set<String> otherConfigKeys = oldOtherConfigs.keySet();
for (String otherConfigKey : otherConfigKeys) {
KeyedInstanceIdentifier<OpenvswitchOtherConfigs, OpenvswitchOtherConfigsKey> externalIid =
nodeAugmentataionIid
.child(OpenvswitchOtherConfigs.class, new OpenvswitchOtherConfigsKey(otherConfigKey));
transaction.delete(LogicalDatastoreType.OPERATIONAL, externalIid);
}
}
private void setNewOtherConfigs(OvsdbNodeAugmentationBuilder ovsdbNodeBuilder,
Map<String, String> otherConfigs) {
Set<String> otherConfigKeys = otherConfigs.keySet();
List<OpenvswitchOtherConfigs> otherConfigsList = new ArrayList<>();
String otherConfigValue;
for (String otherConfigKey : otherConfigKeys) {
otherConfigValue = otherConfigs.get(otherConfigKey);
if (otherConfigKey != null && otherConfigValue != null) {
otherConfigsList.add(new OpenvswitchOtherConfigsBuilder().setOtherConfigKey(otherConfigKey)
.setOtherConfigValue(otherConfigValue).build());
}
}
ovsdbNodeBuilder.setOpenvswitchOtherConfigs(otherConfigsList);
}
private void setExternalIds(InstanceIdentifierCodec instanceIdentifierCodec, ReadWriteTransaction transaction,
OvsdbNodeAugmentationBuilder ovsdbNodeBuilder, OpenVSwitch oldEntry, OpenVSwitch openVSwitch) {
Map<String, String> oldExternalIds = null;
Map<String, String> externalIds = null;
if (openVSwitch.getExternalIdsColumn() != null) {
externalIds = openVSwitch.getExternalIdsColumn().getData();
}
if (oldEntry != null && oldEntry.getExternalIdsColumn() != null) {
oldExternalIds = oldEntry.getExternalIdsColumn().getData();
}
if ((oldExternalIds == null) || oldExternalIds.isEmpty()) {
setNewExternalIds(ovsdbNodeBuilder, externalIds);
} else if (externalIds != null && !externalIds.isEmpty()) {
removeExternalIds(instanceIdentifierCodec, transaction, oldExternalIds, openVSwitch);
setNewExternalIds(ovsdbNodeBuilder, externalIds);
}
}
private void removeExternalIds(InstanceIdentifierCodec instanceIdentifierCodec, ReadWriteTransaction transaction,
Map<String, String> oldExternalIds, OpenVSwitch ovs) {
InstanceIdentifier<OvsdbNodeAugmentation> nodeAugmentataionIid = InstanceIdentifier
.create(NetworkTopology.class)
.child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
.child(Node.class, new NodeKey(getNodeId(instanceIdentifierCodec, ovs)))
.augmentation(OvsdbNodeAugmentation.class);
Set<String> externalIdKeys = oldExternalIds.keySet();
for (String externalIdKey : externalIdKeys) {
KeyedInstanceIdentifier<OpenvswitchExternalIds, OpenvswitchExternalIdsKey> externalIid =
nodeAugmentataionIid
.child(OpenvswitchExternalIds.class, new OpenvswitchExternalIdsKey(externalIdKey));
transaction.delete(LogicalDatastoreType.OPERATIONAL, externalIid);
}
}
private void setNewExternalIds(OvsdbNodeAugmentationBuilder ovsdbNodeBuilder,
Map<String, String> externalIds) {
Set<String> externalIdKeys = externalIds.keySet();
List<OpenvswitchExternalIds> externalIdsList = new ArrayList<>();
String externalIdValue;
for (String externalIdKey : externalIdKeys) {
externalIdValue = externalIds.get(externalIdKey);
if (externalIdKey != null && externalIdValue != null) {
externalIdsList.add(new OpenvswitchExternalIdsBuilder().setExternalIdKey(externalIdKey)
.setExternalIdValue(externalIdValue).build());
}
}
ovsdbNodeBuilder.setOpenvswitchExternalIds(externalIdsList);
}
private void setInterfaceTypes(
OvsdbNodeAugmentationBuilder ovsdbNodeBuilder,
OpenVSwitch openVSwitch) {
try {
Set<String> iftypes = openVSwitch.getIfaceTypesColumn().getData();
List<InterfaceTypeEntry> ifEntryList = new ArrayList<>();
for (String ifType : iftypes) {
if (SouthboundMapper.createInterfaceType(ifType) != null) {
InterfaceTypeEntry ifEntry = new InterfaceTypeEntryBuilder()
.setInterfaceType(
SouthboundMapper.createInterfaceType(ifType))
.build();
ifEntryList.add(ifEntry);
} else {
LOG.warn("Interface type {} not present in model", ifType);
}
}
ovsdbNodeBuilder.setInterfaceTypeEntry(ifEntryList);
} catch (SchemaVersionMismatchException e) {
schemaMismatchLog("iface_types", SouthboundConstants.OPEN_V_SWITCH, e);
}
}
private void setDataPathTypes(
OvsdbNodeAugmentationBuilder ovsdbNodeBuilder,
OpenVSwitch openVSwitch) {
try {
Set<String> dptypes = openVSwitch.getDatapathTypesColumn()
.getData();
List<DatapathTypeEntry> dpEntryList = new ArrayList<>();
for (String dpType : dptypes) {
if (SouthboundMapper.createDatapathType(dpType) != null) {
DatapathTypeEntry dpEntry = new DatapathTypeEntryBuilder()
.setDatapathType(
SouthboundMapper.createDatapathType(dpType))
.build();
dpEntryList.add(dpEntry);
} else {
LOG.warn("Datapath type {} not present in model", dpType);
}
}
ovsdbNodeBuilder.setDatapathTypeEntry(dpEntryList);
} catch (SchemaVersionMismatchException e) {
schemaMismatchLog("datapath_types", SouthboundConstants.OPEN_V_SWITCH, e);
}
}
private void setOvsVersion(OvsdbNodeAugmentationBuilder ovsdbNodeBuilder, OpenVSwitch openVSwitch) {
try {
ovsdbNodeBuilder.setOvsVersion(openVSwitch.getOvsVersionColumn().getData().iterator().next());
} catch (NoSuchElementException e) {
LOG.debug("ovs_version is not set for this switch",e);
}
}
private void setDbVersion(OvsdbNodeAugmentationBuilder ovsdbNodeBuilder, OpenVSwitch openVSwitch) {
try {
ovsdbNodeBuilder.setDbVersion(openVSwitch.getDbVersionColumn().getData().iterator().next());
} catch (NoSuchElementException e) {
LOG.debug("db_version is not set for this switch",e);
}
}
private InstanceIdentifier<Node> getInstanceIdentifier(InstanceIdentifierCodec instanceIdentifierCodec,
OpenVSwitch ovs) {
if (ovs.getExternalIdsColumn() != null
&& ovs.getExternalIdsColumn().getData() != null
&& ovs.getExternalIdsColumn().getData().containsKey(SouthboundConstants.IID_EXTERNAL_ID_KEY)) {
String iidString = ovs.getExternalIdsColumn().getData().get(SouthboundConstants.IID_EXTERNAL_ID_KEY);
InstanceIdentifier<Node> iid =
(InstanceIdentifier<Node>) instanceIdentifierCodec.bindingDeserializerOrNull(iidString);
getOvsdbConnectionInstance().setInstanceIdentifier(iid);
} else {
String nodeString = SouthboundConstants.OVSDB_URI_PREFIX + "://" + SouthboundConstants.UUID + "/"
+ ovs.getUuid().toString();
NodeId nodeId = new NodeId(new Uri(nodeString));
NodeKey nodeKey = new NodeKey(nodeId);
InstanceIdentifier<Node> iid = InstanceIdentifier.builder(NetworkTopology.class)
.child(Topology.class,new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
.child(Node.class,nodeKey)
.build();
getOvsdbConnectionInstance().setInstanceIdentifier(iid);
}
return getOvsdbConnectionInstance().getInstanceIdentifier();
}
private NodeId getNodeId(InstanceIdentifierCodec instanceIdentifierCodec, OpenVSwitch ovs) {
NodeKey nodeKey = getInstanceIdentifier(instanceIdentifierCodec, ovs).firstKeyOf(Node.class);
return nodeKey.getNodeId();
}
}