<httpcomponents.version>4.2.1</httpcomponents.version>
<portlet.version>2.0</portlet.version>
<powermock.version>1.5.2</powermock.version>
+ <dlux.version>0.3.0-SNAPSHOT</dlux.version>
<ovsdb.ui.version>0.1.0-SNAPSHOT</ovsdb.ui.version>
- <dlux.loader.version>0.3.0-SNAPSHOT</dlux.loader.version>
- <dlux.core.version>0.3.0-SNAPSHOT</dlux.core.version>
</properties>
<dependencyManagement>
<openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
<sal.version>0.10.0-SNAPSHOT</sal.version>
<yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
- <dlux.core.version>0.3.0-SNAPSHOT</dlux.core.version>
- <ovsdb.ui.version>0.1.0-SNAPSHOT</ovsdb.ui.version>
<config.version>0.4.0-SNAPSHOT</config.version>
+ <dlux.version>0.3.0-SNAPSHOT</dlux.version>
+ <ovsdb.ui.version>0.1.0-SNAPSHOT</ovsdb.ui.version>
</properties>
<dependencyManagement>
<version>${networkconfig.neutron.version}</version>
<classifier>features</classifier>
<type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.neutron</groupId>
+ <artifactId>dummyprovider</artifactId>
+ <version>${networkconfig.neutron.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.openflowplugin</groupId>
<type>xml</type>
<classifier>features</classifier>
</dependency>
+ <!-- DLUX dependency for the UI -->
+ <dependency>
+ <groupId>org.opendaylight.dlux</groupId>
+ <artifactId>features-dlux</artifactId>
+ <version>${dlux.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>ovsdb-ui-bundle</artifactId>
+ <version>${ovsdb.ui.version}</version>
+ </dependency>
</dependencies>
</project>
<repository>mvn:org.opendaylight.ovsdb/southbound-features/1.2.1-SNAPSHOT/xml/features</repository>
<repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
<repository>mvn:org.opendaylight.ovsdb/library-features/${ovsdb.library.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
<feature name="odl-ovsdb-all" description="OpenDaylight :: OVSDB :: all"
version='${project.version}'>
<bundle>mvn:org.opendaylight.ovsdb/utils.servicehelper/${ovsdb.utils.servicehelper.version}</bundle>
<bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt/${openstack.netvirt.version}</bundle>
<bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-providers/${openstack.netvirt.providers.version}</bundle>
+ <bundle>mvn:org.opendaylight.neutron/dummyprovider/${networkconfig.neutron.version}</bundle>
<configfile finalname="etc/opendaylight/karaf/netvirt-impl-default-config.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt/${project.version}/xml/config</configfile>
<configfile finalname="etc/opendaylight/karaf/netvirt-providers-impl-default-config.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt-providers/${project.version}/xml/config</configfile>
</feature>
<feature name="odl-ovsdb-ui" description="OpenDaylight :: OVSDB :: DLUX Integration Plugin" version='${ovsdb.ui.version}'>
- <feature version="${dlux.core.version}">odl-dlux-core</feature>
+ <feature version="${dlux.version}">odl-dlux-core</feature>
<bundle>mvn:org.opendaylight.ovsdb/ovsdb-ui-bundle/${ovsdb.ui.version}</bundle>
</feature>
</features>
<feature version='${mdsal.version}'>odl-mdsal-broker</feature>
<feature version='${project.version}'>odl-ovsdb-hwvtepsouthbound-api</feature>
<bundle>mvn:org.opendaylight.ovsdb/hwvtepsouthbound-impl/${project.version}</bundle>
+ <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version}</bundle>
+ <bundle>mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version}</bundle>
+ <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version}</bundle>
+ <bundle>mvn:com.fasterxml.jackson.datatype/jackson-datatype-json-org/${jackson.version}</bundle>
+ <bundle>wrap:mvn:org.json/json/${org.json.version}</bundle>
<configfile finalname="${configfile.directory}/hwvtepsouthbound.xml">mvn:org.opendaylight.ovsdb/hwvtepsouthbound-impl/${project.version}/xml/config</configfile>
</feature>
<feature name='odl-ovsdb-hwvtepsouthbound-rest' version='${project.version}' description='OpenDaylight :: hwvtepsouthbound :: REST'>
<artifactId>hwvtepsouthbound-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>library</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>schema.hardwarevtep</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<!-- Testing Dependencies -->
<dependency>
<build>
<plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Private-Package>org.opendaylight.ovsdb.lib.*,org.opendaylight.ovsdb.schema.hardwarevtep</Private-Package>
+ <Export-Package>org.opendaylight.ovsdb.hwvtepsouthbound.*,org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
<name>binding-osgi-broker</name>
</broker>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <binding-normalized-node-serializer>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-normalized-node-serializer>
+ <clustering-entity-ownership-service>
+ <type xmlns:ns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">ns:entity-ownership-service</type>
+ <name>entity-ownership-service</name>
+ </clustering-entity-ownership-service>
</module>
</modules>
</data>
--- /dev/null
+/*
+ * Copyright (c) 2015 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.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactCommand;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactInvoker;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactInvokerImpl;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.lib.EchoServiceCallbackFilters;
+import org.opendaylight.ovsdb.lib.LockAquisitionCallback;
+import org.opendaylight.ovsdb.lib.LockStolenCallback;
+import org.opendaylight.ovsdb.lib.MonitorCallBack;
+import org.opendaylight.ovsdb.lib.MonitorHandle;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
+import org.opendaylight.ovsdb.lib.message.MonitorRequest;
+import org.opendaylight.ovsdb.lib.message.MonitorRequestBuilder;
+import org.opendaylight.ovsdb.lib.message.MonitorSelect;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.operations.Operation;
+import org.opendaylight.ovsdb.lib.operations.OperationResult;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.TableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+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.Node;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class HwvtepConnectionInstance implements OvsdbClient{
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepConnectionInstance.class);
+ private ConnectionInfo connectionInfo;
+ private OvsdbClient client;
+ private InstanceIdentifier<Node> instanceIdentifier;
+ private TransactionInvoker txInvoker;
+ private Map<DatabaseSchema,TransactInvoker> transactInvokers;
+ private MonitorCallBack callback;
+ private volatile boolean hasDeviceOwnership = false;
+ private Entity connectedEntity;
+ private EntityOwnershipCandidateRegistration deviceOwnershipCandidateRegistration;
+
+
+ HwvtepConnectionInstance (ConnectionInfo key,OvsdbClient client,
+ InstanceIdentifier<Node> iid, TransactionInvoker txInvoker) {
+ this.connectionInfo = key;
+ this.client = client;
+ this.instanceIdentifier = iid;
+ this.txInvoker = txInvoker;
+ }
+
+ public void transact(TransactCommand command) {
+ for (TransactInvoker transactInvoker: transactInvokers.values()) {
+ transactInvoker.invoke(command);
+ }
+ }
+
+ public void registerCallbacks() {
+ if ( this.callback == null) {
+ try {
+ List<String> databases = getDatabases().get();
+ this.callback = new HwvtepMonitorCallback(this,txInvoker);
+ for (String database : databases) {
+ DatabaseSchema dbSchema = getSchema(database).get();
+ if (dbSchema != null) {
+ monitorAllTables(database, dbSchema);
+ } else {
+ LOG.warn("No schema reported for database {} for key {}",database,connectionInfo);
+ }
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception attempting to registerCallbacks {}: {}",connectionInfo,e);
+ }
+ }
+ }
+
+ public void createTransactInvokers() {
+ if (transactInvokers == null) {
+ try {
+ transactInvokers = new HashMap<DatabaseSchema,TransactInvoker>();
+ List<String> databases = getDatabases().get();
+ for (String database : databases) {
+ DatabaseSchema dbSchema = getSchema(database).get();
+ if (dbSchema != null) {
+ transactInvokers.put(dbSchema, new TransactInvokerImpl(this,dbSchema));
+ }
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception attempting to createTransactionInvokers {}: {}",connectionInfo,e);
+ }
+ }
+ }
+
+ private void monitorAllTables(String database, DatabaseSchema dbSchema) {
+ Set<String> tables = dbSchema.getTables();
+ if (tables != null) {
+ List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
+ for (String tableName : tables) {
+ GenericTableSchema tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
+ Set<String> columns = tableSchema.getColumns();
+ MonitorRequestBuilder<GenericTableSchema> monitorBuilder = MonitorRequestBuilder.builder(tableSchema);
+ for (String column : columns) {
+ monitorBuilder.addColumn(column);
+ }
+ monitorRequests.add(monitorBuilder.with(new MonitorSelect(true, true, true, true)).build());
+ }
+ this.callback.update(monitor(dbSchema, monitorRequests, callback),dbSchema);
+ } else {
+ LOG.warn("No tables for schema {} for database {} for key {}",dbSchema,database,connectionInfo);
+ }
+ }
+
+ public ListenableFuture<List<String>> getDatabases() {
+ return client.getDatabases();
+ }
+
+ public ListenableFuture<DatabaseSchema> getSchema(String database) {
+ return client.getSchema(database);
+ }
+
+ public TransactionBuilder transactBuilder(DatabaseSchema dbSchema) {
+ return client.transactBuilder(dbSchema);
+ }
+
+ public ListenableFuture<List<OperationResult>> transact(DatabaseSchema dbSchema, List<Operation> operations) {
+ return client.transact(dbSchema, operations);
+ }
+
+ public <E extends TableSchema<E>> TableUpdates monitor(DatabaseSchema schema,
+ List<MonitorRequest<E>> monitorRequests, MonitorCallBack callback) {
+ return client.monitor(schema, monitorRequests, callback);
+ }
+
+ @Override
+ public <E extends TableSchema<E>> TableUpdates monitor(DatabaseSchema schema,
+ List<MonitorRequest<E>> monitorRequests, MonitorHandle monitorHandle, MonitorCallBack callback) {
+ return null;
+ }
+
+ public void cancelMonitor(MonitorHandle handler) {
+ client.cancelMonitor(handler);
+ }
+
+ public void lock(String lockId, LockAquisitionCallback lockedCallBack, LockStolenCallback stolenCallback) {
+ client.lock(lockId, lockedCallBack, stolenCallback);
+ }
+
+ public ListenableFuture<Boolean> steal(String lockId) {
+ return client.steal(lockId);
+ }
+
+ public ListenableFuture<Boolean> unLock(String lockId) {
+ return client.unLock(lockId);
+ }
+
+ public void startEchoService(EchoServiceCallbackFilters callbackFilters) {
+ client.startEchoService(callbackFilters);
+ }
+
+ public void stopEchoService() {
+ client.stopEchoService();
+ }
+
+ public OvsdbConnectionInfo getConnectionInfo() {
+ return client.getConnectionInfo();
+ }
+
+ public boolean isActive() {
+ return client.isActive();
+ }
+
+ public void disconnect() {
+ client.disconnect();
+ }
+
+ public DatabaseSchema getDatabaseSchema(String dbName) {
+ return client.getDatabaseSchema(dbName);
+ }
+
+ public <T extends TypedBaseTable<?>> T createTypedRowWrapper(Class<T> klazz) {
+ return client.createTypedRowWrapper(klazz);
+ }
+
+ public <T extends TypedBaseTable<?>> T createTypedRowWrapper(DatabaseSchema dbSchema, Class<T> klazz) {
+ return client.createTypedRowWrapper(dbSchema, klazz);
+ }
+
+ public <T extends TypedBaseTable<?>> T getTypedRowWrapper(Class<T> klazz, Row<GenericTableSchema> row) {
+ return client.getTypedRowWrapper(klazz, row);
+ }
+
+ public ConnectionInfo getMDConnectionInfo() {
+ return connectionInfo;
+ }
+
+ public void setMDConnectionInfo(ConnectionInfo key) {
+ this.connectionInfo = key;
+ }
+
+ public InstanceIdentifier<Node> getInstanceIdentifier() {
+ return instanceIdentifier;
+ }
+
+ public NodeKey getNodeKey() {
+ //TODO: What is the alternative here?
+ return getInstanceIdentifier().firstKeyOf(Node.class, NodeKey.class);
+ }
+
+ public NodeId getNodeId() {
+ return getNodeKey().getNodeId();
+ }
+
+ public void setInstanceIdentifier(InstanceIdentifier<Node> iid) {
+ this.instanceIdentifier = iid;
+ }
+
+ public Entity getConnectedEntity() {
+ return this.connectedEntity;
+ }
+
+ public void setConnectedEntity(Entity entity ) {
+ this.connectedEntity = entity;
+ }
+
+ public Boolean hasOvsdbClient(OvsdbClient otherClient) {
+ return client.equals(otherClient);
+ }
+
+ public Boolean getHasDeviceOwnership() {
+ return Boolean.valueOf(hasDeviceOwnership);
+ }
+
+ public void setHasDeviceOwnership(Boolean hasDeviceOwnership) {
+ if (hasDeviceOwnership != null) {
+ this.hasDeviceOwnership = hasDeviceOwnership.booleanValue();
+ }
+ }
+
+ public void setDeviceOwnershipCandidateRegistration(@Nonnull EntityOwnershipCandidateRegistration registration) {
+ this.deviceOwnershipCandidateRegistration = registration;
+ }
+
+ public void closeDeviceOwnershipCandidateRegistration() {
+ if (deviceOwnershipCandidateRegistration != null) {
+ this.deviceOwnershipCandidateRegistration.close();
+ setHasDeviceOwnership(Boolean.FALSE);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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 static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.OvsdbConnectionListener;
+import org.opendaylight.ovsdb.lib.operations.Operation;
+import org.opendaylight.ovsdb.lib.operations.OperationResult;
+import org.opendaylight.ovsdb.lib.operations.Select;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+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.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoCloseable{
+ private Map<ConnectionInfo, HwvtepConnectionInstance> clients =
+ new ConcurrentHashMap<ConnectionInfo,HwvtepConnectionInstance>();
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepConnectionManager.class);
+ private static final String ENTITY_TYPE = "hwvtep";
+
+ private DataBroker db;
+ private TransactionInvoker txInvoker;
+ private Map<ConnectionInfo,InstanceIdentifier<Node>> instanceIdentifiers =
+ new ConcurrentHashMap<ConnectionInfo,InstanceIdentifier<Node>>();
+ private Map<Entity, HwvtepConnectionInstance> entityConnectionMap =
+ new ConcurrentHashMap<>();
+ private EntityOwnershipService entityOwnershipService;
+ private HwvtepDeviceEntityOwnershipListener hwvtepDeviceEntityOwnershipListener;
+
+ public HwvtepConnectionManager(DataBroker db, TransactionInvoker txInvoker,
+ EntityOwnershipService entityOwnershipService) {
+ this.db = db;
+ this.txInvoker = txInvoker;
+ this.entityOwnershipService = entityOwnershipService;
+ this.hwvtepDeviceEntityOwnershipListener = new HwvtepDeviceEntityOwnershipListener(this,entityOwnershipService);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (hwvtepDeviceEntityOwnershipListener != null) {
+ hwvtepDeviceEntityOwnershipListener.close();
+ }
+
+ for (OvsdbClient client: clients.values()) {
+ client.disconnect();
+ }
+ }
+
+ @Override
+ public void connected(@Nonnull final OvsdbClient client) {
+ HwvtepConnectionInstance hwClient = connectedButCallBacksNotRegistered(client);
+ registerEntityForOwnership(hwClient);
+ LOG.trace("connected client: {}", hwClient);
+ }
+
+ @Override
+ public void disconnected(OvsdbClient client) {
+ LOG.info("HWVTEP Disconnected from {}:{}. Cleaning up the operational data store"
+ ,client.getConnectionInfo().getRemoteAddress(),
+ client.getConnectionInfo().getRemotePort());
+ ConnectionInfo key = HwvtepSouthboundMapper.createConnectionInfo(client);
+ HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstance(key);
+ if (hwvtepConnectionInstance != null) {
+ //TODO: txInvoker.invoke(new HwvtepNodeRemoveCommand(hwvtepConnectionInstance, null, null));
+ removeConnectionInstance(key);
+
+ // Unregister Cluster Ownership for ConnectionInfo
+ unregisterEntityForOwnership(hwvtepConnectionInstance);
+ } else {
+ LOG.warn("HWVTEP disconnected event did not find connection instance for {}", key);
+ }
+ LOG.trace("disconnected client: {}", client);
+ }
+
+ public HwvtepConnectionInstance connectedButCallBacksNotRegistered(final OvsdbClient externalClient) {
+ LOG.info("OVSDB Connection from {}:{}",externalClient.getConnectionInfo().getRemoteAddress(),
+ externalClient.getConnectionInfo().getRemotePort());
+ ConnectionInfo key = HwvtepSouthboundMapper.createConnectionInfo(externalClient);
+ HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstance(key);
+
+ // Check if existing hwvtepConnectionInstance for the OvsdbClient present.
+ // In such cases, we will see if the hwvtepConnectionInstance has same externalClient.
+ if (hwvtepConnectionInstance != null) {
+ if (hwvtepConnectionInstance.hasOvsdbClient(externalClient)) {
+ LOG.warn("HWVTEP Connection Instance {} already exists for client {}", key, externalClient);
+ return hwvtepConnectionInstance;
+ }
+ LOG.warn("HWVTEP Connection Instance {} being replaced with client {}", key, externalClient);
+ hwvtepConnectionInstance.disconnect();
+
+ // Unregister Cluster Ownership for ConnectionInfo
+ // Because the hwvtepConnectionInstance is about to be completely replaced!
+ unregisterEntityForOwnership(hwvtepConnectionInstance);
+
+ removeConnectionInstance(key);
+ }
+
+ hwvtepConnectionInstance = new HwvtepConnectionInstance(key, externalClient, getInstanceIdentifier(key),
+ txInvoker);
+ hwvtepConnectionInstance.createTransactInvokers();
+ return hwvtepConnectionInstance;
+ }
+
+ /* TODO:
+ public OvsdbClient connect(InstanceIdentifier<Node> iid, OvsdbNodeAugmentation ovsdbNode)
+ throws UnknownHostException {
+ }
+
+ public void disconnect(OvsdbNodeAugmentation ovsdbNode) throws UnknownHostException {
+ OvsdbConnectionInstance client = getConnectionInstance(ovsdbNode.getConnectionInfo());
+
+ }
+
+ */
+
+ private void putConnectionInstance(ConnectionInfo key,HwvtepConnectionInstance instance) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ clients.put(connectionInfo, instance);
+ LOG.info("Clients after put: {}", clients);
+ }
+
+ public HwvtepConnectionInstance getConnectionInstance(ConnectionInfo key) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ return clients.get(connectionInfo);
+ }
+
+ private void removeConnectionInstance(ConnectionInfo key) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ clients.remove(connectionInfo);
+ LOG.info("Clients after remove: {}", clients);
+ }
+
+ private void putInstanceIdentifier(ConnectionInfo key,InstanceIdentifier<Node> iid) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ instanceIdentifiers.put(connectionInfo, iid);
+ }
+
+ public InstanceIdentifier<Node> getInstanceIdentifier(ConnectionInfo key) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ InstanceIdentifier<Node> iid = instanceIdentifiers.get(connectionInfo);
+ return iid;
+ }
+
+ private void removeInstanceIdentifier(ConnectionInfo key) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ instanceIdentifiers.remove(connectionInfo);
+ }
+
+ private void registerEntityForOwnership(HwvtepConnectionInstance hwvtepConnectionInstance) {
+
+ Entity candidateEntity = getEntityFromConnectionInstance(hwvtepConnectionInstance);
+ entityConnectionMap.put(candidateEntity, hwvtepConnectionInstance);
+ hwvtepConnectionInstance.setConnectedEntity(candidateEntity);
+
+ try {
+ EntityOwnershipCandidateRegistration registration =
+ entityOwnershipService.registerCandidate(candidateEntity);
+ hwvtepConnectionInstance.setDeviceOwnershipCandidateRegistration(registration);
+ LOG.info("HWVTEP entity {} is registered for ownership.", candidateEntity);
+
+ //If entity already has owner, it won't get notification from EntityOwnershipService
+ //so cache the connection instances.
+ Optional<EntityOwnershipState> 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);
+ }
+ }
+ }
+ } catch (CandidateAlreadyRegisteredException e) {
+ LOG.warn("OVSDB entity {} was already registered for {} ownership", candidateEntity, e);
+ }
+
+ }
+
+ private Global getHwvtepGlobalTableEntry(HwvtepConnectionInstance connectionInstance) {
+ DatabaseSchema dbSchema = null;
+ Global globalRow = null;
+
+ try {
+ dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.databaseName).get();
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Not able to fetch schema for database {} from device {}",
+ HwvtepSchemaConstants.databaseName,connectionInstance.getConnectionInfo(),e);
+ }
+
+ if (dbSchema != null) {
+ GenericTableSchema hwvtepSchema = TyperUtils.getTableSchema(dbSchema, Global.class);
+
+ List<String> hwvtepTableColumn = new ArrayList<String>();
+ hwvtepTableColumn.addAll(hwvtepSchema.getColumns());
+ Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
+ selectOperation.setColumns(hwvtepTableColumn);;
+
+ ArrayList<Operation> operations = new ArrayList<Operation>();
+ operations.add(selectOperation);
+ operations.add(op.comment("Fetching hardware_vtep table rows"));
+
+ List<OperationResult> results = null;
+ try {
+ results = connectionInstance.transact(dbSchema, operations).get();
+ if (results != null ) {
+ OperationResult selectResult = results.get(0);
+ globalRow = TyperUtils.getTypedRowWrapper(
+ dbSchema,Global.class,selectResult.getRows().get(0));
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Not able to fetch hardware_vtep table row from device {}",
+ connectionInstance.getConnectionInfo(),e);
+ }
+ }
+ LOG.trace("Fetched global {} from hardware_vtep schema",globalRow);
+ return globalRow;
+ }
+
+ private Entity getEntityFromConnectionInstance(@Nonnull HwvtepConnectionInstance hwvtepConnectionInstance) {
+ YangInstanceIdentifier entityId = null;
+ InstanceIdentifier<Node> iid = hwvtepConnectionInstance.getInstanceIdentifier();;
+ if ( iid == null ) {
+ //TODO: Is Global the right one?
+ Global hwvtepGlobalRow = getHwvtepGlobalTableEntry(hwvtepConnectionInstance);
+ iid = HwvtepSouthboundMapper.getInstanceIdentifier(hwvtepGlobalRow);
+ LOG.info("InstanceIdentifier {} generated for device "
+ + "connection {}",iid, hwvtepConnectionInstance.getConnectionInfo());
+
+ }
+ entityId = HwvtepSouthboundUtil.getInstanceIdentifierCodec().getYangInstanceIdentifier(iid);
+ Entity deviceEntity = new Entity(ENTITY_TYPE, entityId);
+ LOG.debug("Entity {} created for device connection {}",
+ deviceEntity, hwvtepConnectionInstance.getConnectionInfo());
+ return deviceEntity;
+ }
+ private void unregisterEntityForOwnership(HwvtepConnectionInstance hwvtepConnectionInstance) {
+ hwvtepConnectionInstance.closeDeviceOwnershipCandidateRegistration();
+ entityConnectionMap.remove(hwvtepConnectionInstance.getConnectedEntity());
+ }
+
+ public void handleOwnershipChanged(EntityOwnershipChange ownershipChange) {
+ HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstanceFromEntity(ownershipChange.getEntity());
+ LOG.info("handleOwnershipChanged: {} event received for device {}",
+ ownershipChange, hwvtepConnectionInstance != null ? hwvtepConnectionInstance.getConnectionInfo()
+ : "THAT'S NOT REGISTERED BY THIS SOUTHBOUND PLUGIN INSTANCE");
+
+ if (hwvtepConnectionInstance == null) {
+ if (ownershipChange.isOwner()) {
+ LOG.warn("handleOwnershipChanged: found no connection instance for {}", ownershipChange.getEntity());
+ } else {
+ // EntityOwnershipService sends notification to all the nodes, irrespective of whether
+ // that instance registered for the device ownership or not. It is to make sure that
+ // If all the controller instance that was connected to the device are down, so the
+ // running instance can clear up the operational data store even though it was not
+ // connected to the device.
+ LOG.debug("handleOwnershipChanged: found no connection instance for {}", ownershipChange.getEntity());
+ }
+
+ // If entity has no owner, clean up the operational data store (it's possible because owner controller
+ // might went down abruptly and didn't get a chance to clean up the operational data store.
+ if (!ownershipChange.hasOwner()) {
+ LOG.debug("{} has no onwer, cleaning up the operational data store", ownershipChange.getEntity());
+ // Below code might look weird but it's required. We want to give first opportunity to the
+ // previous owner of the device to clean up the operational data store if there is no owner now.
+ // That way we will avoid lot of nasty md-sal exceptions because of concurrent delete.
+ if (ownershipChange.wasOwner()) {
+ cleanEntityOperationalData(ownershipChange.getEntity());
+ }
+ // If first cleanEntityOperationalData() was called, this call will be no-op.
+ cleanEntityOperationalData(ownershipChange.getEntity());
+ }
+ return;
+ }
+ //Connection detail need to be cached, irrespective of ownership result.
+ putConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo(),hwvtepConnectionInstance);
+
+ if (ownershipChange.isOwner() == hwvtepConnectionInstance.getHasDeviceOwnership()) {
+ LOG.debug("handleOwnershipChanged: no change in ownership for {}. Ownership status is : {}",
+ hwvtepConnectionInstance.getConnectionInfo(), hwvtepConnectionInstance.getHasDeviceOwnership());
+ return;
+ }
+
+ hwvtepConnectionInstance.setHasDeviceOwnership(ownershipChange.isOwner());
+ // You were not an owner, but now you are
+ if (ownershipChange.isOwner()) {
+ LOG.info("handleOwnershipChanged: *this* southbound plugin instance is owner of device {}",
+ hwvtepConnectionInstance.getConnectionInfo());
+
+ //*this* instance of southbound plugin is owner of the device,
+ //so register for monitor callbacks
+ hwvtepConnectionInstance.registerCallbacks();
+
+ } else {
+ //You were owner of the device, but now you are not. With the current ownership
+ //grant mechanism, this scenario should not occur. Because this scenario will occur
+ //when this controller went down or switch flap the connection, but in both the case
+ //it will go through the re-registration process. We need to implement this condition
+ //when clustering service implement a ownership grant strategy which can revoke the
+ //device ownership for load balancing the devices across the instances.
+ //Once this condition occur, we should unregister the callback.
+ LOG.error("handleOwnershipChanged: *this* southbound plugin instance is no longer the owner of device {}",
+ hwvtepConnectionInstance.getNodeId().getValue());
+ }
+ }
+
+ private void cleanEntityOperationalData(Entity entity) {
+ //TODO: remove entity from Operational DataStore
+ LOG.error("cleanEntityOperationalData(): Code incomplete");
+ }
+
+ private HwvtepConnectionInstance getConnectionInstanceFromEntity(Entity entity) {
+ return entityConnectionMap.get(entity);
+ }
+
+ private class HwvtepDeviceEntityOwnershipListener implements EntityOwnershipListener {
+ private HwvtepConnectionManager hcm;
+ private EntityOwnershipListenerRegistration listenerRegistration;
+
+ HwvtepDeviceEntityOwnershipListener(HwvtepConnectionManager hcm, EntityOwnershipService entityOwnershipService) {
+ this.hcm = hcm;
+ listenerRegistration = entityOwnershipService.registerListener(ENTITY_TYPE, this);
+ }
+ public void close() {
+ listenerRegistration.close();
+ }
+ @Override
+ public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+ hcm.handleOwnershipChanged(ownershipChange);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.HwvtepOperationalCommandAggregator;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.lib.MonitorCallBack;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepMonitorCallback implements MonitorCallBack {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepMonitorCallback.class);
+ private HwvtepConnectionInstance key;
+ private TransactionInvoker txInvoker;
+
+ HwvtepMonitorCallback(HwvtepConnectionInstance key,TransactionInvoker txInvoker) {
+ this.txInvoker = txInvoker;
+ this.key = key;
+ }
+
+ @Override
+ public void update(TableUpdates result, DatabaseSchema dbSchema) {
+ LOG.debug("result: {} dbSchema: {}",result,dbSchema);
+ txInvoker.invoke(new HwvtepOperationalCommandAggregator(key, result, dbSchema));
+ LOG.trace("update exit");
+ }
+
+ @Override
+ public void exception(Throwable exception) {
+ LOG.warn("exception {}", exception);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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;
+
+public class HwvtepSchemaConstants {
+ public static final String databaseName = "hardware_vtep";
+ public enum HWVTEPSCHEMATABLES {
+ GLOBAL("Global", null, null),
+ MANAGER("Manager","Global","managers"),
+ PHYSICALSWITCH("Physical_Switch","Global","switches"),
+ PHYSICALPORT("Physical_Port","Physical_Switch","ports"),
+ TUNNEL("Tunnel","Physical_Switch","tunnels"),
+ LOGICALSWITCH("Logical_Switch","Physical_Port","vlan_bindings"),
+ ACL("ACL","Physical_Port","acl_bindings"),
+ LOGICALBINDINGSTATS("Logical_Binding_Stats","Physical_Port","vlan_stats"),
+// PHYSICALLOCATORLOCAL("Physical_Locator","Tunnel","local"),
+// PHYSICALLOCATORREMOTE("Physical_Locator","Tunnel","remote"),
+ UCASTMACSLOCAL("Ucast_Macs_Local",null, null),
+ UCASTMACSREMOTE("Ucast_Macs_Remote",null, null),
+ MCASTMACSLOCAL("Mcast_Macs_Local",null, null),
+ PHYSICALLOCATORSET("Physical_Locator_Set","Mcast_Macs_Local", "locator_set"),
+ MCASTMACSREMOTE("Mcast_Macs_Remote",null, null),
+ LOGICALROUTER("Logical_Router",null, null),
+ ARPSOURCESLOCAL("Arp_Sources_Local",null, null),
+ ARPSOURCESREMOTE("Arp_Sources_Remote",null, null),
+ PHYSICALLOCATOR("Physical_Locator","Physical_Locator_Set", "locators"),
+ ACLENTRY("Acl_Entry","ACL", "acl_entries");
+
+ private final String tableName;
+ private final String parentTableName;
+ private final String columnNameInParentTable;
+
+ private HWVTEPSCHEMATABLES(final String tableName, final String parentTableName,
+ final String columnNameInParentTable) {
+ this.tableName = tableName;
+ this.parentTableName = parentTableName;
+ this.columnNameInParentTable = columnNameInParentTable;
+ }
+
+ public String getTableName() {
+ return this.tableName;
+ }
+
+ public String getParentTableName() {
+ return this.parentTableName;
+ }
+
+ public String getColumnNameInParentTable() {
+ return this.columnNameInParentTable;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+
+public class HwvtepSouthboundConstants {
+
+ public static final TopologyId HWVTEP_TOPOLOGY_ID = new TopologyId(new Uri("hwvtep:1"));
+ public static final String HWVTEP_URI_PREFIX = "hwvtep";
+ public static final Integer DEFAULT_OVSDB_PORT = 6640;
+ public static final String IID_OTHER_CONFIG_KEY = "opendaylight-iid";
+ public static final String UUID = "uuid";
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfoBuilder;
+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.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepSouthboundMapper {
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundMapper.class);
+ private static final String N_CONNECTIONS_STR = "n_connections";
+
+ private static NodeId createNodeId(HwvtepConnectionInstance client) {
+ NodeKey key = client.getInstanceIdentifier().firstKeyOf(Node.class, NodeKey.class);
+ return key.getNodeId();
+
+ }
+
+ public static InstanceIdentifier<Node> createInstanceIdentifier(NodeId nodeId) {
+ InstanceIdentifier<Node> nodePath = InstanceIdentifier
+ .create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+ .child(Node.class,new NodeKey(nodeId));
+ return nodePath;
+ }
+
+ public static InstanceIdentifier<Node> createInstanceIdentifier (OvsdbClient client) {
+ return createInstanceIdentifier(createIpAddress(client.getConnectionInfo().getRemoteAddress()),
+ new PortNumber(client.getConnectionInfo().getRemotePort()));
+ }
+
+ private static InstanceIdentifier<Node> createInstanceIdentifier(IpAddress ip, PortNumber port) {
+ String uriString = HwvtepSouthboundConstants.HWVTEP_URI_PREFIX + "://"
+ + new String(ip.getValue()) + ":" + port.getValue();
+ Uri uri = new Uri(uriString);
+ NodeId nodeId = new NodeId(uri);
+ InstanceIdentifier<Node> path = InstanceIdentifier.create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+ .child(Node.class,new NodeKey(nodeId));
+ LOG.debug("Created ovsdb path: {}",path);
+ return path;
+ }
+
+ public static NodeId createManagedNodeId(InstanceIdentifier<Node> iid) {
+ NodeKey nodeKey = iid.firstKeyOf(Node.class, NodeKey.class);
+ return nodeKey.getNodeId();
+ }
+
+ public static IpAddress createIpAddress(InetAddress address) {
+ IpAddress ip = null;
+ if (address instanceof Inet4Address) {
+ ip = createIpAddress((Inet4Address)address);
+ } else if (address instanceof Inet6Address) {
+ ip = createIpAddress((Inet6Address)address);
+ }
+ return ip;
+ }
+
+ public static IpAddress createIpAddress(Inet4Address address) {
+ Ipv4Address ipv4 = new Ipv4Address(address.getHostAddress());
+ return new IpAddress(ipv4);
+ }
+
+ public static IpAddress createIpAddress(Inet6Address address) {
+ Ipv6Address ipv6 = new Ipv6Address(address.getHostAddress());
+ return new IpAddress(ipv6);
+ }
+
+ public static ConnectionInfo createConnectionInfo(OvsdbClient client) {
+ ConnectionInfoBuilder connectionInfoBuilder = new ConnectionInfoBuilder();
+ connectionInfoBuilder.setRemoteIp(createIpAddress(client.getConnectionInfo().getRemoteAddress()));
+ connectionInfoBuilder.setRemotePort(new PortNumber(client.getConnectionInfo().getRemotePort()));
+ connectionInfoBuilder.setLocalIp(createIpAddress(client.getConnectionInfo().getLocalAddress()));
+ connectionInfoBuilder.setLocalPort(new PortNumber(client.getConnectionInfo().getLocalPort()));
+ return connectionInfoBuilder.build();
+ }
+
+ public static ConnectionInfo suppressLocalIpPort(ConnectionInfo connectionInfo) {
+ ConnectionInfoBuilder connectionInfoBuilder = new ConnectionInfoBuilder();
+ connectionInfoBuilder.setRemoteIp(connectionInfo.getRemoteIp());
+ connectionInfoBuilder.setRemotePort(connectionInfo.getRemotePort());
+ return connectionInfoBuilder.build();
+ }
+
+ public static InstanceIdentifier<Node> getInstanceIdentifier(Global global) {
+ InstanceIdentifier<Node> iid = null;
+ if (global.getManagersColumn() != null
+ && global.getManagersColumn().getData() != null) {
+ String iidString = global.getManagersColumn().getData().iterator().next().toString();
+ iid = (InstanceIdentifier<Node>) HwvtepSouthboundUtil.deserializeInstanceIdentifier(iidString);
+ } else {
+ String nodeString = HwvtepSouthboundConstants.HWVTEP_URI_PREFIX + "://" +
+ HwvtepSouthboundConstants.UUID + "/" + global.getUuid().toString();
+ NodeId nodeId = new NodeId(new Uri(nodeString));
+ NodeKey nodeKey = new NodeKey(nodeId);
+ TopologyKey topoKey = new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
+ iid = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, topoKey)
+ .child(Node.class,nodeKey)
+ .build();
+ }
+ return iid;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl;
+import org.opendaylight.ovsdb.lib.OvsdbConnection;
+import org.opendaylight.ovsdb.lib.impl.OvsdbConnectionService;
+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.NetworkTopologyBuilder;
+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.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+public class HwvtepSouthboundProvider implements BindingAwareProvider, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundProvider.class);
+ private static final String ENTITY_TYPE = "ovsdb-hwvtepsouthbound-provider";
+
+ public static DataBroker getDb() {
+ return db;
+ }
+
+ private static DataBroker db;
+ private HwvtepConnectionManager cm;
+ private OvsdbConnection ovsdbConnection;
+ private TransactionInvoker txInvoker;
+ private EntityOwnershipService entityOwnershipService;
+ private EntityOwnershipCandidateRegistration registration;
+ private HwvtepsbPluginInstanceEntityOwnershipListener providerOwnershipChangeListener;
+
+ public HwvtepSouthboundProvider(
+ EntityOwnershipService entityOwnershipServiceDependency) {
+ this.entityOwnershipService = entityOwnershipServiceDependency;
+ registration = null;
+ }
+
+ @Override
+ public void onSessionInitiated(ProviderContext session) {
+ LOG.info("HwvtepSouthboundProvider Session Initiated");
+ db = session.getSALService(DataBroker.class);
+ txInvoker = new TransactionInvokerImpl(db);
+ cm = new HwvtepConnectionManager(db, txInvoker, entityOwnershipService);
+ //TODO: Add DataChange Listener
+
+ //Register listener for entityOnwership changes
+ providerOwnershipChangeListener =
+ new HwvtepsbPluginInstanceEntityOwnershipListener(this,this.entityOwnershipService);
+ entityOwnershipService.registerListener(ENTITY_TYPE,providerOwnershipChangeListener);
+
+ //register instance entity to get the ownership of the provider
+ Entity instanceEntity = new Entity(ENTITY_TYPE, ENTITY_TYPE);
+ try {
+ registration = entityOwnershipService.registerCandidate(instanceEntity);
+ } catch (CandidateAlreadyRegisteredException e) {
+ LOG.warn("HWVTEP Southbound Provider instance entity {} was already "
+ + "registered for {} ownership", instanceEntity, e);
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.info("HwvtepSouthboundProvider Closed");
+ if(cm != null){
+ cm.close();
+ cm = null;
+ }
+ if(registration != null) {
+ registration.close();
+ registration = null;
+ }
+ if(providerOwnershipChangeListener != null) {
+ providerOwnershipChangeListener.close();
+ providerOwnershipChangeListener = null;
+ }
+ }
+
+ private void initializeHwvtepTopology(LogicalDatastoreType type) {
+ InstanceIdentifier<Topology> path = InstanceIdentifier
+ .create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID));
+ initializeTopology(type);
+ ReadWriteTransaction transaction = db.newReadWriteTransaction();
+ CheckedFuture<Optional<Topology>, ReadFailedException> hwvtepTp = transaction.read(type, path);
+ try {
+ if (!hwvtepTp.get().isPresent()) {
+ TopologyBuilder tpb = new TopologyBuilder();
+ tpb.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
+ transaction.put(type, path, tpb.build());
+ transaction.submit();
+ } else {
+ transaction.cancel();
+ }
+ } catch (Exception e) {
+ LOG.error("Error initializing hwvtep topology", e);
+ }
+ }
+
+ private void initializeTopology(LogicalDatastoreType type) {
+ ReadWriteTransaction transaction = db.newReadWriteTransaction();
+ InstanceIdentifier<NetworkTopology> path = InstanceIdentifier.create(NetworkTopology.class);
+ CheckedFuture<Optional<NetworkTopology>, ReadFailedException> topology = transaction.read(type,path);
+ try {
+ if (!topology.get().isPresent()) {
+ NetworkTopologyBuilder ntb = new NetworkTopologyBuilder();
+ transaction.put(type,path,ntb.build());
+ transaction.submit();
+ } else {
+ transaction.cancel();
+ }
+ } catch (Exception e) {
+ LOG.error("Error initializing hwvtep topology {}",e);
+ }
+ }
+
+ public void handleOwnershipChange(EntityOwnershipChange ownershipChange) {
+ if (ownershipChange.isOwner()) {
+ LOG.info("*This* instance of HWVTEP southbound provider is set as a MASTER instance");
+ LOG.info("Initialize HWVTEP topology {} in operational and config data store if not already present"
+ ,HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
+ initializeHwvtepTopology(LogicalDatastoreType.OPERATIONAL);
+ initializeHwvtepTopology(LogicalDatastoreType.CONFIGURATION);
+ } else {
+ LOG.info("*This* instance of HWVTEP southbound provider is set as a SLAVE instance");
+ }
+ //TODO: How to make this co-exist with OvsdbSouthbound?
+ if (ovsdbConnection == null) {
+ ovsdbConnection = new OvsdbConnectionService();
+ ovsdbConnection.registerConnectionListener(cm);
+ ovsdbConnection.startOvsdbManager(HwvtepSouthboundConstants.DEFAULT_OVSDB_PORT);
+ }
+ }
+
+ private class HwvtepsbPluginInstanceEntityOwnershipListener implements EntityOwnershipListener {
+ private HwvtepSouthboundProvider hsp;
+ private EntityOwnershipListenerRegistration listenerRegistration;
+
+ HwvtepsbPluginInstanceEntityOwnershipListener(HwvtepSouthboundProvider hsp,
+ EntityOwnershipService entityOwnershipService) {
+ this.hsp = hsp;
+ listenerRegistration = entityOwnershipService.registerListener(ENTITY_TYPE, this);
+ }
+
+ public void close() {
+ this.listenerRegistration.close();
+ }
+ @Override
+ public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+ hsp.handleOwnershipChange(ownershipChange);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, 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.hwvtepsouthbound;
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepSouthboundUtil {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundUtil.class);
+
+ private static InstanceIdentifierCodec instanceIdentifierCodec;
+
+ private HwvtepSouthboundUtil() {
+ // Prevent instantiating a utility class
+ }
+
+ public static void setInstanceIdentifierCodec(InstanceIdentifierCodec iidc) {
+ instanceIdentifierCodec = iidc;
+ }
+
+ public static InstanceIdentifierCodec getInstanceIdentifierCodec() {
+ return instanceIdentifierCodec;
+ }
+
+ public static String serializeInstanceIdentifier(InstanceIdentifier<?> iid) {
+ return instanceIdentifierCodec.serialize(iid);
+ }
+
+ public static InstanceIdentifier<?> deserializeInstanceIdentifier(String iidString) {
+ InstanceIdentifier<?> result = null;
+ try {
+ result = instanceIdentifierCodec.bindingDeserializer(iidString);
+ } catch (DeserializationException e) {
+ LOG.warn("Unable to deserialize iidString", e);
+ }
+ return result;
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.net.URI;
+
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+
+public class InstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec
+ implements SchemaContextListener {
+
+ private DataSchemaContextTree dataSchemaContextTree;
+ private SchemaContext context;
+ private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+
+ public InstanceIdentifierCodec(SchemaService schemaService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+ schemaService.registerSchemaContextListener(this);
+ this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
+ }
+
+ @Override
+ protected DataSchemaContextTree getDataContextTree() {
+ return dataSchemaContextTree;
+ }
+
+ @Override
+ protected Module moduleForPrefix(final String prefix) {
+ return context.findModuleByName(prefix, null);
+ }
+
+ @Override
+ protected String prefixForNamespace(final URI namespace) {
+ final Module module = context.findModuleByNamespaceAndRevision(namespace, null);
+ return module == null ? null : module.getName();
+ }
+
+ @Override
+ public void onGlobalContextUpdated(SchemaContext context) {
+ this.context = context;
+ this.dataSchemaContextTree = DataSchemaContextTree.from(context);
+ }
+
+ public String serialize(InstanceIdentifier<?> iid) {
+ YangInstanceIdentifier normalizedIid = bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid);
+ return serialize(normalizedIid);
+ }
+
+ public YangInstanceIdentifier getYangInstanceIdentifier(InstanceIdentifier<?> iid) {
+ return bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid);
+ }
+
+ public InstanceIdentifier<?> bindingDeserializer(String iidString) throws DeserializationException {
+ YangInstanceIdentifier normalizedYangIid = deserialize(iidString);
+ InstanceIdentifier<?> iid = bindingNormalizedNodeSerializer.fromYangInstanceIdentifier(normalizedYangIid);
+ return iid;
+ }
+
+ public InstanceIdentifier<?> bindingDeserializer(YangInstanceIdentifier yangIID) {
+ InstanceIdentifier<?> iid = bindingNormalizedNodeSerializer.fromYangInstanceIdentifier(yangIID);
+ return iid;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2015 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.impl;
-
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class HwvtepSouthboundProvider implements BindingAwareProvider, AutoCloseable {
-
- private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundProvider.class);
-
- @Override
- public void onSessionInitiated(ProviderContext session) {
- LOG.info("HwvtepSouthboundProvider Session Initiated");
- }
-
- @Override
- public void close() throws Exception {
- LOG.info("HwvtepSouthboundProvider Closed");
- }
-
-}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.lib.operations.TransactionBuilder;
+
+public interface TransactCommand {
+
+ void execute(TransactionBuilder transaction);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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;
+
+public interface TransactInvoker {
+ void invoke(TransactCommand command);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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 java.util.List;
+
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.lib.operations.OperationResult;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class TransactInvokerImpl implements TransactInvoker {
+ private static final Logger LOG = LoggerFactory.getLogger(TransactInvokerImpl.class);
+ private HwvtepConnectionInstance connectionInstance;
+ private DatabaseSchema dbSchema;
+
+ public TransactInvokerImpl(HwvtepConnectionInstance connectionInstance, DatabaseSchema dbSchema) {
+ this.connectionInstance = connectionInstance;
+ this.dbSchema = dbSchema;
+ }
+
+ @Override
+ public void invoke(TransactCommand command) {
+ TransactionBuilder tb = new TransactionBuilder(connectionInstance, dbSchema);
+ command.execute(tb);
+ ListenableFuture<List<OperationResult>> result = tb.execute();
+ LOG.debug("invoke: command: {}, tb: {}", command, tb);
+ if (tb.getOperations().size() > 0) {
+ try {
+ List<OperationResult> got = result.get();
+ LOG.debug("OVSDB transaction result: {}", got);
+ } catch (Exception e) {
+ LOG.warn("Transact execution exception: ", e);
+ }
+ LOG.trace("invoke exit command: {}, tb: {}", command, tb);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, 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.hwvtepsouthbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+
+public class HwvtepOperationalCommandAggregator implements TransactionCommand {
+
+
+ private List<TransactionCommand> commands = new ArrayList<TransactionCommand>();
+
+ public HwvtepOperationalCommandAggregator(HwvtepConnectionInstance key,TableUpdates updates,
+ DatabaseSchema dbSchema) {
+ //TODO: Add commands in here
+ }
+
+ @Override
+ public void execute(ReadWriteTransaction transaction) {
+ for (TransactionCommand command: commands) {
+ command.execute(transaction);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.transactions.md;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+
+public interface TransactionCommand {
+
+ void execute(ReadWriteTransaction transaction);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 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.transactions.md;
+
+public interface TransactionInvoker {
+
+ void invoke(TransactionCommand command);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, 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.hwvtepsouthbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+/* TODO:
+ * Copied over as-is from southbound plugin. Good candidate to be common
+ * when refactoring code.
+ */
+public class TransactionInvokerImpl implements TransactionInvoker,TransactionChainListener, Runnable, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(TransactionInvokerImpl.class);
+ private static final int QUEUE_SIZE = 10000;
+ private BindingTransactionChain chain;
+ private DataBroker db;
+ private BlockingQueue<TransactionCommand> inputQueue = new LinkedBlockingQueue<TransactionCommand>(QUEUE_SIZE);
+ private BlockingQueue<ReadWriteTransaction> successfulTransactionQueue
+ = new LinkedBlockingQueue<ReadWriteTransaction>(QUEUE_SIZE);
+ private BlockingQueue<AsyncTransaction<?, ?>> failedTransactionQueue
+ = new LinkedBlockingQueue<AsyncTransaction<?, ?>>(QUEUE_SIZE);
+ private ExecutorService executor;
+ private Map<ReadWriteTransaction,TransactionCommand> transactionToCommand
+ = new HashMap<ReadWriteTransaction,TransactionCommand>();
+ private List<ReadWriteTransaction> pendingTransactions = new ArrayList<ReadWriteTransaction>();
+
+ public TransactionInvokerImpl(DataBroker db) {
+ this.db = db;
+ this.chain = db.createTransactionChain(this);
+ ThreadFactory threadFact = new ThreadFactoryBuilder().setNameFormat("transaction-invoker-impl-%d").build();
+ executor = Executors.newSingleThreadExecutor(threadFact);
+ executor.submit(this);
+ }
+
+ @Override
+ public void invoke(final TransactionCommand command) {
+ // TODO what do we do if queue is full?
+ inputQueue.offer(command);
+ }
+
+ @Override
+ public void onTransactionChainFailed(TransactionChain<?, ?> chain,
+ AsyncTransaction<?, ?> transaction, Throwable cause) {
+ failedTransactionQueue.offer(transaction);
+ }
+
+ @Override
+ public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
+ // NO OP
+
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ forgetSuccessfulTransactions();
+ try {
+ List<TransactionCommand> commands = extractCommands();
+ for (TransactionCommand command: commands) {
+ final ReadWriteTransaction transaction = chain.newReadWriteTransaction();
+ recordPendingTransaction(command, transaction);
+ command.execute(transaction);
+ Futures.addCallback(transaction.submit(), new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(final Void result) {
+ successfulTransactionQueue.offer(transaction);
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ // NOOP - handled by failure of transaction chain
+ }
+ });
+ }
+ } catch (Exception e) {
+ LOG.warn("Exception invoking Transaction: ", e);
+ }
+ }
+ }
+
+ private List<TransactionCommand> extractResubmitCommands() {
+ AsyncTransaction<?, ?> transaction = failedTransactionQueue.poll();
+ List<TransactionCommand> commands = new ArrayList<TransactionCommand>();
+ if (transaction != null) {
+ int index = pendingTransactions.lastIndexOf(transaction);
+ List<ReadWriteTransaction> transactions =
+ pendingTransactions.subList(index, pendingTransactions.size() - 1);
+ for (ReadWriteTransaction tx: transactions) {
+ commands.add(transactionToCommand.get(tx));
+ }
+ resetTransactionQueue();
+ }
+ return commands;
+ }
+
+ private void resetTransactionQueue() {
+ chain.close();
+ chain = db.createTransactionChain(this);
+ pendingTransactions = new ArrayList<ReadWriteTransaction>();
+ transactionToCommand = new HashMap<ReadWriteTransaction,TransactionCommand>();
+ failedTransactionQueue.clear();
+ successfulTransactionQueue.clear();
+ }
+
+ private void recordPendingTransaction(TransactionCommand command,
+ final ReadWriteTransaction transaction) {
+ transactionToCommand.put(transaction, command);
+ pendingTransactions.add(transaction);
+ }
+
+ private List<TransactionCommand> extractCommands() throws InterruptedException {
+ List<TransactionCommand> commands = extractResubmitCommands();
+ commands.addAll(extractCommandsFromQueue());
+ return commands;
+ }
+
+ private List<TransactionCommand> extractCommandsFromQueue() throws InterruptedException {
+ List<TransactionCommand> result = new ArrayList<TransactionCommand>();
+ TransactionCommand command = inputQueue.take();
+ while (command != null) {
+ result.add(command);
+ command = inputQueue.poll();
+ }
+ return result;
+ }
+
+ private void forgetSuccessfulTransactions() {
+ ReadWriteTransaction transaction = successfulTransactionQueue.poll();
+ while (transaction != null) {
+ pendingTransactions.remove(transaction);
+ transactionToCommand.remove(transaction);
+ transaction = successfulTransactionQueue.poll();
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ this.executor.shutdown();
+ }
+}
package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901;
-import org.opendaylight.ovsdb.hwvtepsouthbound.impl.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
+import org.opendaylight.ovsdb.hwvtepsouthbound.InstanceIdentifierCodec;
public class HwvtepSouthboundModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901.AbstractHwvtepSouthboundModule {
public HwvtepSouthboundModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
@Override
public java.lang.AutoCloseable createInstance() {
- HwvtepSouthboundProvider provider = new HwvtepSouthboundProvider();
+ HwvtepSouthboundUtil.setInstanceIdentifierCodec(new InstanceIdentifierCodec(getSchemaServiceDependency(),
+ getBindingNormalizedNodeSerializerDependency()));
+ HwvtepSouthboundProvider provider = new HwvtepSouthboundProvider(getClusteringEntityOwnershipServiceDependency());
getBrokerDependency().registerProvider(provider);
return provider;
}
import config { prefix config; revision-date 2013-04-05; }
import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+ import opendaylight-entity-ownership-service {prefix eos; revision-date 2015-08-10;}
+ import opendaylight-md-sal-dom {prefix dom; revision-date 2013-10-28;}
description
"Service definition for hwvtepsouthbound project";
}
}
}
+ container schema-service {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity dom:schema-service;
+ }
+ }
+ }
+ container clustering-entity-ownership-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity eos:entity-ownership-service;
+ }
+ }
+ }
+ container binding-normalized-node-serializer {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-normalized-node-serializer;
+ }
+ }
+ }
}
}
}
*/
package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901;
+import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.ovsdb.hwvtepsouthbound.impl.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundProvider;
import javax.management.ObjectName;
module.customValidation();
}
+ //TODO: Ignore for now, will be replaced with better UT
+ @Ignore
@Test
public void testCreateInstance() throws Exception {
// configure mocks
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
</dependency>
- <dependency>
- <groupId>org.opendaylight.neutron</groupId>
- <artifactId>neutron-spi</artifactId>
- <version>${networkconfig.neutron.version}</version>
- </dependency>
<dependency>
<groupId>org.opendaylight.openflowplugin.model</groupId>
<artifactId>model-flow-base</artifactId>
<instructions>
<Embed-Dependency>utils.config,utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
+ <Export-Package>
+ org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.*
+ </Export-Package>
</instructions>
</configuration>
</plugin>
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
import org.opendaylight.ovsdb.openstack.netvirt.MdsalHelper;
import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
LOG.warn("programLocalRules: No DCHP port seen in network of {}", intf);
}
}
+
+ /*
+ * The function is for the new compute node joining the existing network.
+ * When a new VM is instantiated in the new compute node, neutron port add
+ * event is generated. This event is processed only for that node. So,
+ * loop through all the ports of the same network and install unicast mac
+ * flow for the VM's created on the TEP of the destination node in src node.
+ * This function will be executed even for any new VM creation in an existing
+ * network. If a cache is maintained to optimize the below flow addition, it will
+ * work only for one unstack and restack. For the next unstack and restack,
+ * it will not work since the cache would have been already deleted.
+ */
+ private void programTunnelRulesInNewNode(NeutronNetwork network,
+ String networkType, String segmentationId,
+ InetAddress src, InetAddress dst,
+ Node srcBridgeNode, Node dstBridgeNode,
+ OvsdbTerminationPointAugmentation intf){
+ try {
+ long localPort = southbound.getOFPort(intf);
+ if(localPort != 0)
+ {
+ LOG.debug("Interface update details {}", intf);
+
+ /*
+ * When a network is added and the TEP destination is not present in a
+ * node C1, tunnelin and broadcast rules will not be programmed, since
+ * OF port is not created. So, when a new node C2 joins and create a new
+ * VM, the tunnelin and broadcast rule will not be present in C1.
+ * So, handling it in the case below to make ping work.
+ */
+ if(securityServicesManager.getNeutronPortFromDhcpIntf(intf) == null){
+ programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
+ }
+
+ /*
+ * FIX for 4208 - loop through all the ports and add the VM's
+ * unicast mac rule of the destination node in the source node.
+ * When a new node is added, it needs to configure the VM unicast mac
+ * flow rules which were created before it was joined to an existing
+ * network.
+ */
+ List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(dstBridgeNode);
+ for (OvsdbTerminationPointAugmentation port : ports) {
+ if(network == tenantNetworkManager.getTenantNetwork(port)){
+ programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, port, false);
+ }
+ else{
+ LOG.trace("Port {} is not part of network {}", port, network);
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("Exception during handlingNeutron network add", e);
+ }
+ }
+
@Override
public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode,
OvsdbTerminationPointAugmentation intf) {
programVlanRules(network, srcNode, intf);
} else if (isTunnel(networkType)){
- boolean sourceTunnelStatus;
+ boolean sourceTunnelStatus = false;
boolean destTunnelStatus = false;
for (Node dstNode : nodes.values()) {
InetAddress src = configurationService.getTunnelEndPoint(srcNode);
}
if (destTunnelStatus) {
programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
+ programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
+ srcBridgeNode, dstBridgeNode, intf);
}
} else {
LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
import java.math.BigInteger;
import java.util.List;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
private static final int DHCP_SOURCE_PORT = 67;
private static final int DHCP_DESTINATION_PORT = 68;
private static final String HOST_MASK = "/32";
+ private static final int PORT_RANGE_MIN = 1;
+ private static final int PORT_RANGE_MAX = 65535;
public EgressAclService() {
super(Service.EGRESS_ACL);
NeutronSecurityRule portSecurityRule, String dstAddress,
boolean write, Integer protoPortMatchPriority) {
MatchBuilder matchBuilder = new MatchBuilder();
- String flowId = "Egress_Custom_Tcp" + segmentationId + "_" + srcMac + "_";
+ String flowId = "Egress_TCP_" + segmentationId + "_" + srcMac + "_";
matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
+
+ /* Custom TCP Match */
if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
- flowId = flowId + portSecurityRule.getSecurityRulePortMin();
+ flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
portSecurityRule.getSecurityRulePortMin());
} else {
+ /* All TCP Match */
+ if(portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+ && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+ flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_" +
+ portSecurityRule.getSecurityRulePortMax()+ "_";
+ matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
+ }
/*TODO TCP PortRange Match*/
}
new Ipv4Prefix(portSecurityRule
.getSecurityRuleRemoteIpPrefix()));
}
- flowId = flowId + "_Permit_";
+ flowId = flowId + "_Permit";
String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
boolean write, Integer protoPortMatchPriority) {
MatchBuilder matchBuilder = new MatchBuilder();
- String flowId = "Eress_UDP" + segmentationId + "_" + srcMac + "_";
+ String flowId = "Egress_UDP_" + segmentationId + "_" + srcMac + "_";
matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
+
+ /* Custom UDP Match */
if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
- flowId = flowId + portSecurityRule.getSecurityRulePortMin();
+ flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
portSecurityRule.getSecurityRulePortMin());
} else {
+ /* All UDP Match */
+ if(portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+ && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+ flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_" +
+ portSecurityRule.getSecurityRulePortMax()+ "_";
+ matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
+ }
/*TODO UDP PortRange Match*/
}
new Ipv4Prefix(portSecurityRule
.getSecurityRuleRemoteIpPrefix()));
}
- flowId = flowId + "_Permit_";
+ flowId = flowId + "_Permit";
String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
import java.math.BigInteger;
import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
import java.util.List;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class InboundNatService extends AbstractServiceInstance implements ConfigInterface, InboundNatProvider {
+ private static final Logger LOG = LoggerFactory.getLogger(InboundNatService.class);
public static final Class<? extends NxmNxReg> REG_FIELD = NxmNxReg3.class;
public InboundNatService() {
InstructionBuilder ib;
MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+ String ipAddress = excludedCidr.substring(0, excludedCidr.indexOf("/"));
+ InetAddress inetAddress;
+ try {
+ inetAddress = InetAddress.getByName(ipAddress);
+ } catch (UnknownHostException e) {
+ return new Status(StatusCode.BADREQUEST);
+ }
+ if (inetAddress instanceof Inet6Address) {
+ // WORKAROUND: For now ipv6 is not supported
+ // TODO: implement ipv6 cidr case
+ LOG.debug("ipv6 cidr is not implemented yet. cidr {}",
+ excludedCidr);
+ return new Status(StatusCode.NOTIMPLEMENTED);
+ }
MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(excludedCidr));
// Goto Next Table
import java.math.BigInteger;
import java.util.List;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
private static final Logger LOG = LoggerFactory.getLogger(IngressAclService.class);
private volatile SecurityServicesManager securityServicesManager;
+ private static final int PORT_RANGE_MIN = 1;
+ private static final int PORT_RANGE_MAX = 65535;
public IngressAclService() {
super(Service.INGRESS_ACL);
MatchBuilder matchBuilder = new MatchBuilder();
FlowBuilder flowBuilder = new FlowBuilder();
- String flowId = "Ingress_Custom_Tcp" + segmentationId + "_" + dstMac + "_";
+ String flowId = "Ingress_TCP_" + segmentationId + "_" + dstMac + "_";
matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
+
+ /* Custom TCP Match*/
if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
- flowId = flowId + portSecurityRule.getSecurityRulePortMin();
+ flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
portSecurityRule.getSecurityRulePortMin());
} else {
+ /* All TCP Match */
+ if(portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+ && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+ flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_" +
+ portSecurityRule.getSecurityRulePortMax()+ "_";
+ matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
+ }
/*TODO TCP PortRange Match*/
}
}
String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
- flowId = flowId + "_Permit_";
+ flowId = flowId + "_Permit";
syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
}
NeutronSecurityRule portSecurityRule, String srcAddress,
boolean write, Integer protoPortMatchPriority ) {
MatchBuilder matchBuilder = new MatchBuilder();
- String flowId = "ingressAclUDP" + segmentationId + "_" + dstMac + "_";
+ String flowId = "Ingress_UDP_" + segmentationId + "_" + dstMac + "_";
matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
+
+ /* Custom UDP Match */
if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
- flowId = flowId + portSecurityRule.getSecurityRulePortMin();
+ flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
portSecurityRule.getSecurityRulePortMin());
} else {
+ /* All UDP Match */
+ if(portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+ && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+ flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_" +
+ portSecurityRule.getSecurityRulePortMax()+ "_";
+ matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
+ }
/*TODO TCP PortRange Match*/
}
}
String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
- flowId = flowId + "_Permit_";
+ flowId = flowId + "_Permit";
syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
}
import java.math.BigInteger;
import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
import java.util.List;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import com.google.common.collect.Lists;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class OutboundNatService extends AbstractServiceInstance implements OutboundNatProvider, ConfigInterface {
+ private static final Logger LOG = LoggerFactory.getLogger(OutboundNatService.class);
+
public OutboundNatService() {
super(Service.OUTBOUND_NAT);
}
InstructionBuilder ib;
MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+ String ipAddress = excludedCidr.substring(0, excludedCidr.indexOf("/"));
+ InetAddress inetAddress;
+ try {
+ inetAddress = InetAddress.getByName(ipAddress);
+ } catch (UnknownHostException e) {
+ return new Status(StatusCode.BADREQUEST);
+ }
+ if (inetAddress instanceof Inet6Address) {
+ // WORKAROUND: For now ipv6 is not supported
+ // TODO: implement ipv6 cidr case
+ LOG.debug("ipv6 cidr is not implemented yet. cidr {}",
+ excludedCidr);
+ return new Status(StatusCode.NOTIMPLEMENTED);
+ }
MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(excludedCidr));
// Goto Next Table
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
import org.opendaylight.ovsdb.openstack.netvirt.MdsalHelper;
import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;
private static final String SEGMENT_ID = "2";
private static final Long DP_ID_LONG = (long) 1554;
private static final Long LOCAL_PORT = (long) 124;
+ private static final int PORT_RANGE_MIN = 1;
+ private static final int PORT_RANGE_MAX = 65535;
private static FlowBuilder flowBuilder;
private static NodeBuilder nodeBuilder;
@Test
public void testProgramPortSecurityACLRuleAddTcp1() throws Exception {
when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
- when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
- when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(20);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(20);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
- egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
- verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
- verify(writeTransaction, times(1)).submit();
- verify(commitFuture, times(1)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+ Assert.assertEquals(20, layer4Match.getTcpDestinationPort().getValue().intValue());
+ int port=portSecurityRule.getSecurityRulePortMin();
+ Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+ "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
}
/**
@Test
public void testProgramPortSecurityACLRuleRemoveTcp1() throws Exception {
when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
- when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
- when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(30);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(30);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
- egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
- verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
- verify(writeTransaction, times(1)).submit();
- verify(commitFuture, times(1)).get();
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+ Assert.assertEquals(30, layer4Match.getTcpDestinationPort().getValue().intValue());
+ int port=portSecurityRule.getSecurityRulePortMin();
+ Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+ "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
}
/**
@Test
public void testProgramPortSecurityACLRuleAddTcp2() throws Exception {
when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
- when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
- when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
- when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(40);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(40);
when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
- egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
- verify(writeTransaction, times(4)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
- verify(writeTransaction, times(2)).submit();
- verify(commitFuture, times(2)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+ int port=portSecurityRule.getSecurityRulePortMin();
+ String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_1 +
+ "_Permit";
+ String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_2 +
+ "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
}
/**
when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+ when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+ int port=portSecurityRule.getSecurityRulePortMin();
+ String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+ "_Permit";
+ String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+ "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
+ }
+
+ /**
+ * Test TCP add with port range (All TCP) and CIDR selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleAddTcpAll1() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
+
+ Match match = flowBuilder.getMatch();
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+ }
+
+ /**
+ * Test TCP remove with port range (All TCP) and CIDR selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleRemoveTcpAll1() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+ }
+
+ /**
+ * Test TCP add with port range (All TCP) and remote SG selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleAddTcpAll2() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
- egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
- verify(writeTransaction, times(2)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
- verify(writeTransaction, times(2)).submit();
- verify(commitFuture, times(2)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+ String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
+ }
+
+ /**
+ * Test TCP remove with port range (All TCP) and remote SG selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleRemoveTcpAll2() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+ String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
}
/**
when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
- egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
- verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
- verify(writeTransaction, times(1)).submit();
- verify(commitFuture, times(1)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+ "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
}
/**
- * Test UDP add with port no and CIDR selected.
+ * Test UDP remove with port no and CIDR selected.
*/
@Test
public void testProgramPortSecurityACLRuleRemoveUdp1() throws Exception {
when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
- egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
- verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
- verify(writeTransaction, times(1)).submit();
- verify(commitFuture, times(1)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+ "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
}
/**
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
- egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
- verify(writeTransaction, times(4)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
- verify(writeTransaction, times(2)).submit();
- verify(commitFuture, times(2)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_1 +
+ "_Permit";
+ String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_2 +
+ "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
}
/**
- * Test UDP add with port no and remote SG selected.
+ * Test UDP remove with port no and remote SG selected.
*/
@Test
public void testProgramPortSecurityACLRuleRemoveUdp2() throws Exception {
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
- egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
- verify(writeTransaction, times(2)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
- verify(writeTransaction, times(2)).submit();
- verify(commitFuture, times(2)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_1 +
+ "_Permit";
+ String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_2 +
+ "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
+ }
+
+
+ /**
+ * Test UDP add with port (All UDP) and CIDR selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleAddUdpAll1() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+ }
+
+ /**
+ * Test UDP remove with port (All UDP) and CIDR selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleRemoveUdpAll1() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+ }
+
+ /**
+ * Test UDP add with port (All UDP) and remote SG selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleAddUdpAll2() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+ String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
+ }
+
+ /**
+ * Test UDP remove with port (All UDP) and remote SG selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleRemoveUdpAll2() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+ String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
}
/**
Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
- String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+ String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+ DEST_IP_1 + "_Permit";
- String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+ String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+ DEST_IP_2 + "_Permit";
String actualFlowId = flowBuilder.getFlowName();
if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
- String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+ String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+ DEST_IP_1 + "_Permit";
- String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+ String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
+ DEST_IP_2 + "_Permit";
String actualFlowId = flowBuilder.getFlowName();
if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;
private static final String SEGMENT_ID = "2";
private static final Long DP_ID_LONG = (long) 1554;
private static final Long LOCAL_PORT = (long) 124;
+ private static final int PORT_RANGE_MIN = 1;
+ private static final int PORT_RANGE_MAX = 65535;
private static FlowBuilder flowBuilder;
private static NodeBuilder nodeBuilder;
@Test
public void testProgramPortSecurityACLRuleAddTcp1() throws Exception {
when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
- when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
- when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(20);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(20);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
- ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
- verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
- verify(writeTransaction, times(1)).submit();
- verify(commitFuture, times(1)).get();
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+ Assert.assertEquals(20, layer4Match.getTcpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+ "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
}
/**
@Test
public void testProgramPortSecurityACLRuleRemoveTcp1() throws Exception {
when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
- when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
- when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(15);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(15);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
- ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
- verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
- verify(writeTransaction, times(1)).submit();
- verify(commitFuture, times(1)).get();
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+ Assert.assertEquals(15, layer4Match.getTcpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+ "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
}
/**
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
- ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
- verify(writeTransaction, times(4)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
- verify(writeTransaction, times(2)).submit();
- verify(commitFuture, times(2)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getTcpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+ "_Permit";
+ String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+ "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
}
/**
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
- ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
- verify(writeTransaction, times(2)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
- verify(writeTransaction, times(2)).submit();
- verify(commitFuture, times(2)).get();
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getTcpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+ "_Permit";
+ String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+ "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
+ }
+
+
+ /**
+ * Test TCP add with port (All TCP) and CIDR selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleAddTcpAll1() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+ }
+
+ /**
+ * Test TCP remove with port (All TCP) and CIDR selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleRemoveTcpAll1() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+ }
+
+ /**
+ * Test TCP add with port (All TCP) and remote SG selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleAddTcpAll2() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+ String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
+ }
+
+ /**
+ * Test TCP remove with port (All TCP) and remote SG selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleRemoveTcpAll2() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+ TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+ String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+ String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
}
/**
when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
- ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
- verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
- verify(writeTransaction, times(1)).submit();
- verify(commitFuture, times(1)).get();
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+ "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
}
/**
- * Test UDP add with port no and CIDR selected.
+ * Test UDP remove with port no and CIDR selected.
*/
@Test
public void testProgramPortSecurityACLRuleRemoveUdp1() throws Exception {
when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
- ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
- verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
- verify(writeTransaction, times(1)).submit();
- verify(commitFuture, times(1)).get();
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+ "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
}
/**
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
- ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
- verify(writeTransaction, times(4)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
- verify(writeTransaction, times(2)).submit();
- verify(commitFuture, times(2)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+ "_Permit";
+ String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+ "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
}
/**
- * Test UDP add with port no and remote SG selected.
+ * Test UDP remove with port no and remote SG selected.
*/
@Test
public void testProgramPortSecurityACLRuleRemoveUdp2() throws Exception {
when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
- ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
- verify(writeTransaction, times(2)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
- verify(writeTransaction, times(2)).submit();
- verify(commitFuture, times(2)).get();
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+ Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+ int port = portSecurityRule.getSecurityRulePortMin();
+ String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+ "_Permit";
+ String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+ "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
+ }
+
+ /**
+ * Test UDP add with ports (All UDP) and CIDR selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleAddUdpAll1() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+ }
+
+ /**
+ * Test UDP remove with ports (All UDP) and CIDR selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleRemoveUdpAll1() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+ }
+
+ /**
+ * Test UDP add with ports (All UDP) and remote SG selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleAddUdpAll2() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, true);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+ String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
+ }
+
+ /**
+ * Test UDP remove with ports (All UDP) and remote SG selected.
+ */
+ @Test
+ public void testProgramPortSecurityACLRuleRemoveUdpAll2() throws Exception {
+ when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+ when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+ when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+ when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+ when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+ PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+ any(NodeBuilder.class));
+ ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+ neutronSrcIpList, false);
+
+ Match match = flowBuilder.getMatch();
+ EthernetMatch ethMatch = match.getEthernetMatch();
+ Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+ Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+ String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+ String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+ PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+ String actualFlowId = flowBuilder.getFlowName();
+ if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+ Assert.assertTrue(true);
+ } else {
+ Assert.assertTrue(false);
+ }
}
/**
<version>1.2.1-SNAPSHOT</version>
<packaging>bundle</packaging>
+ <properties>
+ <sfc.project.version>0.2.0-SNAPSHOT</sfc.project.version>
+ </properties>
+
<dependencies>
<dependency>
<groupId>org.opendaylight.mdsal.model</groupId>
<groupId>org.opendaylight.mdsal.model</groupId>
<artifactId>yang-ext</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>sfc-model</artifactId>
+ <version>${sfc.project.version}</version>
+ </dependency>
</dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.opendaylight.yang.gen.v1.*;
+ </Export-Package>
+ <!--<Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>-->
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
+++ /dev/null
-module ietf-acl {
- yang-version 1;
-
- namespace "urn:ietf:params:xml:ns:yang:ietf-acl";
-
- prefix acl;
-
- import ietf-yang-types {
- prefix "ietf";
- }
-
- import packet-fields {
- prefix "packet-fields";
- }
-
- organization
- "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
-
- contact
- "WG Web: http://tools.ietf.org/wg/netmod/
- WG List: netmod@ietf.org
-
- WG Chair: Juergen Schoenwaelder
- j.schoenwaelder@jacobs-university.de
-
- WG Chair: Tom Nadeau
- tnadeau@lucidvision.com
-
- Editor: Dean Bogdanovic
- deanb@juniper.net
-
- Editor: Kiran Agrahara Sreenivasa
- kkoushik@brocade.com
-
- Editor: Lisa Huang
- yihuan@cisco.com
-
- Editor: Dana Blair
- dblair@cisco.com";
-
- description
- "This YANG module defines a component that describing the
- configuration of Access Control Lists (ACLs).";
-
- revision 2014-10-10 {
- description "Creating base model for netmod.";
- reference
- "RFC 6020: YANG - A Data Modeling Language for the
- Network Configuration Protocol (NETCONF)";
- }
-
- identity acl-base {
- description "Base acl type for all ACL type identifiers.";
- }
-
- identity ip-acl {
- base "acl:acl-base";
- description "layer 3 ACL type";
- }
- identity eth-acl {
- base "acl:acl-base";
- description "layer 2 ACL type";
- }
-
- typedef acl-type {
- type identityref {
- base "acl-base";
- }
- description
- "This type is used to refer to an Access Control List
- (ACL) type";
- }
-
- typedef acl-ref {
- type leafref {
- path "/acl:access-lists/acl:access-list/acl:acl-name";
- }
- description "This type is used by data models that
- need to referenced an acl";
- }
-
- container access-lists {
- description
- "Access control lists.";
-
- list access-list {
- key acl-name;
- description "
- An access list (acl) is an ordered list of
- access list entries (ace). Each ace has a
- sequence number to define the order, list
- of match criteria, and a list of actions.
- Since there are several kinds of acls
- implementeded with different attributes for
- each and different for each vendor, this
- model accomodates customizing acls for
- each kind and for each vendor.
- ";
-
- leaf acl-name {
- type string;
- description "The name of access-list.
- A device MAY restrict the length and value of
- this name, possibly space and special
- characters are not allowed.";
- }
-
- leaf acl-type {
- type acl-type;
- description "Type of ACL";
- }
-
- container acl-oper-data {
- config false;
-
- description "Overall ACL operational data";
- leaf match-counter {
- type ietf:counter64;
- description "Total match count for ACL";
- }
-
- leaf-list targets {
- type string;
- description "List of targets where ACL is applied";
- }
- }
-
- container access-list-entries {
- description "The access-list-entries container contains
- a list of access-list-entry(ACE).";
-
- list access-list-entry {
- key rule-name;
- ordered-by user;
-
- description "List of access list entries(ACE)";
- leaf rule-name {
- type string;
- description "Entry name.";
- }
-
- container matches {
- description "Define match criteria";
- choice ace-type {
- description "Type of ace.";
- case ace-ip {
- uses packet-fields:acl-ip-header-fields;
- choice ace-ip-version {
- description "Choice of IP version.";
- case ace-ipv4 {
- uses packet-fields:acl-ipv4-header-fields;
- }
- case ace-ipv6 {
- uses packet-fields:acl-ipv6-header-fields;
- }
- }
- }
- case ace-eth {
- uses packet-fields:acl-eth-header-fields;
- }
- }
- uses packet-fields:metadata;
- }
-
- container actions {
- description "Define action criteria";
- choice packet-handling {
- default deny;
-
- description "Packet handling action.";
- case deny {
- leaf deny {
- type empty;
- description "Deny action.";
- }
- }
- case permit {
- leaf permit {
- type empty;
- description "Permit action.";
- }
- }
- }
- }
-
- container ace-oper-data {
- config false;
-
- description "Per ace operational data";
- leaf match-counter {
- type ietf:counter64;
- description "Number of matches for an ace";
- }
- }
- }
- }
- }
- }
-}
namespace "urn:opendaylight:params:xml:ns:yang:netvirt:sfc:acl";
prefix "acl";
- import ietf-acl { prefix ietf-acl;}
+ import ietf-access-control-list { prefix ietf-acl;}
import yang-ext { prefix ext; }
revision "2015-01-05" {
}
// TODO: Add choice for Neutron and add fields there instead of at the root of matches
- augment "/ietf-acl:access-lists/ietf-acl:access-list/ietf-acl:access-list-entries" +
- "/ietf-acl:access-list-entry/ietf-acl:matches" {
+ //augment "/ietf-acl:access-lists/ietf-acl:access-list/ietf-acl:access-list-entries/ietf-acl:access-list-entry/ietf-acl:matches" {
+ augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:matches" {
description "Neutron network uuid";
leaf network-uuid {
type string;
}
// TODO: Add choice for Neutron and add fields there instead of at the root of matches
- augment "/ietf-acl:access-lists/ietf-acl:access-list/ietf-acl:access-list-entries" +
- "/ietf-acl:access-list-entry/ietf-acl:actions" {
+ augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:actions" {
description "Redirect traffic to SFC identified by SFC Path ID";
leaf redirect-sfc {
type string;
+++ /dev/null
-module packet-fields {
- yang-version 1;
-
- namespace "urn:ietf:params:xml:ns:yang:packet-fields";
-
- prefix packet-fields;
-
- import ietf-inet-types {
- prefix "inet";
- }
-
- import ietf-yang-types {
- prefix "yang";
- }
-
- revision 2014-06-25 {
- description "Initial version of packet fields used by access-lists";
- }
-
- grouping acl-transport-header-fields {
- description "Transport header fields";
-
- container source-port-range {
- description "inclusive range of source ports";
- leaf lower-port {
- mandatory true;
- type inet:port-number;
- }
- leaf upper-port {
- type inet:port-number;
- }
- }
-
- container destination-port-range {
- description "inclusive range of destination ports";
- leaf lower-port {
- mandatory true;
- type inet:port-number;
- }
- leaf upper-port {
- type inet:port-number;
- }
- }
- }
-
- grouping acl-ip-header-fields {
- description "Header fields common to ipv4 and ipv6";
-
- uses acl-transport-header-fields;
-
- leaf dscp {
- type inet:dscp;
- }
-
- leaf ip-protocol {
- type uint8;
- }
-
- }
-
- grouping acl-ipv4-header-fields {
- description "fields in IPv4 header";
-
- leaf destination-ipv4-address {
- type inet:ipv4-prefix;
- }
-
- leaf source-ipv4-address {
- type inet:ipv4-prefix;
- }
-
- }
-
- grouping acl-ipv6-header-fields {
- description "fields in IPv6 header";
-
- leaf destination-ipv6-address {
- type inet:ipv6-prefix;
- }
-
- leaf source-ipv6-address {
- type inet:ipv6-prefix;
- }
-
- leaf flow-label {
- type inet:ipv6-flow-label;
- }
-
- }
-
- grouping acl-eth-header-fields {
- description "fields in ethernet header";
-
- leaf destination-mac-address {
- type yang:mac-address;
- }
-
- leaf destination-mac-address-mask {
- type yang:mac-address;
- }
-
- leaf source-mac-address {
- type yang:mac-address;
- }
-
- leaf source-mac-address-mask {
- type yang:mac-address;
- }
- }
-
- grouping timerange {
- description "Define time range entries to restrict
- the access. The time range is identified by a name
- and then referenced by a function, so that those
- time restrictions are imposed on the function itself.";
-
- container absolute {
- description
- "Absolute time and date that
- the associated function starts
- going into effect.";
-
- leaf start {
- type yang:date-and-time;
- description
- "Start time and date";
- }
- leaf end {
- type yang:date-and-time;
- description "Absolute end time and date";
- }
- leaf active {
- type boolean;
- default "true";
- description
- "Specify the associated function
- active or inactive state when
- starts going into effect";
- }
- } // container absolute
- } //grouping timerange
-
- grouping metadata {
- description "Fields associated with a packet but not in the header";
-
- leaf input-interface {
- description "Packet was received on this interface";
- type string;
- }
- uses timerange;
- }
-}
<maven>3.1.1</maven>
</prerequisites>
<properties>
+ <configfile.directory>etc/opendaylight/karaf</configfile.directory>
+ <dlux.version>0.3.0-SNAPSHOT</dlux.version>
<mdsal.model.version>0.8.0-SNAPSHOT</mdsal.model.version>
<mdsal.version>1.3.0-SNAPSHOT</mdsal.version>
+ <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
<restconf.version>1.3.0-SNAPSHOT</restconf.version>
+ <sfc.version>0.2.0-SNAPSHOT</sfc.version>
<yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
- <dlux.version>0.3.0-SNAPSHOT</dlux.version>
- <configfile.directory>etc/opendaylight/karaf</configfile.directory>
</properties>
<dependencyManagement>
<dependencies>
<type>pom</type>
<scope>import</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>ovsdb-artifacts</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<type>xml</type>
<scope>runtime</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>features-ovsdb</artifactId>
+ <classifier>features</classifier>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin</groupId>
+ <artifactId>features-openflowplugin</artifactId>
+ <version>${openflowplugin.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc-ovs</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>openstack.net-virt-sfc-impl</artifactId>
<artifactId>utils.mdsal-utils</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>utils.servicehelper</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</project>
<features name="odl-ovsdb-sfc-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
- <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
<repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
<repository>mvn:org.opendaylight.mdsal.model/features-mdsal-model/${mdsal.model.version}/xml/features</repository>
<repository>mvn:org.opendaylight.netconf/features-restconf/${restconf.version}/xml/features</repository>
- <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
- <repository>mvn:org.opendaylight.ovsdb/southbound-features/1.2.1-SNAPSHOT/xml/features</repository>
+ <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/${openflowplugin.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.ovsdb/features-ovsdb/${project.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.ovsdb/southbound-features/${project.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.sfc/features-sfc/${sfc.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.sfc/features-sfc-ovs/${sfc.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
<feature name='odl-ovsdb-sfc-api' version='${project.version}' description='OpenDaylight :: ovsdb-sfc :: api'>
<feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
<bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-api/${project.version}</bundle>
</feature>
<feature name='odl-ovsdb-sfc' version='${project.version}' description='OpenDaylight :: ovsdb-sfc'>
<feature version='${mdsal.version}'>odl-mdsal-broker</feature>
- <feature version='${project.version}'>odl-ovsdb-sfc-api</feature>
+ <feature version="${openflowplugin.version}">odl-openflowplugin-nsf-model</feature>
<feature version='${project.version}'>odl-ovsdb-southbound-impl</feature>
- <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-impl/${project.version}</bundle>
+ <feature version='${project.version}'>odl-ovsdb-openstack</feature>
+ <feature version='${sfc.version}'>odl-sfc-core</feature>
+ <feature version='${sfc.version}'>odl-sfc-ovs</feature>
+ <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
+ <feature version='${project.version}'>odl-ovsdb-sfc-api</feature>
<bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.ovsdb/utils.servicehelper/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-impl/${project.version}</bundle>
<configfile finalname="${configfile.directory}/openstack.net-virt-sfc.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-impl/${project.version}/xml/config</configfile>
</feature>
<feature name='odl-ovsdb-sfc-rest' version='${project.version}' description='OpenDaylight :: ovsdb-sfc :: REST'>
<feature name='odl-ovsdb-sfc-test' version='${project.version}' description='OpenDaylight :: ovsdb-sfc-test'>
<bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/${project.version}</bundle>
<bundle>mvn:org.opendaylight.ovsdb/utils.southbound-utils/${project.version}</bundle>
- <feature version='${project.version}'>odl-ovsdb-southbound-impl-ui</feature>
<feature version='${project.version}'>odl-ovsdb-sfc-ui</feature>
</feature>
</features>
<packaging>bundle</packaging>
<properties>
+ <networkconfig.neutron.version>0.6.0-SNAPSHOT</networkconfig.neutron.version>
+ <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
<sonar.jacoco.itReportPath>../it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+ <sfc.project.version>0.2.0-SNAPSHOT</sfc.project.version>
</properties>
<dependencies>
<artifactId>openstack.net-virt-sfc-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openstack.net-virt</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openstack.net-virt-providers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>utils.mdsal-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>utils.mdsal-openflow</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>utils.servicehelper</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<artifactId>sal-common-api</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.ovsdb</groupId>
- <artifactId>utils.mdsal-utils</artifactId>
- <version>${project.version}</version>
+ <groupId>org.opendaylight.openflowplugin.model</groupId>
+ <artifactId>model-flow-base</artifactId>
+ <version>${openflowplugin.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin.model</groupId>
+ <artifactId>model-flow-service</artifactId>
+ <version>${openflowplugin.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-topology</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>sfc-model</artifactId>
+ <version>${sfc.project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>sfc-ovs</artifactId>
+ <version>${sfc.project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>sfc-provider</artifactId>
+ <version>${sfc.project.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<build>
<plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Embed-Dependency>utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
+ <Embed-Transitive>true</Embed-Transitive>
+ </instructions>
+ </configuration>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
- <propertyExpansion>checkstyle.checker.severity=error</propertyExpansion>
+ <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
</configuration>
</plugin>
<plugin>
<capability>urn:opendaylight:params:xml:ns:yang:netvirt:sfc?module=netvirt-sfc&revision=2014-12-10</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
<capability>urn:opendaylight:params:xml:ns:yang:southbound:impl?module=southbound-impl&revision=2014-12-10</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:netvirt:impl?module=netvirt-impl&revision=2015-05-13</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:netvirt:providers:impl?module=netvirt-providers-impl&revision=2015-05-13</capability>
</required-capabilities>
<configuration>
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.INetvirtSfcOF13Provider;
import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessLists;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessListKey;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.AccessListEntries;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntry;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntryKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntries;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
/**
* Data tree listener for AccessList.
*/
-public class NetvirtSfcAclListener extends AbstractDataTreeListener<AccessList> {
+public class NetvirtSfcAclListener extends AbstractDataTreeListener<Acl> {
private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcAclListener.class);
private ListenerRegistration<NetvirtSfcAclListener> listenerRegistration;
private MdsalUtils dbutils;
* @param db MdSal {@link DataBroker}
*/
public NetvirtSfcAclListener(final INetvirtSfcOF13Provider provider, final DataBroker db) {
- super(provider, AccessList.class);
+ super(provider, Acl.class);
Preconditions.checkNotNull(db, "DataBroker can not be null!");
dbutils = new MdsalUtils(db);
}
private void registrationListener(final DataBroker db) {
- final DataTreeIdentifier<AccessList> treeId =
+ final DataTreeIdentifier<Acl> treeId =
new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, getIetfAclIid());
try {
- LOG.info("Registering Data Change Listener for Netvirt AccesList configuration.");
+ LOG.info("Registering Data Change Listener for NetvirtSfc AccesList configuration.");
listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
} catch (final Exception e) {
LOG.warn("Netvirt AccesList DataChange listener registration fail!");
}
@Override
- public void remove(final InstanceIdentifier<AccessList> identifier,
- final AccessList removeDataObj) {
+ public void remove(final InstanceIdentifier<Acl> identifier,
+ final Acl removeDataObj) {
Preconditions.checkNotNull(removeDataObj, "Removed object can not be null!");
String aclName = removeDataObj.getAclName();
}
@Override
- public void update(final InstanceIdentifier<AccessList> identifier,
- final AccessList original, final AccessList update) {
+ public void update(final InstanceIdentifier<Acl> identifier,
+ final Acl original, final Acl update) {
}
@Override
- public void add(final InstanceIdentifier<AccessList> identifier,
- final AccessList addDataObj) {
+ public void add(final InstanceIdentifier<Acl> identifier,
+ final Acl addDataObj) {
Preconditions.checkNotNull(addDataObj, "Added object can not be null!");
String aclName = addDataObj.getAclName();
LOG.debug("Adding accesslist = {}", identifier);
return InstanceIdentifier.create(Classifiers.class);
}
- public InstanceIdentifier<AccessList> getIetfAclIid() {
- return InstanceIdentifier.create(AccessLists.class).child(AccessList.class);
+ public InstanceIdentifier<Acl> getIetfAclIid() {
+ return InstanceIdentifier.create(AccessLists.class).child(Acl.class);
}
/**
- * Create an {@link AccessListEntry} {@link InstanceIdentifier}.
+ * Create an {@link Ace} {@link InstanceIdentifier}.
* @param aclName is the name of the ACL
* @param ruleName is the name of the rule
- * @return the {@link AccessListEntry} {@link InstanceIdentifier}
+ * @return the {@link Ace} {@link InstanceIdentifier}
*/
- public InstanceIdentifier<AccessListEntry> getIetfAclEntryIid(String aclName, String ruleName) {
- return InstanceIdentifier.create(AccessLists.class).child(AccessList.class,
- new AccessListKey(aclName)).child(AccessListEntries.class).child(AccessListEntry.class,
- new AccessListEntryKey(ruleName));
+ public InstanceIdentifier<Ace> getIetfAclEntryIid(String aclName, String ruleName) {
+ return InstanceIdentifier.create(AccessLists.class).child(Acl.class,
+ new AclKey(aclName)).child(AccessListEntries.class).child(Ace.class,
+ new AceKey(ruleName));
}
}
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.INetvirtSfcOF13Provider;
import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessLists;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessListKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
final DataTreeIdentifier<Classifier> treeId =
new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
try {
- LOG.info("Registering Data Change Listener for Netvirt Classifier configuration.");
+ LOG.info("Registering Data Change Listener for NetvirtSfc Classifier configuration.");
listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
} catch (final Exception e) {
LOG.warn("Netvirt Classifier DataChange listener registration fail!");
Preconditions.checkNotNull(removeDataObj, "Added object can not be null!");
String aclName = removeDataObj.getAcl();
// Read the ACL information from data store and make sure it exists.
- AccessList acl = dbutils.read(LogicalDatastoreType.CONFIGURATION,getIetfAclIid(aclName));
+ Acl acl = dbutils.read(LogicalDatastoreType.CONFIGURATION, getIetfAclIid(aclName));
if (acl == null) {
LOG.debug("IETF ACL with name ={} is not yet configured. skip this operation", aclName);
return;
Preconditions.checkNotNull(addDataObj, "Added object can not be null!");
String aclName = addDataObj.getAcl();
// Read the ACL information from data store and make sure it exists.
- AccessList acl = dbutils.read(LogicalDatastoreType.CONFIGURATION,getIetfAclIid(aclName));
+ Acl acl = dbutils.read(LogicalDatastoreType.CONFIGURATION,getIetfAclIid(aclName));
if (acl == null) {
LOG.debug("IETF ACL with name ={} is not yet configured. skip this operation", aclName);
return;
return InstanceIdentifier.create(Classifiers.class).child(Classifier.class);
}
- private InstanceIdentifier<AccessList> getIetfAclIid(String aclName) {
- return InstanceIdentifier.create(AccessLists.class).child(AccessList.class, new AccessListKey(aclName));
+ private InstanceIdentifier<Acl> getIetfAclIid(String aclName) {
+ return InstanceIdentifier.create(AccessLists.class).child(Acl.class, new AclKey(aclName));
}
}
public class NetvirtSfcProvider implements BindingAwareProvider, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcProvider.class);
- private DataBroker dataBroker = null;
- private BundleContext bundleContext = null;
private NetvirtSfcAclListener aclListener;
-
private NetvirtSfcClassifierListener classfierListener;
- private INetvirtSfcOF13Provider provider;
-
- public NetvirtSfcProvider(BundleContext bundleContext) {
- LOG.info("NetvirtProvider: bundleContext: {}", bundleContext);
- this.bundleContext = bundleContext;
- }
@Override
public void onSessionInitiated(ProviderContext session) {
LOG.info("NetvirtSfcProvider Session Initiated");
- dataBroker = session.getSALService(DataBroker.class);
+ DataBroker dataBroker = session.getSALService(DataBroker.class);
- provider = new NetvirtSfcOF13Provider(this.dataBroker);
- aclListener = new NetvirtSfcAclListener(provider, this.dataBroker);
- classfierListener = new NetvirtSfcClassifierListener(provider, this.dataBroker);
+ INetvirtSfcOF13Provider provider = new NetvirtSfcOF13Provider(dataBroker);
+ aclListener = new NetvirtSfcAclListener(provider, dataBroker);
+ classfierListener = new NetvirtSfcClassifierListener(provider, dataBroker);
}
@Override
package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
/**
* @param sff - Service Function Forwarder
* @param acl - Access list includes rules that need to be installed in a SFF.
*/
- public void addClassifierRules(Sff sff, AccessList acl);
+ public void addClassifierRules(Sff sff, Acl acl);
/**
* Method removes the OF rules corresponding to rules within ACL
* @param sff - Service Function Forwarder
* @param acl - Access list includes rules that need to be installed in a SFF.
*/
- public void removeClassifierRules(Sff sff, AccessList acl);
+ public void removeClassifierRules(Sff sff, Acl acl);
}
package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
+import java.util.Iterator;
+import java.util.List;
+
import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
+import org.opendaylight.sfc.sfc_ovs.provider.SfcOvsUtil;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Actions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.Deny;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.Permit;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
+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.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
* @author Arun Yerra
*/
public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
+ private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcOF13Provider.class);
+ private static final int DEFAULT_FLOW_PRIORITY = 32768;
+ private volatile NodeCacheManager nodeCacheManager;
+ private volatile Southbound southbound;
+ private MdsalUtils dbutils;
+ private PipelineOrchestrator orchestrator;
- private final DataBroker dataService;
-
+ /**
+ * {@link NetvirtSfcOF13Provider} constructor.
+ * @param dataBroker MdSal {@link DataBroker}
+ */
public NetvirtSfcOF13Provider(final DataBroker dataBroker) {
- this.dataService = Preconditions.checkNotNull(dataBroker, "DataBroker can not be null!");
+ Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
+
+ //this.dataService = dataBroker;
+ dbutils = new MdsalUtils(dataBroker);
+
+ this.setDependencies(null);
}
@Override
- public void addClassifierRules(Sff sff, AccessList acl) {
- // TODO Auto-generated method stub
+ public void addClassifierRules(Sff sff, Acl acl) {
+ Preconditions.checkNotNull(sff, "Input service function forwarder cannot be NULL!");
+ Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
+
+ // Validate if any service function forwarder exists by the name, using SFC provider APIs.
+ ServiceFunctionForwarder serviceForwarder =
+ SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sff.getName());
+ if (serviceForwarder == null) {
+ LOG.debug("Service Function Forwarder = {} not yet configured. Skip processing !!", sff.getName());
+ return;
+ }
+
+ // If a service function forwarder exists, then get the corresponding OVS Bridge details and Openflow NodeId.
+ // If OVS Bridge augmentation is configured, the following API returns NULL.
+ String datapathId = SfcOvsUtil.getOpenFlowNodeIdForSff(serviceForwarder);
+ if (datapathId == null) {
+ LOG.debug("Service Function Forwarder = {} is not augemented with "
+ + "OVS Bridge Information. Skip processing!!", sff.getName());
+ }
+ // If openflow Node Id is NULL, get all the bridge nodes using southbound apis and fetch
+ // SFF with matching name. From this bridge name, get the openflow data path ID.
+ if (datapathId == null) {
+ Node node = null;
+ final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+ if (nodes.isEmpty()) {
+ LOG.debug("Noop with Classifier Creation on SFF={}. No Bridges configured YET!!", sff.getName());
+ } else {
+ for (Node dstNode : nodes) {
+ LOG.debug("Processing Node={}, sff={}", dstNode.getNodeId().getValue(), sff.getName());
+ if (dstNode.getNodeId().getValue().equalsIgnoreCase(sff.getName())) {
+ LOG.debug("Found matching OVSDB Bridge Name!!= {}", dstNode.getNodeId().getValue());
+ node = dstNode;
+ break;
+ }
+ }
+ }
+ }
+
+ LOG.debug("Processing the Classifier rules on Node={}", datapathId);
+ if (datapathId != null) {
+ // Program the OF flow on the corresponding open flow node.
+ Iterator<Ace> itr = acl.getAccessListEntries().getAce().iterator();
+ while (itr.hasNext()) {
+ Ace entry = itr.next();
+ programOfRules(entry, datapathId, true);
+ }
+ }
+ }
+
+ private void programOfRules(Ace entry, String datapathId, boolean write) {
+ NodeBuilder nodeBuilder = new NodeBuilder();
+ nodeBuilder.setId(new NodeId(Constants.OPENFLOW_NODE_PREFIX + datapathId));
+ nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
+
+ //Create the match using match builder, by parsing the Accesslist Entry Match.
+ MatchBuilder matchBuilder = null;
+ matchBuilder = buildMatch(entry.getRuleName(), entry.getMatches(), datapathId);
+
+ InstructionsBuilder isb = null;
+ isb = buildActions(entry.getRuleName(), entry.getActions(), datapathId);
+
+ String flowId = "NETVIRT_SFC_FLOW" + "_" + entry.getRuleName();
+
+ FlowBuilder flowBuilder = new FlowBuilder();
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setMatch(matchBuilder.build());
+ flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
+ flowBuilder.setBarrier(true);
+ flowBuilder.setTableId(this.getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+
+ flowBuilder.setInstructions(isb.build());
+
+ if (write) {
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+ private InstructionsBuilder buildActions(String ruleName, Actions actions, String datapathId) {
+ InstructionBuilder ib = new InstructionBuilder();
+
+ if (actions.getPacketHandling() instanceof Deny) {
+ InstructionUtils.createDropInstructions(ib);
+ } else if (actions.getPacketHandling() instanceof Permit) {
+ //Permit actPermit = (Permit) actions.getPacketHandling();
+ } else {
+ InstructionUtils.createDropInstructions(ib);
+ }
+
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+ instructions.add(ib.build());
+
+ // Call the InstructionBuilder Methods Containing Actions
+ ib = this.getMutablePipelineInstructionBuilder();
+ ib.setOrder(1);
+ ib.setKey(new InstructionKey(1));
+ instructions.add(ib.build());
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ InstructionsBuilder isb = new InstructionsBuilder();
+ isb.setInstruction(instructions);
+ return isb;
+ }
+
+ private MatchBuilder buildMatch(String ruleName, Matches matches, String dpId) {
+ MatchBuilder matchBuilder = new MatchBuilder();
+
+ if (matches.getAceType() instanceof AceIp) {
+ AceIp aceIp = (AceIp)matches.getAceType();
+ if (aceIp.getAceIpVersion() instanceof AceIpv4) {
+ AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
+ MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Network());
+ MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network());
+ MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
+ MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(),
+ aceIp.getSourcePortRange().getLowerPort().getValue().intValue(),
+ aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
+ }
+ } else if (matches.getAceType() instanceof AceEth) {
+ AceEth aceEth = (AceEth) matches.getAceType();
+ MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(aceEth.getSourceMacAddress().getValue()));
+ MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(aceEth.getDestinationMacAddress().getValue()),
+ new MacAddress(aceEth.getDestinationMacAddressMask().getValue()));
+ }
+
+ //MatchUtils.createInPortMatch(matchBuilder, Long.getLong(dpId), Long.getLong(matches.getInputInterface()));
+ return matchBuilder;
}
@Override
- public void removeClassifierRules(Sff sff, AccessList acl) {
+ public void removeClassifierRules(Sff sff, Acl acl) {
// TODO Auto-generated method stub
}
+
+
+ protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+ LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
+ flowBuilder.build(), nodeBuilder.build());
+ dbutils.merge(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder), nodeBuilder.build());
+ dbutils.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder), flowBuilder.build());
+ }
+
+ protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+ dbutils.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
+ }
+
+ private String getDpid(Node node) {
+ long dpid = southbound.getDataPathId(node);
+ if (dpid == 0) {
+ LOG.warn("getDpid: DPID could not be found for node: {}", node.getNodeId().getValue());
+ }
+ return String.valueOf(dpid);
+ }
+
+ private static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+ return InstanceIdentifier.builder(Nodes.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
+ nodeBuilder.getKey())
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(flowBuilder.getTableId()))
+ .child(Flow.class, flowBuilder.getKey()).build();
+ }
+
+ private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
+ createNodePath(NodeBuilder nodeBuilder) {
+ return InstanceIdentifier.builder(Nodes.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
+ nodeBuilder.getKey()).build();
+ }
+
+ private short getTable() {
+ return Service.INGRESS_ACL.getTable();
+ }
+
+ private final InstructionBuilder getMutablePipelineInstructionBuilder() {
+ Service nextService = orchestrator.getNextServiceInPipeline(Service.INGRESS_ACL);
+ if (nextService != null) {
+ return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
+ } else {
+ return InstructionUtils.createDropInstructions(new InstructionBuilder());
+ }
+ }
+
+ private void setDependencies(ServiceReference serviceReference) {
+ nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+ southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+ orchestrator = (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
+ }
}
public class NetvirtSfcModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210.AbstractNetvirtSfcModule {
private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcModule.class);
- private BundleContext bundleContext = null;
public NetvirtSfcModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
super(identifier, dependencyResolver);
@Override
public java.lang.AutoCloseable createInstance() {
LOG.info("Netvirt SFC module initialization.");
- //final NetvirtSfcProvider sfcProvider = new NetvirtSfcProvider(getDataBrokerDependency());
- final NetvirtSfcProvider sfcProvider = new NetvirtSfcProvider(bundleContext);
+ NetvirtSfcProvider sfcProvider = new NetvirtSfcProvider();
getBrokerDependency().registerProvider(sfcProvider);
return sfcProvider;
}
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
}
import org.slf4j.LoggerFactory;
public class NetvirtSfcModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210.AbstractNetvirtSfcModuleFactory {
- private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcModuleFactory.class);
-
- @Override
- public Module createModule(String instanceName,
- DependencyResolver dependencyResolver,
- DynamicMBeanWithInstance old, BundleContext bundleContext)
- throws Exception {
- Module module = super.createModule(instanceName, dependencyResolver, old, bundleContext);
- LOG.info("Created NetvirtSfcModule1= {}!!", (module instanceof NetvirtSfcModule));
- setModuleBundleContext(bundleContext, module);
- return module;
- }
-
- @Override
- public Module createModule(String instanceName,
- DependencyResolver dependencyResolver, BundleContext bundleContext) {
- Module module = super.createModule(instanceName, dependencyResolver, bundleContext);
- LOG.info("Created NetvirtSfcModule2= {}!!", (module instanceof NetvirtSfcModule));
- setModuleBundleContext(bundleContext, module);
- return module;
- }
-
- private void setModuleBundleContext(BundleContext bundleContext,
- Module module) {
- if (module instanceof NetvirtSfcModule) {
- LOG.info("Setting Bundle Context for NetvirtSfcModule!!");
- ((NetvirtSfcModule)module).setBundleContext(bundleContext);
- } else {
- LOG.warn("Module is of type {} expected type {}",
- module.getClass(), NetvirtSfcModule.class);
- }
- }
}
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.NetvirtSfcProvider;
+import org.osgi.framework.BundleContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import javax.management.ObjectName;
// create instance of module with injected mocks
NetvirtSfcModule module = new NetvirtSfcModule(mock(ModuleIdentifier.class), dependencyResolver);
- //module.setDataBroker(mock(ObjectName.class));
// getInstance calls resolveInstance to get the broker dependency and then calls createInstance
AutoCloseable closeable = module.getInstance();
((NetvirtSfcProvider)closeable).onSessionInitiated(session);
<groupId>${project.groupId}</groupId>
<artifactId>utils.mdsal-utils</artifactId>
<version>${project.version}</version>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>utils.southbound-utils</artifactId>
<version>${project.version}</version>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>concepts</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.sonar-plugins.java</groupId>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
+ </configuration>
+ </plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
+ <!--<configuration>
+ <excludes>
+ <exclude>**/NetvirtSfcIT.java</exclude>
+ </excludes>
+ </configuration>-->
</plugin>
</plugins>
</build>
package org.opendaylight.ovsdb.openstack.netvirt.sfc;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.AclUtils;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ClassifierUtils;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils;
-import org.opendaylight.ovsdb.southbound.SouthboundConstants;
import org.opendaylight.ovsdb.southbound.SouthboundUtil;
import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessLists;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessListsBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessListBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.AccessListEntriesBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntryBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.ActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.MatchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.ClassifiersBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+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.TopologyId;
+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.Builder;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.karaf.options.LogLevelOption;
import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
import org.ops4j.pax.exam.options.MavenUrlReference;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
public static final String CONNECTION_TYPE_ACTIVE = "active";
public static final String CONNECTION_TYPE_PASSIVE = "passive";
public static final String DEFAULT_SERVER_PORT = "6640";
- public static final String BRIDGE_NAME = "brtest";
+ public static final String INTEGRATION_BRIDGE_NAME = "br-int";
+ private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
@Override
public String getModuleName() {
@Override
public Option getLoggingOption() {
- Option option = editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
- logConfiguration(NetvirtSfcIT.class),
- LogLevel.INFO.name());
- option = composite(option, super.getLoggingOption());
- return option;
+ return composite(
+ editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+ logConfiguration(NetvirtSfcIT.class),
+ LogLevel.INFO.name()),
+ editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+ "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
+ LogLevel.INFO.name()),
+ /*editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+ "log4j.logger.org.opendaylight.ovsdb",
+ LogLevelOption.LogLevel.TRACE.name()),*/
+ super.getLoggingOption());
}
protected String usage() {
}
try {
+ Thread.sleep(1000);
super.setup();
} catch (Exception e) {
e.printStackTrace();
}
+ getProperties();
+
DataBroker dataBroker = getDatabroker(getProviderContext());
mdsalUtils = new MdsalUtils(dataBroker);
assertNotNull("mdsalUtils should not be null", mdsalUtils);
southboundUtils = new SouthboundUtils(mdsalUtils);
- getProperties();
+ assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
setup.set(true);
}
return dataBroker;
}
+ private Boolean getNetvirtTopology() {
+ LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
+ Boolean found = false;
+ final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
+ InstanceIdentifier<Topology> path =
+ InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
+ for (int i = 0; i < 60; i++) {
+ Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
+ if (topology != null) {
+ LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
+ found = true;
+ break;
+ } else {
+ LOG.info("getNetvirtTopology: still looking ({})...", i);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return found;
+ }
+
@Test
public void testNetvirtSfcFeatureLoad() {
assertTrue(true);
private AccessListsBuilder setAccessLists () {
MatchesBuilder matchesBuilder = aclUtils.createMatches(new MatchesBuilder(), 80);
ActionsBuilder actionsBuilder = aclUtils.createActions(new ActionsBuilder(), Boolean.TRUE);
- AccessListEntryBuilder accessListEntryBuilder = aclUtils.createAccessListEntryBuilder(
- new AccessListEntryBuilder(), "http", matchesBuilder, actionsBuilder);
+ AceBuilder accessListEntryBuilder = aclUtils.createAccessListEntryBuilder(
+ new AceBuilder(), "http", matchesBuilder, actionsBuilder);
AccessListEntriesBuilder accessListEntriesBuilder = aclUtils.createAccessListEntries(
new AccessListEntriesBuilder(), accessListEntryBuilder);
- AccessListBuilder accessListBuilder = aclUtils.createAccessList(new AccessListBuilder(),
+ AclBuilder accessListBuilder = aclUtils.createAccessList(new AclBuilder(),
"http", accessListEntriesBuilder);
AccessListsBuilder accessListsBuilder = aclUtils.createAccessLists(new AccessListsBuilder(),
accessListBuilder);
assertNull(clazz.getSimpleName() + " should be null", result);
}
+ /*
+ * Connect to an ovsdb node. Netvirt should add br-int, add the controller address
+ * and program the pipeline flows.
+ */
@Test
public void testDoIt() throws InterruptedException {
ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
- Node ovsdbNode = southboundUtils.connectOvsdbNode(connectionInfo);
-
- String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
- assertNotNull("Failed to get controller target", controllerTarget);
- List<ControllerEntry> setControllerEntry = southboundUtils.createControllerEntry(controllerTarget);
- Uri setUri = new Uri(controllerTarget);
- Assert.assertTrue(southboundUtils.addBridge(connectionInfo, null, BRIDGE_NAME, null, true,
- SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
- setControllerEntry, null));
- OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, BRIDGE_NAME);
- Assert.assertNotNull("bridge was not found: " + BRIDGE_NAME, bridge);
- Assert.assertNotNull("ControllerEntry was not found: " + setControllerEntry.iterator().next(),
- bridge.getControllerEntry());
- List<ControllerEntry> getControllerEntries = bridge.getControllerEntry();
- for (ControllerEntry entry : getControllerEntries) {
- if (entry.getTarget() != null) {
- Assert.assertEquals(setUri.toString(), entry.getTarget().toString());
+ assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+ assertNotNull("node is not connected", southboundUtils.getOvsdbNode(connectionInfo));
+ ControllerEntry controllerEntry;
+ // Loop 10s checking if the controller was added
+ for (int i = 0; i < 10; i++) {
+ Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
+ assertNotNull("ovsdb node not found", ovsdbNode);
+ String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
+ assertNotNull("Failed to get controller target", controllerTarget);
+ OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, INTEGRATION_BRIDGE_NAME);
+ assertNotNull(bridge);
+ assertNotNull(bridge.getControllerEntry());
+ controllerEntry = bridge.getControllerEntry().iterator().next();
+ assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
+ if (controllerEntry.isIsConnected()) {
+ Assert.assertTrue(controllerEntry.isIsConnected());
+ break;
}
+ Thread.sleep(1000);
}
/* TODO: add code to write to mdsal to exercise the sfc dataChangeListener */
/* allow some time to let the impl code do it's work to push flows */
/* or just comment out below lines and just manually verify on the bridges and reset them */
- Thread.sleep(10000);
+ //Thread.sleep(10000);
- Assert.assertTrue(southboundUtils.deleteBridge(connectionInfo, BRIDGE_NAME));
- southboundUtils.disconnectOvsdbNode(connectionInfo);
+ assertTrue(southboundUtils.deleteBridge(connectionInfo, INTEGRATION_BRIDGE_NAME));
+ Thread.sleep(1000);
+ assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
}
}
import java.util.ArrayList;
import java.util.List;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessListsBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessListBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.AccessListEntriesBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntry;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntryBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.ActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.MatchesBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.actions.packet.handling.PermitBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.matches.ace.type.AceIpBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.PermitBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.DestinationPortRangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev150611.acl.transport.header.fields.DestinationPortRangeBuilder;
public class AclUtils {
public MatchesBuilder createMatches (MatchesBuilder matchesBuilder, int destPort) {
return actionsBuilder;
}
- public AccessListEntryBuilder createAccessListEntryBuilder(AccessListEntryBuilder accessListEntryBuilder,
- String ruleName,
- MatchesBuilder matchesBuilder,
- ActionsBuilder actionsBuilder) {
+ public AceBuilder createAccessListEntryBuilder(AceBuilder accessListEntryBuilder,
+ String ruleName,
+ MatchesBuilder matchesBuilder,
+ ActionsBuilder actionsBuilder) {
accessListEntryBuilder.setRuleName(ruleName);
accessListEntryBuilder.setMatches(matchesBuilder.build());
accessListEntryBuilder.setActions(actionsBuilder.build());
}
public AccessListEntriesBuilder createAccessListEntries(AccessListEntriesBuilder accessListEntriesBuilder,
- AccessListEntryBuilder accessListEntryBuilder) {
- List<AccessListEntry> accessListEntriesList = new ArrayList<>();
+ AceBuilder accessListEntryBuilder) {
+ List<Ace> accessListEntriesList = new ArrayList<>();
accessListEntriesList.add(accessListEntryBuilder.build());
return accessListEntriesBuilder;
}
- public AccessListBuilder createAccessList(AccessListBuilder accessListBuilder,
- String aclName,
- AccessListEntriesBuilder accessListEntriesBuilder) {
+ public AclBuilder createAccessList(AclBuilder accessListBuilder,
+ String aclName,
+ AccessListEntriesBuilder accessListEntriesBuilder) {
accessListBuilder.setAclName(aclName);
accessListBuilder.setAccessListEntries(accessListEntriesBuilder.build());
}
public AccessListsBuilder createAccessLists(AccessListsBuilder accessListsBuilder,
- AccessListBuilder accessListBuilder) {
- List<AccessList> accessListList = new ArrayList<>();
+ AclBuilder accessListBuilder) {
+ List<Acl> accessListList = new ArrayList<>();
accessListList.add(accessListBuilder.build());
- accessListsBuilder.setAccessList(accessListList);
+ accessListsBuilder.setAcl(accessListList);
return accessListsBuilder;
}
<properties>
<karaf.localFeature>odl-ovsdb-sfc-test</karaf.localFeature>
</properties>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openstack.net-virt-sfc-artifacts</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
<dependencies>
<dependency>
<!-- scope is compile so all features (there is only one) are installed
</scm>
<properties>
- <networkconfig.neutron.version>0.6.0-SNAPSHOT</networkconfig.neutron.version>
+ <neutron.model.version>0.6.0-SNAPSHOT</neutron.model.version>
<ovsdb.utils.config.version>1.2.1-SNAPSHOT</ovsdb.utils.config.version>
<ovsdb.utils.servicehelper.version>1.2.1-SNAPSHOT</ovsdb.utils.servicehelper.version>
<powermock.version>1.5.2</powermock.version>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
</dependency>
- <dependency>
- <groupId>org.opendaylight.neutron</groupId>
- <artifactId>neutron-spi</artifactId>
- <version>${networkconfig.neutron.version}</version>
- </dependency>
<dependency>
<groupId>org.opendaylight.ovsdb</groupId>
<artifactId>southbound-api</artifactId>
<version>1.2.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.neutron</groupId>
+ <artifactId>model</artifactId>
+ <version>${neutron.model.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.ovsdb</groupId>
<artifactId>utils.config</artifactId>
<groupId>org.opendaylight.mdsal.model</groupId>
<artifactId>ietf-yang-types</artifactId>
</dependency>
+ <dependency>
+ <groupId>commons-net</groupId>
+ <artifactId>commons-net</artifactId>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<Embed-Dependency>utils.config;type=!pom;inline=false</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
<Export-Package>
+ org.opendaylight.ovsdb.openstack.netvirt.translator,
org.opendaylight.ovsdb.openstack.netvirt.api,
org.opendaylight.ovsdb.openstack.netvirt
</Export-Package>
import org.apache.commons.lang3.tuple.Pair;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.neutron.spi.*;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.*;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronFirewallInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronFirewallPolicyInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronFirewallRuleInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronFloatingIPInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerHealthMonitorInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerListenerInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerPoolInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerPoolMemberInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronNetworkInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronPortInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronRouterInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronSecurityGroupInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronSecurityRuleInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronSubnetInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallPolicyAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallRuleAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFloatingIPAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronNetworkAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronPortAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronRouterAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSubnetAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.*;
import org.opendaylight.ovsdb.openstack.netvirt.impl.*;
import org.osgi.framework.BundleActivator;
public class ConfigActivator implements BundleActivator {
private static final Logger LOG = LoggerFactory.getLogger(ConfigActivator.class);
+ private List<ServiceRegistration<?>> translatorCRUDRegistrations = new ArrayList<ServiceRegistration<?>>();
private List<Pair<Object, ServiceRegistration>> servicesAndRegistrations = new ArrayList<>();
private ProviderContext providerContext;
@Override
public void start(BundleContext context) throws Exception {
LOG.info("ConfigActivator start:");
+ registerCRUDServiceProviders(context, this.providerContext);
ConfigurationServiceImpl configurationService = new ConfigurationServiceImpl();
registerService(context, new String[] {ConfigurationService.class.getName()},
trackService(context, RoutingProvider.class, neutronL3Adapter);
trackService(context, L3ForwardingProvider.class, neutronL3Adapter);
trackService(context, GatewayMacResolver.class, neutronL3Adapter);
+ trackService(context, IngressAclProvider.class, securityServices);
+ trackService(context, EgressAclProvider.class, securityServices);
// We no longer need to track the services, avoid keeping references around
servicesAndRegistrations.clear();
}
+ private void registerCRUDServiceProviders(BundleContext context,
+ ProviderContext providerContext) {
+ LOG.debug("Registering CRUD service providers");
+ NeutronRouterInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronPortInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronSubnetInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronNetworkInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronSecurityGroupInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronSecurityRuleInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronFirewallInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronFirewallPolicyInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronFirewallRuleInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronLoadBalancerInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronLoadBalancerPoolInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronLoadBalancerListenerInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronLoadBalancerHealthMonitorInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronLoadBalancerPoolMemberInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ NeutronFloatingIPInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+ }
+
private void trackService(BundleContext context, final Class<?> clazz, final ConfigInterface... dependents) {
@SuppressWarnings("unchecked")
ServiceTracker tracker = new ServiceTracker(context, clazz, null) {
@Override
public void stop(BundleContext context) throws Exception {
- LOG.info("ConfigActivator stop");
+ LOG.info("Stop Translator CRUD service provides");
// ServiceTrackers and services are already released when bundle stops,
// so we don't need to close the trackers or unregister the services
+ for (ServiceRegistration registration : translatorCRUDRegistrations) {
+ if (registration != null) {
+ registration.unregister();
+ }
+ }
+
}
private ServiceRegistration<?> registerService(BundleContext bundleContext, String[] interfaces,
import java.net.HttpURLConnection;
-import org.opendaylight.neutron.spi.INeutronFirewallAware;
-import org.opendaylight.neutron.spi.INeutronFirewallPolicyAware;
-import org.opendaylight.neutron.spi.INeutronFirewallRuleAware;
-import org.opendaylight.neutron.spi.NeutronFirewall;
-import org.opendaylight.neutron.spi.NeutronFirewallPolicy;
-import org.opendaylight.neutron.spi.NeutronFirewallRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallPolicyAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallRuleAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
import org.osgi.framework.ServiceReference;
/**
* Process the event.
*
- * @param abstractEvent@see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
+ * @param abstractEvent new FWaas Event@see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
*/
@Override
public void processEvent(AbstractEvent abstractEvent) {
import java.net.HttpURLConnection;
-import org.opendaylight.neutron.spi.INeutronFloatingIPAware;
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFloatingIPAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
import java.util.List;
import java.util.Map;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerAware;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
/**
* Useful utility for extracting the loadbalancer instance
* configuration from the neutron LB cache
+ * @param neutronLB neutron load balancer object
+ * @return returns load balancer configuration
*/
public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancer neutronLB) {
String loadBalancerName = neutronLB.getLoadBalancerName();
import java.util.List;
import java.util.Map;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolAware;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
/**
* Useful utility for extracting the loadbalancer instance. With
* each LB pool, we allow multiple VIP and LB to be instantiated.
+ * @param neutronLBPool Neutron load balancer pool object
+ * @return list of loadbalancer configuration of pool members
*/
public List<LoadBalancerConfiguration> extractLBConfiguration(NeutronLoadBalancerPool neutronLBPool) {
String poolProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
import java.util.List;
import java.util.Map;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolMemberAware;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
/**
* Useful utility for extracting the loadbalancer instance
* configuration from the neutron LB cache based on member info
+ * @param neutronLBPoolMember Neutron LB pool member object
+ * @return load balancer configuration of the pool member
*/
public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
String memberID = neutronLBPoolMember.getID();
import java.net.HttpURLConnection;
import java.util.List;
-import org.opendaylight.neutron.spi.INeutronNetworkAware;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronNetworkAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
package org.opendaylight.ovsdb.openstack.netvirt;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
import java.util.AbstractMap;
import java.util.Iterator;
/**
* Look up in the NeutronPortsCRUD cache and return the MAC address for a corresponding IP address
+ * @param neutronPortsCache Reference to port cache to get existing port related data. This interface
+ * basically read data from the md-sal data store.
+ * @param subnetID subnet to which given port is attached
* @param ipAddr IP address of a member or VM
* @return MAC address registered with that IP address
*/
/**
* Look up in the NeutronNetworkCRUD cache and NeutronSubnetCRUD cache for
* extracting the provider segmentation_type and segmentation_id
+ * @param neutronNetworkCache Reference to neutron network cache to get existing network related data.
+ * This interface basically read data from the md-sal data store.
+ * @param neutronSubnetCache Reference to neutron subnet cache to get existing subnet related data.
+ * This interface basically read data from the md-sal data store.
* @param subnetID Subnet UUID
* @return {Type: ID} pair for that subnet ID
*/
package org.opendaylight.ovsdb.openstack.netvirt;
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
-import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
public class NorthboundEvent extends AbstractEvent {
import java.net.HttpURLConnection;
import java.util.List;
-import org.opendaylight.neutron.spi.INeutronPortAware;
-import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronPortAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import java.net.HttpURLConnection;
-import org.opendaylight.neutron.spi.INeutronSecurityGroupAware;
-import org.opendaylight.neutron.spi.INeutronSecurityRuleAware;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
import org.osgi.framework.ServiceReference;
import java.net.HttpURLConnection;
-import org.opendaylight.neutron.spi.INeutronRouterAware;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronRouterAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
import java.util.List;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
import org.opendaylight.ovsdb.openstack.netvirt.api.*;
import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
import java.net.HttpURLConnection;
-import org.opendaylight.neutron.spi.INeutronSubnetAware;
-import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSubnetAware;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
package org.opendaylight.ovsdb.openstack.netvirt.api;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import java.util.List;
* For OpenFlow 1.3 the Integration Bridge is required and must have a physical device connected.
* @param bridgeNode the {@link Node} that represents bridge
* @param ovsdbNode the {@link Node} where the bridge is configured
- * @param network the {@link org.opendaylight.neutron.spi.NeutronNetwork}
+ * @param network the {@link org.opendaylight.ovsdb.openstack.netvirt.translator}
* @return True or False
*/
boolean isNodeVlanReady(Node bridgeNode, Node ovsdbNode, NeutronNetwork network);
* Returns true if the bridges required for the provider network type are created
* If the bridges are not created, this method will attempt to create them
* @param node the {@link Node} to query
- * @param network the {@link org.opendaylight.neutron.spi.NeutronNetwork}
+ * @param network the {@link org.opendaylight.ovsdb.openstack.netvirt.translator}
* @return True or False
*/
boolean createLocalNetwork(Node node, NeutronNetwork network);
/**
* Returns the physical interface mapped to the given neutron physical network.
- * @param node
- * @param physicalNetwork
- * @return
+ * @param node the {@link Node} to query
+ * @param physicalNetwork neutron physical network
+ * @return name of the physical interface
*/
String getPhysicalInterfaceName(Node node, String physicalNetwork);
public interface ConfigurationService {
/**
- * Returns the name configured name of the Integration Bridge
+ * @return the name configured name of the Integration Bridge
*/
String getIntegrationBridgeName();
/**
* Configures the name of the Integration Bridge
+ * @param integrationBridgeName name of integration bridge
*/
void setIntegrationBridgeName(String integrationBridgeName);
/**
- * Returns the name configured name of the Network Bridge
+ * @return the name configured name of the Network Bridge
*/
String getNetworkBridgeName();
/**
* Configures the name of the Network Bridge
+ * @param networkBridgeName Name of the network bridge
*/
void setNetworkBridgeName(String networkBridgeName);
/**
- * Returns the name configured name of the ExternalBridge
+ * @return the name configured name of the ExternalBridge
*/
String getExternalBridgeName();
/**
* Configures the name of the External Bridge
+ * @param externalBridgeName Name of external bridge
*/
void setExternalBridgeName(String externalBridgeName);
/**
- * Returns the key used to access the Tunnel Endpoint configuration from Open vSwitch
+ * @return the key used to access the Tunnel Endpoint configuration from Open vSwitch
*/
String getTunnelEndpointKey();
/**
* Sets the key used to access the Tunnel Endpoint configuration from Open vSwitch
+ * @param tunnelEndpointKey key of tunnel end point
*/
void setTunnelEndpointKey(String tunnelEndpointKey);
/**
- * Returns a Map of patch port names where the key is a tuple of source bridge and destination bridge
+ * @return a Map of patch port names where the key is a tuple of source bridge and destination bridge
*/
Map<Pair<String, String>, String> getPatchPortNames();
/**
* Sets the Map of source/destination bridges to patch port name
+ * @param patchPortNames Map of source/destination bridges to patch port name
*/
void setPatchPortNames(Map<Pair<String, String>, String> patchPortNames);
String getPatchPortName(Pair portTuple);
/**
- * Returns the key used to access the Tunnel Endpoint configuration from Open vSwitch
+ * @return the key used to access the Tunnel Endpoint configuration from Open vSwitch
*/
String getProviderMappingsKey();
/**
* Sets the key used to access the Tunnel Endpoint configuration from Open vSwitch
+ * @param providerMappingsKey provide mapping key
*/
void setProviderMappingsKey(String providerMappingsKey);
/**
- * Gets the default provider mapping
+ * @return Gets the default provider mapping
*/
String getDefaultProviderMapping();
/**
* Sets the default provider mapping
+ * @param providerMapping provider mapping
*/
void setDefaultProviderMapping(String providerMapping);
import java.util.List;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
/**
* This interface allows egress Port Security flows to be written to devices.
* periodicRefresh flag.
* @param externalNetworkBridgeDpid This bridge will be used for sending ARP request
* @param gatewayIp ARP request will be send for this ip address
+ * @param sourceIpAddress Source IP address for the ARP request (localhost)
+ * @param sourceMacAddress Source MAC address for the ARP request (localhost)
* @param periodicRefresh Do you want to periodically refresh the gateway mac?
- * @return
+ * @return ListenableFuture that contains the mac address of gateway ip.
*/
public ListenableFuture<MacAddress> resolveMacAddress( final Long externalNetworkBridgeDpid, final Ipv4Address gatewayIp,
final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress, final Boolean periodicRefresh);
/**
* Method will stop the periodic refresh of the given gateway ip address.
- * @param gatewayIp
+ * @param gatewayIp Gateway IP Address
*/
public void stopPeriodicRefresh(final Ipv4Address gatewayIp);
}
import java.util.List;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
/**
* This interface allows ingress Port Security flows to be written to devices.
package org.opendaylight.ovsdb.openstack.netvirt.api;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.osgi.framework.ServiceReference;
public interface NetworkingProvider {
/**
- * Returns the name of the NetworkingProvider
+ * @return the name of the NetworkingProvider
*/
String getName();
/**
- * Return true if the provider supports Network Service Instances
+ * @return true if the provider supports Network Service Instances
*/
boolean supportsServices();
/**
- * Return true if the provider supports per-tenant or "static" tunneling
+ * @return true if the provider supports per-tenant or "static" tunneling
*/
boolean hasPerTenantTunneling();
/**
* Handle Interface Update Callback Method
+ * @param network Neutron Network attached to the interface
+ * @param source Source node where interface is attached
+ * @param intf Termination point attached to the node
+ * @return true if interface update handled successfully
*/
boolean handleInterfaceUpdate(NeutronNetwork network, Node source, OvsdbTerminationPointAugmentation intf);
/**
* Handle Interface Delete Callback Method
+ * @param tunnelType Type of the tunnel (e.g. vxlan)
+ * @param network Neutron Network associated with the removed interface
+ * @param source Source node where interface was attached
+ * @param intf Termination point associated to the deleted interface
+ * @param isLastInstanceOnNode is last interface attached to the node ?
+ * @return true if interface delete handled successfully
*/
boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node source,
OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode);
* This method provides a set of common functionalities to initialize the Flow rules of an OVSDB node
* that are Openflow Version specific. Hence we have this method in addition to the following
* Openflow Node specific initialization method.
+ * @param node Node on which flow rules are going to be installed
*/
void initializeFlowRules(Node node);
/**
* Initialize the Flow rules for a given OpenFlow node
+ * @param openflowNode Node on which flow rules are going to be installed
*/
void initializeOFFlowRules(Node openflowNode);
}
package org.opendaylight.ovsdb.openstack.netvirt.api;
-import java.util.List;
-
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import java.util.List;
+
/**
* Open vSwitch isolates Tenant Networks using VLANs on the Integration Bridge.
* This class manages the provisioning of these VLANs
*/
NeutronPort getDhcpServerPort(OvsdbTerminationPointAugmentation intf);
+ /**
+ * Check if the given interface corresponds to a DHCP server port.
+ *
+ * @param intf the intf
+ * @return Return the DHCP neutron port
+ */
+ NeutronPort getNeutronPortFromDhcpIntf(OvsdbTerminationPointAugmentation intf);
+
/**
* Is the port a compute port.
*
*/
List<Neutron_IPs> getVmListForSecurityGroup(List<Neutron_IPs> srcAddressList,
String securityGroupUuid);
-}
\ No newline at end of file
+ /**
+ * Add or remove the security groups rules from the port.
+ * @param port the neutron port.
+ * @param securityGroup the security group associated with the port.
+ * @param write whether to add/delete flow.
+ */
+ void syncSecurityGroup(NeutronPort port, List<NeutronSecurityGroup> securityGroup, boolean write);
+}
package org.opendaylight.ovsdb.openstack.netvirt.api;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
/**
* Get the Neutron Network ID for a given Segmentation ID
+ * @param segmentationId segmentation id of the neutron network
+ * @return Neutron network id associated with the given segmentation id
*/
String getNetworkId(String segmentationId);
/**
* Network Created Callback
+ * @param node target node
+ * @param networkId Id of neutron network
+ * @return vlan assigned to the network
*/
int networkCreated(Node node, String networkId);
/**
* Network Deleted Callback
+ * @param id Id of the neutron network
*/
void networkDeleted(String id);
NeutronNetwork getTenantNetwork(OvsdbTerminationPointAugmentation terminationPointAugmentation);
package org.opendaylight.ovsdb.openstack.netvirt.impl;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
*
* @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
* @param path {@link InstanceIdentifier} for path to read
- * @param <D> the data object type
+ * @param data object of type D
* @return the result of the request
*/
public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean merge(
*
* @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
* @param path {@link InstanceIdentifier} for path to read
- * @param <D> the data object type
+ * @param data object of type D
* @return the result of the request
*/
public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean put(
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
import org.opendaylight.ovsdb.openstack.netvirt.api.*;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
import java.util.HashMap;
import java.util.HashSet;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
private volatile ArpProvider arpProvider;
private volatile RoutingProvider routingProvider;
private volatile GatewayMacResolver gatewayMacResolver;
+ private volatile SecurityServicesManager securityServicesManager;
private class FloatIpData {
// br-int of node where floating ip is associated with tenant port
*/
public void handleNeutronPortEvent(final NeutronPort neutronPort, Action action) {
LOG.debug("Neutron port {} event : {}", action, neutronPort.toString());
+
+ this.processSecurityGroupUpdate(neutronPort);
if (!this.enabled) {
return;
}
* way around) on OpenFlow Table 100.
*
* @param actionIn the {@link org.opendaylight.ovsdb.openstack.netvirt.api.Action} action to be handled.
- * @param neutronFloatingIP An {@link org.opendaylight.neutron.spi.NeutronFloatingIP} instance of NeutronFloatingIP object.
+ * @param neutronFloatingIP An {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP} instance of NeutronFloatingIP object.
*/
public void handleNeutronFloatingIPEvent(final NeutronFloatingIP neutronFloatingIP,
Action actionIn) {
* Process the event.
*
* @param action the {@link org.opendaylight.ovsdb.openstack.netvirt.api.Action} action to be handled.
- * @param neutronNetwork An {@link org.opendaylight.neutron.spi.NeutronNetwork} instance of NeutronFloatingIP object.
+ * @param neutronNetwork An {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork} instance of NeutronFloatingIP object.
*/
public void handleNeutronNetworkEvent(final NeutronNetwork neutronNetwork, Action action) {
LOG.debug("neutronNetwork {}: network: {}", action, neutronNetwork);
* @param bridgeNode An instance of Node object.
* @param intf An {@link org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
* .OvsdbTerminationPointAugmentation} instance of OvsdbTerminationPointAugmentation object.
- * @param neutronNetwork An {@link org.opendaylight.neutron.spi.NeutronNetwork} instance of NeutronNetwork
+ * @param neutronNetwork An {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork} instance of NeutronNetwork
* object.
* @param action the {@link org.opendaylight.ovsdb.openstack.netvirt.api.Action} action to be handled.
*/
}
}
+ private void processSecurityGroupUpdate(NeutronPort neutronPort) {
+ LOG.trace("processSecurityGroupUpdate:" + neutronPort);
+ /**
+ * Get updated data and original data for the the changed. Identify the security groups that got
+ * added and removed and call the appropriate providers for updating the flows.
+ */
+ try {
+ NeutronPort originalPort = neutronPort.getOriginalPort();
+ if (null == originalPort) {
+ LOG.debug("processSecurityGroupUpdate: originalport is empty");
+ return;
+ }
+ List<NeutronSecurityGroup> addedGroup = getsecurityGroupChanged(neutronPort,
+ neutronPort.getOriginalPort());
+ List<NeutronSecurityGroup> deletedGroup = getsecurityGroupChanged(neutronPort.getOriginalPort(),
+ neutronPort);
+
+ if (null != addedGroup && !addedGroup.isEmpty()) {
+ securityServicesManager.syncSecurityGroup(neutronPort,addedGroup,true);
+ }
+ if (null != deletedGroup && !deletedGroup.isEmpty()) {
+ securityServicesManager.syncSecurityGroup(neutronPort,deletedGroup,false);
+ }
+
+ } catch (Exception e) {
+ LOG.error("Exception in processSecurityGroupUpdate", e);
+ }
+ }
+
+ private List<NeutronSecurityGroup> getsecurityGroupChanged(NeutronPort port1, NeutronPort port2) {
+ LOG.trace("getsecurityGroupChanged:" + "Port1:" + port1 + "Port2" + port2);
+ ArrayList<NeutronSecurityGroup> list1 = new ArrayList<NeutronSecurityGroup>(port1.getSecurityGroups());
+ ArrayList<NeutronSecurityGroup> list2 = new ArrayList<NeutronSecurityGroup>(port2.getSecurityGroups());
+ for (Iterator<NeutronSecurityGroup> iterator = list1.iterator(); iterator.hasNext();) {
+ NeutronSecurityGroup securityGroup1 = iterator.next();
+ for (NeutronSecurityGroup securityGroup2 :list2) {
+ if (securityGroup1.getID().equals(securityGroup2.getID())) {
+ iterator.remove();
+ }
+ }
+ }
+ return list1;
+ }
+
private void programL3ForwardingStage1(Node node, Long dpid, String providerSegmentationId,
String macAddress, String ipStr,
Action actionForNode) {
(Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
gatewayMacResolver =
(GatewayMacResolver) ServiceHelper.getGlobalInstance(GatewayMacResolver.class, this);
+ securityServicesManager =
+ (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
initL3AdapterMembers();
}
package org.opendaylight.ovsdb.openstack.netvirt.impl;
import com.google.common.collect.Sets;
+
import java.util.Set;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbInventoryService;
import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronFloatingIPChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronNetworkChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronPortChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronRouterChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronSubnetChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronLoadBalancerPoolChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronLoadBalancerPoolMemberChangeListener;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
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.TopologyId;
@Override
public void providersReady() {
ovsdbDataChangeListener.start();
+ initializeNeutronModelsDataChangeListeners(dataBroker);
initializeNetvirtTopology();
}
LOG.error("Error initializing netvirt topology");
}
}
+
+ private void initializeNeutronModelsDataChangeListeners(
+ DataBroker db) {
+ new NeutronNetworkChangeListener(db);
+ new NeutronSubnetChangeListener(db);
+ new NeutronPortChangeListener(db);
+ new NeutronRouterChangeListener(db);
+ new NeutronFloatingIPChangeListener(db);
+ new NeutronLoadBalancerPoolChangeListener(db);
+ new NeutronLoadBalancerPoolMemberChangeListener(db);
+ }
+
}
package org.opendaylight.ovsdb.openstack.netvirt.impl;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
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.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
+import java.util.List;
+
public class SecurityServicesImpl implements ConfigInterface, SecurityServicesManager {
private static final Logger LOG = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
private volatile INeutronPortCRUD neutronPortCache;
private volatile INeutronSubnetCRUD neutronSubnetCache;
private volatile Southbound southbound;
+ private volatile INeutronNetworkCRUD neutronNetworkCache;
+ private volatile ConfigurationService configurationService;
+ private volatile IngressAclProvider ingressAclProvider;
+ private volatile EgressAclProvider egressAclProvider;
+ private volatile SecurityServicesManager securityServicesManager;
@Override
public boolean isPortSecurityReady(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
LOG.error("getDHCPServerPort:getDHCPServerPort failed due to ", e);
return null;
}
-
return null;
+ }
+ @Override
+ public NeutronPort getNeutronPortFromDhcpIntf(
+ OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+ if (neutronPortCache == null) {
+ LOG.error("getNeutronPortFromDhcpIntf: neutron port is null");
+ return null;
+ }
+ String neutronPortId = southbound.getInterfaceExternalIdsValue(
+ terminationPointAugmentation,
+ Constants.EXTERNAL_ID_INTERFACE_ID);
+ if (neutronPortId == null) {
+ return null;
+ }
+ NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+ if (neutronPort == null) {
+ LOG.error("getNeutronPortFromDhcpIntf: neutron port of {} is not found", neutronPortId);
+ return null;
+ }
+ /* if the current port is a DHCP port, return true*/
+ if (neutronPort.getDeviceOwner().contains("dhcp")) {
+ LOG.trace("getNeutronPortFromDhcpIntf: neutronPort is a dhcp port", neutronPort );
+ return neutronPort;
+ }
+ return null;
}
@Override
}
+ @Override
+ public void syncSecurityGroup(NeutronPort port, List<NeutronSecurityGroup> securityGroupList, boolean write) {
+ LOG.trace("syncSecurityGroup:" + securityGroupList + " Write:" + Boolean.valueOf(write));
+ if (null != port && null != port.getSecurityGroups()) {
+ Node node = getNode(port);
+ NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
+ String segmentationId = neutronNetwork.getProviderSegmentationID();
+ OvsdbTerminationPointAugmentation intf = getInterface(node, port);
+ long localPort = southbound.getOFPort(intf);
+ String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+ if (attachedMac == null) {
+ LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
+ return;
+ }
+ long dpid = getDpidOfIntegrationBridge(node);
+ List<Neutron_IPs> srcAddressList = securityServicesManager.getIpAddressList(node, intf);
+ for (NeutronSecurityGroup securityGroupInPort:securityGroupList) {
+ ingressAclProvider.programPortSecurityAcl(dpid, segmentationId, attachedMac, localPort,
+ securityGroupInPort, srcAddressList, write);
+ egressAclProvider.programPortSecurityAcl(dpid, segmentationId, attachedMac, localPort,
+ securityGroupInPort, srcAddressList, write);
+ }
+ }
+ }
+
+ private long getDpidOfIntegrationBridge(Node node) {
+ LOG.trace("getDpidOfIntegrationBridge:" + node);
+ long dpid = 0L;
+ if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
+ dpid = getDpid(node);
+ }
+ return dpid;
+ }
+
+ private long getDpid(Node node) {
+ LOG.trace("getDpid" + node);
+ long dpid = southbound.getDataPathId(node);
+ if (dpid == 0) {
+ LOG.warn("getDpid: dpid not found: {}", node);
+ }
+ return dpid;
+ }
+
+ private Node getNode(NeutronPort port) {
+ LOG.trace("getNode:Port" + port);
+ List<Node> toplogyNodes = southbound.readOvsdbTopologyNodes();
+
+ for (Node topologyNode : toplogyNodes) {
+ try {
+ Node node = southbound.getBridgeNode(topologyNode,Constants.INTEGRATION_BRIDGE);
+ List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
+ for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
+ String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
+ Constants.EXTERNAL_ID_INTERFACE_ID);
+ if (null != uuid && uuid.equals(port.getID())) {
+ return node;
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("Exception during handlingNeutron network delete", e);
+ }
+ }
+ return null;
+ }
+
+ private OvsdbTerminationPointAugmentation getInterface(Node node, NeutronPort port) {
+ LOG.trace("getInterface:Node:" + node + " Port:" + port);
+ try {
+ List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
+ for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
+ String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
+ Constants.EXTERNAL_ID_INTERFACE_ID);
+ if (null != uuid && uuid.equals(port.getID())) {
+ return ovsdbPort;
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("Exception during handlingNeutron network delete", e);
+ }
+ return null;
+ }
+
@Override
public void setDependencies(ServiceReference serviceReference) {
southbound =
(Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+ neutronNetworkCache =
+ (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
+ configurationService =
+ (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
+ securityServicesManager =
+ (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
}
@Override
neutronPortCache = (INeutronPortCRUD)impl;
} else if (impl instanceof INeutronSubnetCRUD) {
neutronSubnetCache = (INeutronSubnetCRUD) impl;
+ } else if (impl instanceof IngressAclProvider) {
+ ingressAclProvider = (IngressAclProvider) impl;
+ } else if (impl instanceof EgressAclProvider) {
+ egressAclProvider = (EgressAclProvider) impl;
}
}
-}
\ No newline at end of file
+}
/**
* Method read ports from bridge node. Method will check if the provided node
* has the ports details, if not, it will read from Operational data store.
- * @param node
- * @return
+ * @param node Target bridge to getch termination points from.
+ * @return List of termination points on the given bridge
*/
public List<OvsdbTerminationPointAugmentation> getTerminationPointsOfBridge(Node node) {
List<OvsdbTerminationPointAugmentation> tpAugmentations = extractTerminationPointAugmentations(node);
package org.opendaylight.ovsdb.openstack.netvirt.impl;
import com.google.common.base.Preconditions;
+
import java.util.List;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+/**
+ * This class contains behaviour common to Neutron configuration objects
+ */
+public interface INeutronObject {
+
+ String getID();
+
+ void setID(String id);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Firewall as a service
+ * (FWaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of the fields:
+ * Implemented fields are as follows:
+ *
+ * id uuid-str
+ * tenant_id uuid-str
+ * name String
+ * description String
+ * admin_state_up Bool
+ * status String
+ * shared Bool
+ * firewall_policy_id uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ *
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFirewall implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String firewallUUID;
+
+ @XmlElement (name = "tenant_id")
+ String firewallTenantID;
+
+ @XmlElement (name = "name")
+ String firewallName;
+
+ @XmlElement (name = "description")
+ String firewallDescription;
+
+ @XmlElement (defaultValue = "true", name = "admin_state_up")
+ Boolean firewallAdminStateIsUp;
+
+ @XmlElement (name = "status")
+ String firewallStatus;
+
+ @XmlElement (defaultValue = "false", name = "shared")
+ Boolean firewallIsShared;
+
+ @XmlElement (name = "firewall_policy_id")
+ String neutronFirewallPolicyID;
+
+ public String getID() {
+ return firewallUUID;
+ }
+
+ public void setID(String id) {
+ firewallUUID = id;
+ }
+
+ // @deprecated use getID()
+ public String getFirewallUUID() {
+ return firewallUUID;
+ }
+
+ // @deprecated use setID()
+ public void setFirewallUUID(String firewallUUID) {
+ this.firewallUUID = firewallUUID;
+ }
+
+ public String getFirewallTenantID() {
+ return firewallTenantID;
+ }
+
+ public void setFirewallTenantID(String firewallTenantID) {
+ this.firewallTenantID = firewallTenantID;
+ }
+
+ public String getFirewallName() {
+ return firewallName;
+ }
+
+ public void setFirewallName(String firewallName) {
+ this.firewallName = firewallName;
+ }
+
+ public String getFirewallDescription() {
+ return firewallDescription;
+ }
+
+ public void setFirewallDescription(String firewallDescription) {
+ this.firewallDescription = firewallDescription;
+ }
+
+ public Boolean getFirewallAdminStateIsUp() {
+ return firewallAdminStateIsUp;
+ }
+
+ public void setFirewallAdminStateIsUp(Boolean firewallAdminStateIsUp) {
+ this.firewallAdminStateIsUp = firewallAdminStateIsUp;
+ }
+
+ public String getFirewallStatus() {
+ return firewallStatus;
+ }
+
+ public void setFirewallStatus(String firewallStatus) {
+ this.firewallStatus = firewallStatus;
+ }
+
+ public Boolean getFirewallIsShared() {
+ return firewallIsShared;
+ }
+
+ public void setFirewallIsShared(Boolean firewallIsShared) {
+ this.firewallIsShared = firewallIsShared;
+ }
+
+ public String getFirewallPolicyID() {
+ return neutronFirewallPolicyID;
+ }
+
+ public void setNeutronFirewallPolicyID(String firewallPolicy) {
+ this.neutronFirewallPolicyID = firewallPolicy;
+ }
+
+ public NeutronFirewall extractFields(List<String> fields) {
+ NeutronFirewall ans = new NeutronFirewall();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setFirewallTenantID(this.getFirewallTenantID());
+ }
+ if (s.equals("name")) {
+ ans.setFirewallName(this.getFirewallName());
+ }
+ if(s.equals("description")) {
+ ans.setFirewallDescription(this.getFirewallDescription());
+ }
+ if (s.equals("admin_state_up")) {
+ ans.setFirewallAdminStateIsUp(firewallAdminStateIsUp);
+ }
+ if (s.equals("status")) {
+ ans.setFirewallStatus(this.getFirewallStatus());
+ }
+ if (s.equals("shared")) {
+ ans.setFirewallIsShared(firewallIsShared);
+ }
+ if (s.equals("firewall_policy_id")) {
+ ans.setNeutronFirewallPolicyID(this.getFirewallPolicyID());
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronFirewall{" +
+ "firewallUUID='" + firewallUUID + '\'' +
+ ", firewallTenantID='" + firewallTenantID + '\'' +
+ ", firewallName='" + firewallName + '\'' +
+ ", firewallDescription='" + firewallDescription + '\'' +
+ ", firewallAdminStateIsUp=" + firewallAdminStateIsUp +
+ ", firewallStatus='" + firewallStatus + '\'' +
+ ", firewallIsShared=" + firewallIsShared +
+ ", firewallRulePolicyID=" + neutronFirewallPolicyID +
+ '}';
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Firewall as a service
+ * (FWaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of the fields.
+ * The implemented fields are as follows:
+ *
+ * id uuid-str
+ * tenant_id uuid-str
+ * name String
+ * description String
+ * shared Boolean
+ * firewall_rules List
+ * audited Boolean
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ *
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFirewallPolicy implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String firewallPolicyUUID;
+
+ @XmlElement (name = "tenant_id")
+ String firewallPolicyTenantID;
+
+ @XmlElement (name = "name")
+ String firewallPolicyName;
+
+ @XmlElement (name = "description")
+ String firewallPolicyDescription;
+
+ @XmlElement (defaultValue = "false", name = "shared")
+ Boolean firewallPolicyIsShared;
+
+ @XmlElement (name = "firewall_rules")
+ List<String> firewallPolicyRules;
+
+ @XmlElement (defaultValue = "false", name = "audited")
+ Boolean firewallPolicyIsAudited;
+
+ public Boolean getFirewallPolicyIsAudited() {
+ return firewallPolicyIsAudited;
+ }
+
+ public void setFirewallPolicyIsAudited(Boolean firewallPolicyIsAudited) {
+ this.firewallPolicyIsAudited = firewallPolicyIsAudited;
+ }
+
+ public void setFirewallPolicyRules(List<String> firewallPolicyRules) {
+ this.firewallPolicyRules = firewallPolicyRules;
+ }
+
+ public List<String> getFirewallPolicyRules() {
+ return firewallPolicyRules;
+ }
+
+ public Boolean getFirewallPolicyIsShared() {
+ return firewallPolicyIsShared;
+ }
+
+ public void setFirewallPolicyIsShared(Boolean firewallPolicyIsShared) {
+ this.firewallPolicyIsShared = firewallPolicyIsShared;
+ }
+
+ public String getFirewallPolicyDescription() {
+ return firewallPolicyDescription;
+ }
+
+ public void setFirewallPolicyDescription(String firewallPolicyDescription) {
+ this.firewallPolicyDescription = firewallPolicyDescription;
+ }
+
+ public String getFirewallPolicyName() {
+ return firewallPolicyName;
+ }
+
+ public void setFirewallPolicyName(String firewallPolicyName) {
+ this.firewallPolicyName = firewallPolicyName;
+ }
+
+ public String getFirewallPolicyTenantID() {
+ return firewallPolicyTenantID;
+ }
+
+ public void setFirewallPolicyTenantID(String firewallPolicyTenantID) {
+ this.firewallPolicyTenantID = firewallPolicyTenantID;
+ }
+
+ public String getID() {
+ return firewallPolicyUUID;
+ }
+
+ public void setID(String id) {
+ firewallPolicyUUID = id;
+ }
+
+ // @deprecated use getID()
+ public String getFirewallPolicyUUID() {
+ return firewallPolicyUUID;
+ }
+
+ // @deprecated use setID()
+ public void setFirewallPolicyUUID(String firewallPolicyUUID) {
+ this.firewallPolicyUUID = firewallPolicyUUID;
+ }
+
+ public NeutronFirewallPolicy extractFields(List<String> fields) {
+ NeutronFirewallPolicy ans = new NeutronFirewallPolicy();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setFirewallPolicyTenantID(this.getFirewallPolicyTenantID());
+ }
+ if (s.equals("name")) {
+ ans.setFirewallPolicyName(this.getFirewallPolicyName());
+ }
+ if(s.equals("description")) {
+ ans.setFirewallPolicyDescription(this.getFirewallPolicyDescription());
+ }
+ if (s.equals("shared")) {
+ ans.setFirewallPolicyIsShared(firewallPolicyIsShared);
+ }
+ if (s.equals("firewall_rules")) {
+ List<String> firewallRuleList = new ArrayList<String>();
+ firewallRuleList.addAll(this.getFirewallPolicyRules());
+ ans.setFirewallPolicyRules(firewallRuleList);
+ }
+ if (s.equals("audited")) {
+ ans.setFirewallPolicyIsAudited(firewallPolicyIsAudited);
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronFirewallPolicy{" +
+ "firewallPolicyUUID='" + firewallPolicyUUID + '\'' +
+ ", firewallPolicyTenantID='" + firewallPolicyTenantID + '\'' +
+ ", firewallPolicyName='" + firewallPolicyName + '\'' +
+ ", firewallPolicyDescription='" + firewallPolicyDescription + '\'' +
+ ", firewallPolicyIsShared=" + firewallPolicyIsShared +
+ ", firewallPolicyRules=" + firewallPolicyRules +
+ ", firewallPolicyIsAudited='" + firewallPolicyIsAudited + '\'' +
+ '}';
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2015 Red Hat, 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Firewall as a service
+ * (FWaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of the fields.
+ * The implemented fields are as follows:
+ *
+ * tenant_id uuid-str
+ * name String
+ * description String
+ * admin_state_up Bool
+ * status String
+ * shared Bool
+ * firewall_policy_id uuid-str
+ * protocol String
+ * ip_version Integer
+ * source_ip_address String (IP addr or CIDR)
+ * destination_ip_address String (IP addr or CIDR)
+ * source_port Integer
+ * destination_port Integer
+ * position Integer
+ * action String
+ * enabled Bool
+ * id uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ *
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFirewallRule implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String firewallRuleUUID;
+
+ @XmlElement(name = "tenant_id")
+ String firewallRuleTenantID;
+
+ @XmlElement(name = "name")
+ String firewallRuleName;
+
+ @XmlElement(name = "description")
+ String firewallRuleDescription;
+
+ @XmlElement(name = "status")
+ String firewallRuleStatus;
+
+ @XmlElement(defaultValue = "false", name = "shared")
+ Boolean firewallRuleIsShared;
+
+ @XmlElement(name = "firewall_policy_id")
+ String firewallRulePolicyID;
+
+ @XmlElement(name = "protocol")
+ String firewallRuleProtocol;
+
+ @XmlElement(name = "ip_version")
+ Integer firewallRuleIpVer;
+
+ @XmlElement(name = "source_ip_address")
+ String firewallRuleSrcIpAddr;
+
+ @XmlElement(name = "destination_ip_address")
+ String firewallRuleDstIpAddr;
+
+ @XmlElement(name = "source_port")
+ Integer firewallRuleSrcPort;
+
+ @XmlElement(name = "destination_port")
+ Integer firewallRuleDstPort;
+
+ @XmlElement(name = "position")
+ Integer firewallRulePosition;
+
+ @XmlElement(name = "action")
+ String firewallRuleAction;
+
+ @XmlElement(name = "enabled")
+ Boolean firewallRuleIsEnabled;
+
+ public Boolean getFirewallRuleIsEnabled() {
+ return firewallRuleIsEnabled;
+ }
+
+ public void setFirewallRuleIsEnabled(Boolean firewallRuleIsEnabled) {
+ this.firewallRuleIsEnabled = firewallRuleIsEnabled;
+ }
+
+ public String getFirewallRuleAction() {
+ return firewallRuleAction;
+ }
+
+ public void setFirewallRuleAction(String firewallRuleAction) {
+ this.firewallRuleAction = firewallRuleAction;
+ }
+
+ public Integer getFirewallRulePosition() {
+ return firewallRulePosition;
+ }
+
+ public void setFirewallRulePosition(Integer firewallRulePosition) {
+ this.firewallRulePosition = firewallRulePosition;
+ }
+
+ public Integer getFirewallRuleDstPort() {
+ return firewallRuleDstPort;
+ }
+
+ public void setFirewallRuleDstPort(Integer firewallRuleDstPort) {
+ this.firewallRuleDstPort = firewallRuleDstPort;
+ }
+
+ public Integer getFirewallRuleSrcPort() {
+ return firewallRuleSrcPort;
+ }
+
+ public void setFirewallRuleSrcPort(Integer firewallRuleSrcPort) {
+ this.firewallRuleSrcPort = firewallRuleSrcPort;
+ }
+
+ public String getFirewallRuleDstIpAddr() {
+ return firewallRuleDstIpAddr;
+ }
+
+ public void setFirewallRuleDstIpAddr(String firewallRuleDstIpAddr) {
+ this.firewallRuleDstIpAddr = firewallRuleDstIpAddr;
+ }
+
+ public String getFirewallRuleSrcIpAddr() {
+ return firewallRuleSrcIpAddr;
+ }
+
+ public void setFirewallRuleSrcIpAddr(String firewallRuleSrcIpAddr) {
+ this.firewallRuleSrcIpAddr = firewallRuleSrcIpAddr;
+ }
+
+ public Integer getFirewallRuleIpVer() {
+ return firewallRuleIpVer;
+ }
+
+ public void setFirewallRuleIpVer(Integer firewallRuleIpVer) {
+ this.firewallRuleIpVer = firewallRuleIpVer;
+ }
+
+ public String getFirewallRuleProtocol() {
+ return firewallRuleProtocol;
+ }
+
+ public void setFirewallRuleProtocol(String firewallRuleProtocol) {
+ this.firewallRuleProtocol = firewallRuleProtocol;
+ }
+
+ public String getFirewallRulePolicyID() {
+ return firewallRulePolicyID;
+ }
+
+ public void setFirewallRulesPolicyID(String firewallRulePolicyID) {
+ this.firewallRulePolicyID = firewallRulePolicyID;
+ }
+
+ public Boolean getFirewallRuleIsShared() {
+ return firewallRuleIsShared;
+ }
+
+ public void setFirewallRuleIsShared(Boolean firewallRuleIsShared) {
+ this.firewallRuleIsShared = firewallRuleIsShared;
+ }
+
+ public String getFirewallRuleStatus() {
+ return firewallRuleStatus;
+ }
+
+ public void setFirewallRuleStatus(String firewallRuleStatus) {
+ this.firewallRuleStatus = firewallRuleStatus;
+ }
+
+ public String getFirewallRuleDescription() {
+ return firewallRuleDescription;
+ }
+
+ public void setFirewallRuleDescription(String firewallRuleDescription) {
+ this.firewallRuleDescription = firewallRuleDescription;
+ }
+
+ public String getFirewallRuleName() {
+ return firewallRuleName;
+ }
+
+ public void setFirewallRuleName(String firewallRuleName) {
+ this.firewallRuleName = firewallRuleName;
+ }
+
+ public String getFirewallRuleTenantID() {
+ return firewallRuleTenantID;
+ }
+
+ public void setFirewallRuleTenantID(String firewallRuleTenantID) {
+ this.firewallRuleTenantID = firewallRuleTenantID;
+ }
+
+ public String getID() {
+ return firewallRuleUUID;
+ }
+
+ public void setID(String id) {
+ firewallRuleUUID = id;
+ }
+
+ // @deprecated use getID()
+ public String getFirewallRuleUUID() {
+ return firewallRuleUUID;
+ }
+
+ // @deprecated use setID()
+ public void setFireWallRuleID(String firewallRuleUUID) {
+ this.firewallRuleUUID = firewallRuleUUID;
+ }
+
+ public NeutronFirewallRule extractFields(List<String> fields) {
+ NeutronFirewallRule ans = new NeutronFirewallRule();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setFirewallRuleTenantID(this.getFirewallRuleTenantID());
+ }
+ if (s.equals("name")) {
+ ans.setFirewallRuleName(this.getFirewallRuleName());
+ }
+ if (s.equals("description")) {
+ ans.setFirewallRuleDescription(this.getFirewallRuleDescription());
+ }
+ if (s.equals("status")) {
+ ans.setFirewallRuleStatus(this.getFirewallRuleStatus());
+ }
+ if (s.equals("shared")) {
+ ans.setFirewallRuleIsShared(firewallRuleIsShared);
+ }
+ if (s.equals("firewall_policy_id")) {
+ ans.setFirewallRulesPolicyID(this.getFirewallRulePolicyID());
+ }
+ if (s.equals("protocol")) {
+ ans.setFirewallRuleProtocol(this.getFirewallRuleProtocol());
+ }
+ if (s.equals("source_ip_address")) {
+ ans.setFirewallRuleSrcIpAddr(this.getFirewallRuleSrcIpAddr());
+ }
+ if (s.equals("destination_ip_address")) {
+ ans.setFirewallRuleDstIpAddr(this.getFirewallRuleDstIpAddr());
+ }
+ if (s.equals("source_port")) {
+ ans.setFirewallRuleSrcPort(this.getFirewallRuleSrcPort());
+ }
+ if (s.equals("destination_port")) {
+ ans.setFirewallRuleDstPort(this.getFirewallRuleDstPort());
+ }
+ if (s.equals("position")) {
+ ans.setFirewallRulePosition(this.getFirewallRulePosition());
+ }
+ if (s.equals("action")) {
+ ans.setFirewallRuleAction(this.getFirewallRuleAction());
+ }
+ if (s.equals("enabled")) {
+ ans.setFirewallRuleIsEnabled(firewallRuleIsEnabled);
+ }
+
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "firewallPolicyRules{" +
+ "firewallRuleUUID='" + firewallRuleUUID + '\'' +
+ ", firewallRuleTenantID='" + firewallRuleTenantID + '\'' +
+ ", firewallRuleName='" + firewallRuleName + '\'' +
+ ", firewallRuleDescription='" + firewallRuleDescription + '\'' +
+ ", firewallRuleStatus='" + firewallRuleStatus + '\'' +
+ ", firewallRuleIsShared=" + firewallRuleIsShared +
+ ", firewallRulePolicyID=" + firewallRulePolicyID +
+ ", firewallRuleProtocol='" + firewallRuleProtocol + '\'' +
+ ", firewallRuleIpVer=" + firewallRuleIpVer +
+ ", firewallRuleSrcIpAddr='" + firewallRuleSrcIpAddr + '\'' +
+ ", firewallRuleDstIpAddr='" + firewallRuleDstIpAddr + '\'' +
+ ", firewallRuleSrcPort=" + firewallRuleSrcPort +
+ ", firewallRuleDstPort=" + firewallRuleDstPort +
+ ", firewallRulePosition=" + firewallRulePosition +
+ ", firewallRuleAction='" + firewallRuleAction + '\'' +
+ ", firewallRuleIsEnabled=" + firewallRuleIsEnabled +
+ '}';
+ }
+
+ public void initDefaults() {
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFloatingIP implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement (name = "id")
+ String floatingIPUUID;
+
+ @XmlElement (name = "floating_network_id")
+ String floatingNetworkUUID;
+
+ @XmlElement (name = "port_id")
+ String portUUID;
+
+ @XmlElement (name = "fixed_ip_address")
+ String fixedIPAddress;
+
+ @XmlElement (name = "floating_ip_address")
+ String floatingIPAddress;
+
+ @XmlElement (name = "tenant_id")
+ String tenantUUID;
+
+ @XmlElement (name="router_id")
+ String routerUUID;
+
+ @XmlElement (name="status")
+ String status;
+
+ public NeutronFloatingIP() {
+ }
+
+ public String getID() {
+ return floatingIPUUID;
+ }
+
+ public void setID(String id) {
+ floatingIPUUID = id;
+ }
+
+ // @deprecated use getID()
+ public String getFloatingIPUUID() {
+ return floatingIPUUID;
+ }
+
+ // @deprecated use setID()
+ public void setFloatingIPUUID(String floatingIPUUID) {
+ this.floatingIPUUID = floatingIPUUID;
+ }
+
+ public String getFloatingNetworkUUID() {
+ return floatingNetworkUUID;
+ }
+
+ public void setFloatingNetworkUUID(String floatingNetworkUUID) {
+ this.floatingNetworkUUID = floatingNetworkUUID;
+ }
+
+ public String getPortUUID() {
+ return portUUID;
+ }
+
+ public String getRouterUUID() {
+ return routerUUID;
+ }
+
+ public void setPortUUID(String portUUID) {
+ this.portUUID = portUUID;
+ }
+
+ public String getFixedIPAddress() {
+ return fixedIPAddress;
+ }
+
+ public void setFixedIPAddress(String fixedIPAddress) {
+ this.fixedIPAddress = fixedIPAddress;
+ }
+
+ public String getFloatingIPAddress() {
+ return floatingIPAddress;
+ }
+
+ public void setFloatingIPAddress(String floatingIPAddress) {
+ this.floatingIPAddress = floatingIPAddress;
+ }
+
+ public String getTenantUUID() {
+ return tenantUUID;
+ }
+
+ public void setTenantUUID(String tenantUUID) {
+ this.tenantUUID = tenantUUID;
+ }
+
+ public void setRouterUUID(String routerUUID) {
+ this.routerUUID = routerUUID;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ /**
+ * This method copies selected fields from the object and returns them
+ * as a new object, suitable for marshaling.
+ *
+ * @param fields
+ * List of attributes to be extracted
+ * @return an OpenStackFloatingIPs object with only the selected fields
+ * populated
+ */
+
+ public NeutronFloatingIP extractFields(List<String> fields) {
+ NeutronFloatingIP ans = new NeutronFloatingIP();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if (s.equals("floating_network_id")) {
+ ans.setFloatingNetworkUUID(this.getFloatingNetworkUUID());
+ }
+ if (s.equals("port_id")) {
+ ans.setPortUUID(this.getPortUUID());
+ }
+ if (s.equals("fixed_ip_address")) {
+ ans.setFixedIPAddress(this.getFixedIPAddress());
+ }
+ if (s.equals("floating_ip_address")) {
+ ans.setFloatingIPAddress(this.getFloatingIPAddress());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setTenantUUID(this.getTenantUUID());
+ }
+ if (s.equals("router_id")) {
+ ans.setRouterUUID(this.getRouterUUID());
+ }
+ if (s.equals("status")) {
+ ans.setStatus(this.getStatus());
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronFloatingIP{" +
+ "fipUUID='" + floatingIPUUID + '\'' +
+ ", fipFloatingNetworkId='" + floatingNetworkUUID + '\'' +
+ ", fipPortUUID='" + portUUID + '\'' +
+ ", fipFixedIPAddress='" + fixedIPAddress + '\'' +
+ ", fipFloatingIPAddress=" + floatingIPAddress +
+ ", fipTenantId='" + tenantUUID + '\'' +
+ ", fipRouterId='" + routerUUID + '\'' +
+ ", fipStatus='" + status + '\'' +
+ '}';
+ }
+
+ public void initDefaults() {
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of the fields:
+ * Implemented fields are as follows:
+ *
+ * id uuid-str
+ * tenant_id uuid-str
+ * name String
+ * description String
+ * status String
+ * vip_address IP address
+ * vip_subnet uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancer implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String loadBalancerID;
+
+ @XmlElement (name = "tenant_id")
+ String loadBalancerTenantID;
+
+ @XmlElement (name = "name")
+ String loadBalancerName;
+
+ @XmlElement (name = "description")
+ String loadBalancerDescription;
+
+ @XmlElement (name = "status")
+ String loadBalancerStatus;
+
+ @XmlElement (name = "admin_state_up")
+ Boolean loadBalancerAdminStateUp;
+
+ @XmlElement (name = "vip_address")
+ String loadBalancerVipAddress;
+
+ @XmlElement (name = "vip_subnet_id")
+ String loadBalancerVipSubnetID;
+
+ public String getID() {
+ return loadBalancerID;
+ }
+
+ public void setID(String id) {
+ loadBalancerID = id;
+ }
+
+ // @deprecated use getID()
+ public String getLoadBalancerID() {
+ return loadBalancerID;
+ }
+
+ // @deprecated use setID()
+ public void setLoadBalancerID(String loadBalancerID) {
+ this.loadBalancerID = loadBalancerID;
+ }
+
+ public String getLoadBalancerTenantID() {
+ return loadBalancerTenantID;
+ }
+
+ public void setLoadBalancerTenantID(String loadBalancerTenantID) {
+ this.loadBalancerTenantID = loadBalancerTenantID;
+ }
+
+ public String getLoadBalancerName() {
+ return loadBalancerName;
+ }
+
+ public void setLoadBalancerName(String loadBalancerName) {
+ this.loadBalancerName = loadBalancerName;
+ }
+
+ public String getLoadBalancerDescription() {
+ return loadBalancerDescription;
+ }
+
+ public void setLoadBalancerDescription(String loadBalancerDescription) {
+ this.loadBalancerDescription = loadBalancerDescription;
+ }
+
+ public String getLoadBalancerStatus() {
+ return loadBalancerStatus;
+ }
+
+ public void setLoadBalancerStatus(String loadBalancerStatus) {
+ this.loadBalancerStatus = loadBalancerStatus;
+ }
+
+ public Boolean getLoadBalancerAdminStateUp() {
+ return loadBalancerAdminStateUp;
+ }
+
+ public void setLoadBalancerAdminStateUp(Boolean loadBalancerAdminStateUp) {
+ this.loadBalancerAdminStateUp = loadBalancerAdminStateUp;
+ }
+
+ public String getLoadBalancerVipAddress() {
+ return loadBalancerVipAddress;
+ }
+
+ public void setLoadBalancerVipAddress(String loadBalancerVipAddress) {
+ this.loadBalancerVipAddress = loadBalancerVipAddress;
+ }
+
+ public String getLoadBalancerVipSubnetID() {
+ return loadBalancerVipSubnetID;
+ }
+
+ public void setLoadBalancerVipSubnetID(String loadBalancerVipSubnetID) {
+ this.loadBalancerVipSubnetID = loadBalancerVipSubnetID;
+ }
+
+ public NeutronLoadBalancer extractFields(List<String> fields) {
+ NeutronLoadBalancer ans = new NeutronLoadBalancer();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setLoadBalancerTenantID(this.getLoadBalancerTenantID());
+ }
+ if (s.equals("name")) {
+ ans.setLoadBalancerName(this.getLoadBalancerName());
+ }
+ if(s.equals("description")) {
+ ans.setLoadBalancerDescription(this.getLoadBalancerDescription());
+ }
+ if (s.equals("vip_address")) {
+ ans.setLoadBalancerVipAddress(this.getLoadBalancerVipAddress());
+ }
+ if (s.equals("vip_subnet_id")) {
+ ans.setLoadBalancerVipSubnetID(this.getLoadBalancerVipSubnetID());
+ }
+ if (s.equals("status")) {
+ ans.setLoadBalancerStatus(this.getLoadBalancerStatus());
+ }
+ if (s.equals("admin_state_up")) {
+ ans.setLoadBalancerAdminStateUp(this.getLoadBalancerAdminStateUp());
+ }
+ }
+ return ans;
+ }
+
+ @Override public String toString() {
+ return "NeutronLoadBalancer{" +
+ "loadBalancerID='" + loadBalancerID + '\'' +
+ ", loadBalancerTenantID='" + loadBalancerTenantID + '\'' +
+ ", loadBalancerName='" + loadBalancerName + '\'' +
+ ", loadBalancerDescription='" + loadBalancerDescription + '\'' +
+ ", loadBalancerStatus='" + loadBalancerStatus + '\'' +
+ ", loadBalancerAdminStateUp='" + loadBalancerAdminStateUp + '\'' +
+ ", loadBalancerVipAddress='" + loadBalancerVipAddress + '\'' +
+ ", loadBalancerVipSubnetID='" + loadBalancerVipSubnetID + '\'' +
+ '}';
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of the fields:
+ * Implemented fields are as follows:
+ *
+ *
+ * id uuid-str
+ * tenant_id uuid-str
+ * type String
+ * delay Integer
+ * timeout Integer
+ * max_retries Integer
+ * http_method String
+ * url_path String
+ * expected_codes String
+ * admin_state_up Boolean
+ * status String
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerHealthMonitor
+ implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String loadBalancerHealthMonitorID;
+
+ @XmlElement (name = "tenant_id")
+ String loadBalancerHealthMonitorTenantID;
+
+ @XmlElement (name = "type")
+ String loadBalancerHealthMonitorType;
+
+ @XmlElement (name = "delay")
+ Integer loadBalancerHealthMonitorDelay;
+
+ @XmlElement (name = "timeout")
+ Integer loadBalancerHealthMonitorTimeout;
+
+ @XmlElement (name = "max_retries")
+ Integer loadBalancerHealthMonitorMaxRetries;
+
+ @XmlElement (name = "http_method")
+ String loadBalancerHealthMonitorHttpMethod;
+
+ @XmlElement (name = "url_path")
+ String loadBalancerHealthMonitorUrlPath;
+
+ @XmlElement (name = "expected_codes")
+ String loadBalancerHealthMonitorExpectedCodes;
+
+ @XmlElement (defaultValue = "true", name = "admin_state_up")
+ Boolean loadBalancerHealthMonitorAdminStateIsUp;
+
+ @XmlElement (name = "pools")
+ List<Neutron_ID> loadBalancerHealthMonitorPools;
+
+ public String getID() {
+ return loadBalancerHealthMonitorID;
+ }
+
+ public void setID(String id) {
+ loadBalancerHealthMonitorID = id;
+ }
+
+ // @deprecated use getID()
+ public String getLoadBalancerHealthMonitorID() {
+ return loadBalancerHealthMonitorID;
+ }
+
+ // @deprecated use setID()
+ public void setLoadBalancerHealthMonitorID(String loadBalancerHealthMonitorID) {
+ this.loadBalancerHealthMonitorID = loadBalancerHealthMonitorID;
+ }
+
+ public String getLoadBalancerHealthMonitorTenantID() {
+ return loadBalancerHealthMonitorTenantID;
+ }
+
+ public void setLoadBalancerHealthMonitorTenantID(String loadBalancerHealthMonitorTenantID) {
+ this.loadBalancerHealthMonitorTenantID = loadBalancerHealthMonitorTenantID;
+ }
+
+ public String getLoadBalancerHealthMonitorType() {
+ return loadBalancerHealthMonitorType;
+ }
+
+ public void setLoadBalancerHealthMonitorType(String loadBalancerHealthMonitorType) {
+ this.loadBalancerHealthMonitorType = loadBalancerHealthMonitorType;
+ }
+
+ public Integer getLoadBalancerHealthMonitorDelay() {
+ return loadBalancerHealthMonitorDelay;
+ }
+
+ public void setLoadBalancerHealthMonitorDelay(Integer loadBalancerHealthMonitorDelay) {
+ this.loadBalancerHealthMonitorDelay = loadBalancerHealthMonitorDelay;
+ }
+
+ public Integer getLoadBalancerHealthMonitorTimeout() {
+ return loadBalancerHealthMonitorTimeout;
+ }
+
+ public void setLoadBalancerHealthMonitorTimeout(Integer loadBalancerHealthMonitorTimeout) {
+ this.loadBalancerHealthMonitorTimeout = loadBalancerHealthMonitorTimeout;
+ }
+
+ public Integer getLoadBalancerHealthMonitorMaxRetries() {
+ return loadBalancerHealthMonitorMaxRetries;
+ }
+
+ public void setLoadBalancerHealthMonitorMaxRetries(Integer loadBalancerHealthMonitorMaxRetries) {
+ this.loadBalancerHealthMonitorMaxRetries = loadBalancerHealthMonitorMaxRetries;
+ }
+
+ public String getLoadBalancerHealthMonitorHttpMethod() {
+ return loadBalancerHealthMonitorHttpMethod;
+ }
+
+ public void setLoadBalancerHealthMonitorHttpMethod(String loadBalancerHealthMonitorHttpMethod) {
+ this.loadBalancerHealthMonitorHttpMethod = loadBalancerHealthMonitorHttpMethod;
+ }
+
+ public String getLoadBalancerHealthMonitorUrlPath() {
+ return loadBalancerHealthMonitorUrlPath;
+ }
+
+ public void setLoadBalancerHealthMonitorUrlPath(String loadBalancerHealthMonitorUrlPath) {
+ this.loadBalancerHealthMonitorUrlPath = loadBalancerHealthMonitorUrlPath;
+ }
+
+ public String getLoadBalancerHealthMonitorExpectedCodes() {
+ return loadBalancerHealthMonitorExpectedCodes;
+ }
+
+ public void setLoadBalancerHealthMonitorExpectedCodes(String loadBalancerHealthMonitorExpectedCodes) {
+ this.loadBalancerHealthMonitorExpectedCodes = loadBalancerHealthMonitorExpectedCodes;
+ }
+
+ public Boolean getLoadBalancerHealthMonitorAdminStateIsUp() {
+ return loadBalancerHealthMonitorAdminStateIsUp;
+ }
+
+ public void setLoadBalancerHealthMonitorAdminStateIsUp(Boolean loadBalancerHealthMonitorAdminStateIsUp) {
+ this.loadBalancerHealthMonitorAdminStateIsUp = loadBalancerHealthMonitorAdminStateIsUp;
+ }
+
+ public List<Neutron_ID> getLoadBalancerHealthMonitorPools() {
+ return loadBalancerHealthMonitorPools;
+ }
+
+ public void setLoadBalancerHealthMonitorPools(List<Neutron_ID> loadBalancerHealthMonitorPools) {
+ this.loadBalancerHealthMonitorPools = loadBalancerHealthMonitorPools;
+ }
+
+ public NeutronLoadBalancerHealthMonitor extractFields(List<String> fields) {
+ NeutronLoadBalancerHealthMonitor ans = new NeutronLoadBalancerHealthMonitor();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setLoadBalancerHealthMonitorTenantID(this.getLoadBalancerHealthMonitorTenantID());
+ }
+ if (s.equals("type")) {
+ ans.setLoadBalancerHealthMonitorType(this.getLoadBalancerHealthMonitorType());
+ }
+ if (s.equals("delay")) {
+ ans.setLoadBalancerHealthMonitorDelay(this.getLoadBalancerHealthMonitorDelay());
+ }
+ if (s.equals("timeout")) {
+ ans.setLoadBalancerHealthMonitorTimeout(this.getLoadBalancerHealthMonitorTimeout());
+ }
+ if (s.equals("max_retries")) {
+ ans.setLoadBalancerHealthMonitorMaxRetries(this.getLoadBalancerHealthMonitorMaxRetries());
+ }
+ if (s.equals("http_method")) {
+ ans.setLoadBalancerHealthMonitorHttpMethod(this.getLoadBalancerHealthMonitorHttpMethod());
+ }
+ if(s.equals("url_path")) {
+ ans.setLoadBalancerHealthMonitorUrlPath(this.getLoadBalancerHealthMonitorUrlPath());
+ }
+ if (s.equals("expected_codes")) {
+ ans.setLoadBalancerHealthMonitorExpectedCodes(this.getLoadBalancerHealthMonitorExpectedCodes());
+ }
+ if (s.equals("admin_state_up")) {
+ ans.setLoadBalancerHealthMonitorAdminStateIsUp(loadBalancerHealthMonitorAdminStateIsUp);
+ }
+ }
+ return ans;
+ }
+
+ @Override public String toString() {
+ return "NeutronLoadBalancerHealthMonitor{" +
+ "loadBalancerHealthMonitorID='" + loadBalancerHealthMonitorID + '\'' +
+ ", loadBalancerHealthMonitorTenantID='" + loadBalancerHealthMonitorTenantID + '\'' +
+ ", loadBalancerHealthMonitorType='" + loadBalancerHealthMonitorType + '\'' +
+ ", loadBalancerHealthMonitorDelay=" + loadBalancerHealthMonitorDelay +
+ ", loadBalancerHealthMonitorTimeout=" + loadBalancerHealthMonitorTimeout +
+ ", loadBalancerHealthMonitorMaxRetries=" + loadBalancerHealthMonitorMaxRetries +
+ ", loadBalancerHealthMonitorHttpMethod='" + loadBalancerHealthMonitorHttpMethod + '\'' +
+ ", loadBalancerHealthMonitorUrlPath='" + loadBalancerHealthMonitorUrlPath + '\'' +
+ ", loadBalancerHealthMonitorExpectedCodes='" + loadBalancerHealthMonitorExpectedCodes + '\'' +
+ ", loadBalancerHealthMonitorAdminStateIsUp=" + loadBalancerHealthMonitorAdminStateIsUp +
+ '}';
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of the fields:
+ * Implemented fields are as follows:
+ *
+ * id uuid-str
+ * default_pool_id String
+ * tenant_id uuid-str
+ * name String
+ * description String
+ * shared Bool
+ * protocol String
+ * protocol_port String
+ * load_balancer_id String
+ * admin_state_up Boolean
+ * status String
+ *
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerListener
+ implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String loadBalancerListenerID;
+
+ @XmlElement (name = "default_pool_id")
+ String neutronLoadBalancerListenerDefaultPoolID;
+
+ @XmlElement (name = "connection_limit")
+ Integer neutronLoadBalancerListenerConnectionLimit;
+
+ @XmlElement (name = "tenant_id")
+ String loadBalancerListenerTenantID;
+
+ @XmlElement (name = "name")
+ String loadBalancerListenerName;
+
+ @XmlElement (name = "description")
+ String loadBalancerListenerDescription;
+
+ @XmlElement (defaultValue = "true", name = "admin_state_up")
+ Boolean loadBalancerListenerAdminStateIsUp;
+
+ @XmlElement (name = "protocol")
+ String neutronLoadBalancerListenerProtocol;
+
+ @XmlElement (name = "protocol_port")
+ String neutronLoadBalancerListenerProtocolPort;
+
+ @XmlElement (name = "load_balancers")
+ List<Neutron_ID> neutronLoadBalancerListenerLoadBalancerIDs;
+
+ public String getID() {
+ return loadBalancerListenerID;
+ }
+
+ public void setID(String id) {
+ loadBalancerListenerID = id;
+ }
+
+ // @deprecated use getID()
+ public String getLoadBalancerListenerID() {
+ return loadBalancerListenerID;
+ }
+
+ // @deprecated use setID()
+ public void setLoadBalancerListenerID(String loadBalancerListenerID) {
+ this.loadBalancerListenerID = loadBalancerListenerID;
+ }
+
+ public String getLoadBalancerListenerTenantID() {
+ return loadBalancerListenerTenantID;
+ }
+
+ public void setLoadBalancerListenerTenantID(String loadBalancerListenerTenantID) {
+ this.loadBalancerListenerTenantID = loadBalancerListenerTenantID;
+ }
+
+ public String getLoadBalancerListenerName() {
+ return loadBalancerListenerName;
+ }
+
+ public void setLoadBalancerListenerName(String loadBalancerListenerName) {
+ this.loadBalancerListenerName = loadBalancerListenerName;
+ }
+
+ public String getLoadBalancerListenerDescription() {
+ return loadBalancerListenerDescription;
+ }
+
+ public void setLoadBalancerListenerDescription(String loadBalancerListenerDescription) {
+ this.loadBalancerListenerDescription = loadBalancerListenerDescription;
+ }
+
+ public Boolean getLoadBalancerListenerAdminStateIsUp() {
+ return loadBalancerListenerAdminStateIsUp;
+ }
+
+ public void setLoadBalancerListenerAdminStateIsUp(Boolean loadBalancerListenerAdminStateIsUp) {
+ this.loadBalancerListenerAdminStateIsUp = loadBalancerListenerAdminStateIsUp;
+ }
+
+ public String getNeutronLoadBalancerListenerProtocol() {
+ return neutronLoadBalancerListenerProtocol;
+ }
+
+ public void setNeutronLoadBalancerListenerProtocol(String neutronLoadBalancerListenerProtocol) {
+ this.neutronLoadBalancerListenerProtocol = neutronLoadBalancerListenerProtocol;
+ }
+
+ public String getNeutronLoadBalancerListenerProtocolPort() {
+ return neutronLoadBalancerListenerProtocolPort;
+ }
+
+ public void setNeutronLoadBalancerListenerProtocolPort(String neutronLoadBalancerListenerProtocolPort) {
+ this.neutronLoadBalancerListenerProtocolPort = neutronLoadBalancerListenerProtocolPort;
+ }
+
+ public String getNeutronLoadBalancerListenerDefaultPoolID() {
+ return neutronLoadBalancerListenerDefaultPoolID;
+ }
+
+ public void setNeutronLoadBalancerListenerDefaultPoolID(String neutronLoadBalancerListenerDefaultPoolID) {
+ this.neutronLoadBalancerListenerDefaultPoolID = neutronLoadBalancerListenerDefaultPoolID;
+ }
+
+ public Integer getNeutronLoadBalancerListenerConnectionLimit() {
+ return neutronLoadBalancerListenerConnectionLimit;
+ }
+
+ public void setNeutronLoadBalancerListenerConnectionLimit(Integer neutronLoadBalancerListenerConnectionLimit) {
+ this.neutronLoadBalancerListenerConnectionLimit = neutronLoadBalancerListenerConnectionLimit;
+ }
+
+ public List<Neutron_ID> getNeutronLoadBalancerListenerLoadBalancerIDs() {
+ return neutronLoadBalancerListenerLoadBalancerIDs;
+ }
+
+ public void setNeutronLoadBalancerListenerLoadBalancerIDs(List<Neutron_ID> neutronLoadBalancerListenerLoadBalancerIDs) {
+ this.neutronLoadBalancerListenerLoadBalancerIDs = neutronLoadBalancerListenerLoadBalancerIDs;
+ }
+
+ public NeutronLoadBalancerListener extractFields(List<String> fields) {
+ NeutronLoadBalancerListener ans = new NeutronLoadBalancerListener();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if(s.equals("default_pool_id")) {
+ ans.setNeutronLoadBalancerListenerDefaultPoolID(this.getNeutronLoadBalancerListenerDefaultPoolID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setLoadBalancerListenerTenantID(this.getLoadBalancerListenerTenantID());
+ }
+ if (s.equals("name")) {
+ ans.setLoadBalancerListenerName(this.getLoadBalancerListenerName());
+ }
+ if(s.equals("description")) {
+ ans.setLoadBalancerListenerDescription(this.getLoadBalancerListenerDescription());
+ }
+ if (s.equals("protocol")) {
+ ans.setNeutronLoadBalancerListenerProtocol(this.getNeutronLoadBalancerListenerProtocol());
+ }
+ if (s.equals("protocol_port")) {
+ ans.setNeutronLoadBalancerListenerProtocolPort(this.getNeutronLoadBalancerListenerProtocolPort());
+ }
+ if (s.equals("admin_state_up")) {
+ ans.setLoadBalancerListenerAdminStateIsUp(loadBalancerListenerAdminStateIsUp);
+ }
+ }
+ return ans;
+ }
+
+ @Override public String toString() {
+ return "NeutronLoadBalancerListener{" +
+ "loadBalancerListenerID='" + loadBalancerListenerID + '\'' +
+ ", neutronLoadBalancerListenerDefaultPoolID='" + neutronLoadBalancerListenerDefaultPoolID + '\'' +
+ ", neutronLoadBalancerListenerConnectionLimit='" + neutronLoadBalancerListenerConnectionLimit + '\'' +
+ ", loadBalancerListenerTenantID='" + loadBalancerListenerTenantID + '\'' +
+ ", loadBalancerListenerName='" + loadBalancerListenerName + '\'' +
+ ", loadBalancerListenerDescription='" + loadBalancerListenerDescription + '\'' +
+ ", loadBalancerListenerAdminStateIsUp=" + loadBalancerListenerAdminStateIsUp +
+ ", neutronLoadBalancerListenerProtocol='" + neutronLoadBalancerListenerProtocol + '\'' +
+ ", neutronLoadBalancerListenerProtocolPort='" + neutronLoadBalancerListenerProtocolPort + '\'' +
+ '}';
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of the fields:
+ * Implemented fields are as follows:
+ *
+ * id uuid-str
+ * tenant_id uuid-str
+ * name String
+ * description String
+ * protocol String
+ * lb_algorithm String
+ * healthmonitor_id String
+ * admin_state_up Bool
+ * status String
+ * members List <NeutronLoadBalancerPoolMember>
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerPool implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String loadBalancerPoolID;
+
+ @XmlElement (name = "tenant_id")
+ String loadBalancerPoolTenantID;
+
+ @XmlElement (name = "name")
+ String loadBalancerPoolName;
+
+ @XmlElement (name = "description")
+ String loadBalancerPoolDescription;
+
+ @XmlElement (name = "protocol")
+ String loadBalancerPoolProtocol;
+
+ @XmlElement (name = "lb_algorithm")
+ String loadBalancerPoolLbAlgorithm;
+
+ @XmlElement (name = "healthmonitor_id")
+ String neutronLoadBalancerPoolHealthMonitorID;
+
+ @XmlElement (defaultValue = "true", name = "admin_state_up")
+ Boolean loadBalancerPoolAdminStateIsUp;
+
+ @XmlElement(name = "listeners")
+ List<Neutron_ID> loadBalancerPoolListeners;
+
+ @XmlElement(name = "session_persistence")
+ NeutronLoadBalancer_SessionPersistence loadBalancerPoolSessionPersistence;
+
+ @XmlElement(name = "members")
+ List<NeutronLoadBalancerPoolMember> loadBalancerPoolMembers;
+
+ public NeutronLoadBalancerPool() {
+ }
+
+ public String getID() {
+ return loadBalancerPoolID;
+ }
+
+ public void setID(String id) {
+ loadBalancerPoolID = id;
+ }
+
+ // @deprecated use getID()
+ public String getLoadBalancerPoolID() {
+ return loadBalancerPoolID;
+ }
+
+ // @deprecated use setID()
+ public void setLoadBalancerPoolID(String loadBalancerPoolID) {
+ this.loadBalancerPoolID = loadBalancerPoolID;
+ }
+
+ public String getLoadBalancerPoolTenantID() {
+ return loadBalancerPoolTenantID;
+ }
+
+ public void setLoadBalancerPoolTenantID(String loadBalancerPoolTenantID) {
+ this.loadBalancerPoolTenantID = loadBalancerPoolTenantID;
+ }
+
+ public String getLoadBalancerPoolName() {
+ return loadBalancerPoolName;
+ }
+
+ public void setLoadBalancerPoolName(String loadBalancerPoolName) {
+ this.loadBalancerPoolName = loadBalancerPoolName;
+ }
+
+ public String getLoadBalancerPoolDescription() {
+ return loadBalancerPoolDescription;
+ }
+
+ public void setLoadBalancerPoolDescription(String loadBalancerPoolDescription) {
+ this.loadBalancerPoolDescription = loadBalancerPoolDescription;
+ }
+
+ public String getLoadBalancerPoolProtocol() {
+ return loadBalancerPoolProtocol;
+ }
+
+ public void setLoadBalancerPoolProtocol(String loadBalancerPoolProtocol) {
+ this.loadBalancerPoolProtocol = loadBalancerPoolProtocol;
+ }
+
+ public String getLoadBalancerPoolLbAlgorithm() {
+ return loadBalancerPoolLbAlgorithm;
+ }
+
+ public void setLoadBalancerPoolLbAlgorithm(String loadBalancerPoolLbAlgorithm) {
+ this.loadBalancerPoolLbAlgorithm = loadBalancerPoolLbAlgorithm;
+ }
+
+ public String getNeutronLoadBalancerPoolHealthMonitorID() {
+ return neutronLoadBalancerPoolHealthMonitorID;
+ }
+
+ public void setNeutronLoadBalancerPoolHealthMonitorID(String neutronLoadBalancerPoolHealthMonitorID) {
+ this.neutronLoadBalancerPoolHealthMonitorID = neutronLoadBalancerPoolHealthMonitorID;
+ }
+
+ public Boolean getLoadBalancerPoolAdminIsStateIsUp() {
+ return loadBalancerPoolAdminStateIsUp;
+ }
+
+ public void setLoadBalancerPoolAdminStateIsUp(Boolean loadBalancerPoolAdminStateIsUp) {
+ this.loadBalancerPoolAdminStateIsUp = loadBalancerPoolAdminStateIsUp;
+ }
+
+ public NeutronLoadBalancer_SessionPersistence getLoadBalancerPoolSessionPersistence() {
+ return loadBalancerPoolSessionPersistence;
+ }
+
+ public void setLoadBalancerSessionPersistence(NeutronLoadBalancer_SessionPersistence loadBalancerPoolSessionPersistence) {
+ this.loadBalancerPoolSessionPersistence = loadBalancerPoolSessionPersistence;
+ }
+
+ public List<Neutron_ID> getLoadBalancerPoolListeners() {
+ return loadBalancerPoolListeners;
+ }
+
+ public void setLoadBalancerPoolListeners(List<Neutron_ID> loadBalancerPoolListeners) {
+ this.loadBalancerPoolListeners = loadBalancerPoolListeners;
+ }
+
+ public List<NeutronLoadBalancerPoolMember> getLoadBalancerPoolMembers() {
+ /*
+ * Update the pool_id of the member to that this.loadBalancerPoolID
+ */
+ if (loadBalancerPoolMembers != null) {
+ for (NeutronLoadBalancerPoolMember member: loadBalancerPoolMembers) {
+ member.setPoolID(loadBalancerPoolID);
+ }
+ return loadBalancerPoolMembers;
+ }
+ return loadBalancerPoolMembers;
+ }
+
+ public void setLoadBalancerPoolMembers(List<NeutronLoadBalancerPoolMember> loadBalancerPoolMembers) {
+ this.loadBalancerPoolMembers = loadBalancerPoolMembers;
+ }
+
+ public void addLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember) {
+ this.loadBalancerPoolMembers.add(loadBalancerPoolMember);
+ }
+
+ public void removeLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember) {
+ this.loadBalancerPoolMembers.remove(loadBalancerPoolMember);
+ }
+
+ public NeutronLoadBalancerPool extractFields(List<String> fields) {
+ NeutronLoadBalancerPool ans = new NeutronLoadBalancerPool();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setLoadBalancerPoolTenantID(this.getLoadBalancerPoolTenantID());
+ }
+ if (s.equals("name")) {
+ ans.setLoadBalancerPoolName(this.getLoadBalancerPoolName());
+ }
+ if(s.equals("description")) {
+ ans.setLoadBalancerPoolDescription(this.getLoadBalancerPoolDescription());
+ }
+ if(s.equals("protocol")) {
+ ans.setLoadBalancerPoolProtocol(this.getLoadBalancerPoolProtocol());
+ }
+ if (s.equals("lb_algorithm")) {
+ ans.setLoadBalancerPoolLbAlgorithm(this.getLoadBalancerPoolLbAlgorithm());
+ }
+ if (s.equals("healthmonitor_id")) {
+ ans.setNeutronLoadBalancerPoolHealthMonitorID(this.getNeutronLoadBalancerPoolHealthMonitorID());
+ }
+ if (s.equals("admin_state_up")) {
+ ans.setLoadBalancerPoolAdminStateIsUp(loadBalancerPoolAdminStateIsUp);
+ }
+ if (s.equals("members")) {
+ ans.setLoadBalancerPoolMembers(getLoadBalancerPoolMembers());
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronLoadBalancerPool{" +
+ "id='" + loadBalancerPoolID + '\'' +
+ ", tenantID='" + loadBalancerPoolTenantID + '\'' +
+ ", name='" + loadBalancerPoolName + '\'' +
+ ", description='" + loadBalancerPoolDescription + '\'' +
+ ", protocol=" + loadBalancerPoolProtocol +'\''+
+ ", lbAlgorithm='" + loadBalancerPoolLbAlgorithm + '\'' +
+ ", healthmonitorID=" + neutronLoadBalancerPoolHealthMonitorID +
+ ", adminStateUp=" + loadBalancerPoolAdminStateIsUp +
+// todo: add loadBalancerPoolMembers as joined string
+ '}';
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerPoolMember
+ implements Serializable, INeutronObject {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * TODO: Plumb into LBaaS Pool. Members are nested underneath Pool CRUD.
+ */
+ @XmlElement (name = "id")
+ String poolMemberID;
+
+ @XmlElement (name = "tenant_id")
+ String poolMemberTenantID;
+
+ @XmlElement (name = "address")
+ String poolMemberAddress;
+
+ @XmlElement (name = "protocol_port")
+ Integer poolMemberProtoPort;
+
+ @XmlElement (name = "admin_state_up")
+ Boolean poolMemberAdminStateIsUp;
+
+ @XmlElement (name = "weight")
+ Integer poolMemberWeight;
+
+ @XmlElement (name = "subnet_id")
+ String poolMemberSubnetID;
+
+ String poolID;
+
+ public NeutronLoadBalancerPoolMember() {
+ }
+
+ @XmlTransient
+ public String getPoolID() {
+ return poolID;
+ }
+
+ public void setPoolID(String poolID) {
+ this.poolID = poolID;
+ }
+
+ public String getID() {
+ return poolMemberID;
+ }
+
+ public void setID(String id) {
+ poolMemberID = id;
+ }
+
+ // @deprecated use getID()
+ public String getPoolMemberID() {
+ return poolMemberID;
+ }
+
+ // @deprecated use setID()
+ public void setPoolMemberID(String poolMemberID) {
+ this.poolMemberID = poolMemberID;
+ }
+
+ public String getPoolMemberTenantID() {
+ return poolMemberTenantID;
+ }
+
+ public void setPoolMemberTenantID(String poolMemberTenantID) {
+ this.poolMemberTenantID = poolMemberTenantID;
+ }
+
+ public String getPoolMemberAddress() {
+ return poolMemberAddress;
+ }
+
+ public void setPoolMemberAddress(String poolMemberAddress) {
+ this.poolMemberAddress = poolMemberAddress;
+ }
+
+ public Integer getPoolMemberProtoPort() {
+ return poolMemberProtoPort;
+ }
+
+ public void setPoolMemberProtoPort(Integer poolMemberProtoPort) {
+ this.poolMemberProtoPort = poolMemberProtoPort;
+ }
+
+ public Boolean getPoolMemberAdminStateIsUp() {
+ return poolMemberAdminStateIsUp;
+ }
+
+ public void setPoolMemberAdminStateIsUp(Boolean poolMemberAdminStateIsUp) {
+ this.poolMemberAdminStateIsUp = poolMemberAdminStateIsUp;
+ }
+
+ public Integer getPoolMemberWeight() {
+ return poolMemberWeight;
+ }
+
+ public void setPoolMemberWeight(Integer poolMemberWeight) {
+ this.poolMemberWeight = poolMemberWeight;
+ }
+
+ public String getPoolMemberSubnetID() {
+ return poolMemberSubnetID;
+ }
+
+ public void setPoolMemberSubnetID(String poolMemberSubnetID) {
+ this.poolMemberSubnetID = poolMemberSubnetID;
+ }
+
+ public NeutronLoadBalancerPoolMember extractFields(List<String> fields) {
+ NeutronLoadBalancerPoolMember ans = new NeutronLoadBalancerPoolMember();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if (s.equals("pool_id")) {
+ ans.setPoolID(this.getPoolID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setPoolMemberTenantID(this.getPoolMemberTenantID());
+ }
+ if (s.equals("address")) {
+ ans.setPoolMemberAddress(this.getPoolMemberAddress());
+ }
+ if(s.equals("protocol_port")) {
+ ans.setPoolMemberProtoPort(this.getPoolMemberProtoPort());
+ }
+ if (s.equals("admin_state_up")) {
+ ans.setPoolMemberAdminStateIsUp(poolMemberAdminStateIsUp);
+ }
+ if(s.equals("weight")) {
+ ans.setPoolMemberWeight(this.getPoolMemberWeight());
+ }
+ if(s.equals("subnet_id")) {
+ ans.setPoolMemberSubnetID(this.getPoolMemberSubnetID());
+ }
+ }
+ return ans;
+ }
+ @Override public String toString() {
+ return "NeutronLoadBalancerPoolMember{" +
+ "poolMemberID='" + poolMemberID + '\'' +
+ ", poolID='" + poolID + '\'' +
+ ", poolMemberTenantID='" + poolMemberTenantID + '\'' +
+ ", poolMemberAddress='" + poolMemberAddress + '\'' +
+ ", poolMemberProtoPort=" + poolMemberProtoPort +
+ ", poolMemberAdminStateIsUp=" + poolMemberAdminStateIsUp +
+ ", poolMemberWeight=" + poolMemberWeight +
+ ", poolMemberSubnetID='" + poolMemberSubnetID + '\'' +
+ '}';
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronLoadBalancer_SessionPersistence implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement(name = "cookie_name")
+ String cookieName;
+
+ @XmlElement(name = "type")
+ String type;
+
+ public NeutronLoadBalancer_SessionPersistence() {
+ }
+
+ public NeutronLoadBalancer_SessionPersistence(String cookieName, String type) {
+ this.cookieName = cookieName;
+ this.type = type;
+ }
+
+ public String getCookieName() {
+ return cookieName;
+ }
+
+ public void setCookieName(String cookieName) {
+ this.cookieName = cookieName;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "network")
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronNetwork implements Serializable, INeutronObject {
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement (name = "id")
+ String networkUUID;
+
+ @XmlElement (name = "name")
+ String networkName;
+
+ @XmlElement (defaultValue = "true", name = "admin_state_up")
+ Boolean adminStateUp;
+
+ @XmlElement (defaultValue = "false", name = "shared")
+ Boolean shared;
+
+ @XmlElement (name = "tenant_id")
+ String tenantID;
+
+ // @XmlElement (defaultValue = "false", name = "router:external")
+ @XmlElement (defaultValue="false", namespace="router", name="external")
+ Boolean routerExternal;
+
+ // @XmlElement (defaultValue = "flat", name = "provider:network_type")
+ @XmlElement (namespace="provider", name="network_type")
+ String providerNetworkType;
+
+ // @XmlElement (name = "provider:physical_network")
+ @XmlElement (namespace="provider", name="physical_network")
+ String providerPhysicalNetwork;
+
+ // @XmlElement (name = "provider:segmentation_id")
+ @XmlElement (namespace="provider", name="segmentation_id")
+ String providerSegmentationID;
+
+ @XmlElement (name = "status")
+ String status;
+
+ @XmlElement (name = "subnets")
+ List<String> subnets;
+
+ @XmlElement (name="segments")
+ List<NeutronNetwork_Segment> segments;
+
+ @XmlElement (name="vlan_transparent")
+ Boolean vlanTransparent;
+
+ @XmlElement (name="mtu")
+ Integer mtu;
+
+ /* This attribute lists the ports associated with an instance
+ * which is needed for determining if that instance can be deleted
+ */
+
+ public NeutronNetwork() {
+ }
+
+ public void initDefaults() {
+ subnets = new ArrayList<String>();
+ if (status == null) {
+ status = "ACTIVE";
+ }
+ if (adminStateUp == null) {
+ adminStateUp = true;
+ }
+ if (shared == null) {
+ shared = false;
+ }
+ if (routerExternal == null) {
+ routerExternal = false;
+ }
+ if (providerNetworkType == null) {
+ providerNetworkType = "flat";
+ }
+ }
+
+ public String getID() { return networkUUID; }
+
+ public void setID(String id) { this.networkUUID = id; }
+
+ public String getNetworkUUID() {
+ return networkUUID;
+ }
+
+ public void setNetworkUUID(String networkUUID) {
+ this.networkUUID = networkUUID;
+ }
+
+ public String getNetworkName() {
+ return networkName;
+ }
+
+ public void setNetworkName(String networkName) {
+ this.networkName = networkName;
+ }
+
+ public boolean isAdminStateUp() {
+ return adminStateUp;
+ }
+
+ public Boolean getAdminStateUp() { return adminStateUp; }
+
+ public void setAdminStateUp(boolean newValue) {
+ adminStateUp = newValue;
+ }
+
+ public boolean isShared() { return shared; }
+
+ public Boolean getShared() { return shared; }
+
+ public void setShared(boolean newValue) {
+ shared = newValue;
+ }
+
+ public String getTenantID() {
+ return tenantID;
+ }
+
+ public void setTenantID(String tenantID) {
+ this.tenantID = tenantID;
+ }
+
+ public boolean isRouterExternal() { return routerExternal; }
+
+ public Boolean getRouterExternal() { return routerExternal; }
+
+ public void setRouterExternal(boolean newValue) {
+ routerExternal = newValue;
+ }
+
+ public String getProviderNetworkType() {
+ return providerNetworkType;
+ }
+
+ public void setProviderNetworkType(String providerNetworkType) {
+ this.providerNetworkType = providerNetworkType;
+ }
+
+ public String getProviderPhysicalNetwork() {
+ return providerPhysicalNetwork;
+ }
+
+ public void setProviderPhysicalNetwork(String providerPhysicalNetwork) {
+ this.providerPhysicalNetwork = providerPhysicalNetwork;
+ }
+
+ public String getProviderSegmentationID() {
+ return providerSegmentationID;
+ }
+
+ public void setProviderSegmentationID(String providerSegmentationID) {
+ this.providerSegmentationID = providerSegmentationID;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public List<String> getSubnets() {
+ return subnets;
+ }
+
+ public void setSubnets(List<String> subnets) {
+ this.subnets = subnets;
+ }
+
+ public void addSubnet(String uuid) {
+ subnets.add(uuid);
+ }
+
+ public void removeSubnet(String uuid) {
+ subnets.remove(uuid);
+ }
+
+ public void setSegments(List<NeutronNetwork_Segment> segments) {
+ this.segments = segments;
+ }
+
+ public List<NeutronNetwork_Segment> getSegments() {
+ return segments;
+ }
+
+ public Boolean getVlanTransparent() {
+ return vlanTransparent;
+ }
+
+ public void setVlanTransparent(Boolean input) {
+ this.vlanTransparent = input;
+ }
+
+ public Integer getMtu() {
+ return mtu;
+ }
+
+ public void setMtu(Integer input) {
+ mtu = input;
+ }
+
+ /**
+ * This method copies selected fields from the object and returns them
+ * as a new object, suitable for marshaling.
+ *
+ * @param fields
+ * List of attributes to be extracted
+ * @return an OpenStackNetworks object with only the selected fields
+ * populated
+ */
+
+ public NeutronNetwork extractFields(List<String> fields) {
+ NeutronNetwork ans = new NeutronNetwork();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setNetworkUUID(this.getNetworkUUID());
+ }
+ if (s.equals("name")) {
+ ans.setNetworkName(this.getNetworkName());
+ }
+ if (s.equals("admin_state_up")) {
+ ans.setAdminStateUp(adminStateUp);
+ }
+ if (s.equals("status")) {
+ ans.setStatus(this.getStatus());
+ }
+ if (s.equals("subnets")) {
+ List<String> subnetList = new ArrayList<String>();
+ subnetList.addAll(this.getSubnets());
+ ans.setSubnets(subnetList);
+ }
+ if (s.equals("shared")) {
+ ans.setShared(shared);
+ }
+ if (s.equals("tenant_id")) {
+ ans.setTenantID(this.getTenantID());
+ }
+ if (s.equals("external")) {
+ ans.setRouterExternal(this.getRouterExternal());
+ }
+ if (s.equals("segmentation_id")) {
+ ans.setProviderSegmentationID(this.getProviderSegmentationID());
+ }
+ if (s.equals("physical_network")) {
+ ans.setProviderPhysicalNetwork(this.getProviderPhysicalNetwork());
+ }
+ if (s.equals("network_type")) {
+ ans.setProviderNetworkType(this.getProviderNetworkType());
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronNetwork [networkUUID=" + networkUUID + ", networkName=" + networkName + ", adminStateUp="
+ + adminStateUp + ", shared=" + shared + ", tenantID=" + tenantID + ", routerExternal=" + routerExternal
+ + ", providerNetworkType=" + providerNetworkType + ", providerPhysicalNetwork="
+ + providerPhysicalNetwork + ", providerSegmentationID=" + providerSegmentationID + ", status=" + status
+ + ", subnets=" + subnets + ", segments = " + segments + "]";
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "network")
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronNetwork_Segment implements Serializable {
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ private static final long serialVersionUID = 1L;
+
+ // @XmlElement (defaultValue="flat", name="provider:network_type")
+ @XmlElement (defaultValue="flat", namespace="provider", name="network_type")
+ String providerNetworkType;
+
+ // @XmlElement (name="provider:physical_network")
+ @XmlElement (namespace="provider", name="physical_network")
+ String providerPhysicalNetwork;
+
+ // @XmlElement (name="provider:segmentation_id")
+ @XmlElement (namespace="provider", name="segmentation_id")
+ String providerSegmentationID;
+
+ public NeutronNetwork_Segment() {
+ }
+
+ public String getProviderNetworkType() {
+ return providerNetworkType;
+ }
+
+ public void setProviderNetworkType(String providerNetworkType) {
+ this.providerNetworkType = providerNetworkType;
+ }
+
+ public String getProviderPhysicalNetwork() {
+ return providerPhysicalNetwork;
+ }
+
+ public void setProviderPhysicalNetwork(String providerPhysicalNetwork) {
+ this.providerPhysicalNetwork = providerPhysicalNetwork;
+ }
+
+ public String getProviderSegmentationID() {
+ return providerSegmentationID;
+ }
+
+ public void setProviderSegmentationID(String providerSegmentationID) {
+ this.providerSegmentationID = providerSegmentationID;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronNetwork_Segment [ " +
+ ", providerNetworkType=" + providerNetworkType +
+ ", providerPhysicalNetwork=" + providerPhysicalNetwork +
+ ", providerSegmentationID=" + providerSegmentationID + "]";
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronPort implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement (name = "id")
+ String portUUID;
+
+ @XmlElement (name = "network_id")
+ String networkUUID;
+
+ @XmlElement (name = "name")
+ String name;
+
+ @XmlElement (defaultValue = "true", name = "admin_state_up")
+ Boolean adminStateUp;
+
+ @XmlElement (name = "status")
+ String status;
+
+ @XmlElement (name = "mac_address")
+ String macAddress;
+
+ @XmlElement (name = "fixed_ips")
+ List<Neutron_IPs> fixedIPs;
+
+ @XmlElement (name = "device_id")
+ String deviceID;
+
+ @XmlElement (name = "device_owner")
+ String deviceOwner;
+
+ @XmlElement (name = "tenant_id")
+ String tenantID;
+
+ @XmlElement (name = "security_groups")
+ List<NeutronSecurityGroup> securityGroups;
+
+ @XmlElement (name = "allowed_address_pairs")
+ List<NeutronPort_AllowedAddressPairs> allowedAddressPairs;
+
+ //@XmlElement (name = "binding:host_id")
+ @XmlElement (namespace = "binding", name = "host_id")
+ String bindinghostID;
+
+ //@XmlElement (name = "binding:vnic_type")
+ @XmlElement (namespace = "binding", name = "vnic_type")
+ String bindingvnicType;
+
+ //@XmlElement (name = "binding:vif_type")
+ @XmlElement (namespace = "binding", name = "vif_type")
+ String bindingvifType;
+
+ //@XmlElement (name = "binding:vif_details")
+ @XmlElement (namespace = "binding", name = "vif_details")
+ List<NeutronPort_VIFDetail> vifDetails;
+
+ @XmlElement (name = "extra_dhcp_opts")
+ List<NeutronPort_ExtraDHCPOption> extraDHCPOptions;
+
+ NeutronPort originalPort;
+
+ public NeutronPort() {
+ }
+
+ public String getID() { return portUUID; }
+
+ public void setID(String id) { this.portUUID = id; }
+
+ public String getPortUUID() {
+ return portUUID;
+ }
+
+ public void setPortUUID(String portUUID) {
+ this.portUUID = portUUID;
+ }
+
+ public String getNetworkUUID() {
+ return networkUUID;
+ }
+
+ public void setNetworkUUID(String networkUUID) {
+ this.networkUUID = networkUUID;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isAdminStateUp() {
+ if (adminStateUp == null) {
+ return true;
+ }
+ return adminStateUp;
+ }
+
+ public Boolean getAdminStateUp() { return adminStateUp; }
+
+ public void setAdminStateUp(Boolean newValue) {
+ adminStateUp = newValue;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getMacAddress() {
+ return macAddress;
+ }
+
+ public void setMacAddress(String macAddress) {
+ this.macAddress = macAddress;
+ }
+
+ public List<Neutron_IPs> getFixedIPs() {
+ return fixedIPs;
+ }
+
+ public void setFixedIPs(List<Neutron_IPs> fixedIPs) {
+ this.fixedIPs = fixedIPs;
+ }
+
+ public String getDeviceID() {
+ return deviceID;
+ }
+
+ public void setDeviceID(String deviceID) {
+ this.deviceID = deviceID;
+ }
+
+ public String getDeviceOwner() {
+ return deviceOwner;
+ }
+
+ public void setDeviceOwner(String deviceOwner) {
+ this.deviceOwner = deviceOwner;
+ }
+
+ public String getTenantID() {
+ return tenantID;
+ }
+
+ public void setTenantID(String tenantID) {
+ this.tenantID = tenantID;
+ }
+
+ public List<NeutronSecurityGroup> getSecurityGroups() {
+ return securityGroups;
+ }
+
+ public void setSecurityGroups(List<NeutronSecurityGroup> securityGroups) {
+ this.securityGroups = securityGroups;
+ }
+
+ public List<NeutronPort_AllowedAddressPairs> getAllowedAddressPairs() {
+ return allowedAddressPairs;
+ }
+
+ public void setAllowedAddressPairs(List<NeutronPort_AllowedAddressPairs> allowedAddressPairs) {
+ this.allowedAddressPairs = allowedAddressPairs;
+ }
+
+ public List<NeutronPort_ExtraDHCPOption> getExtraDHCPOptions() {
+ return extraDHCPOptions;
+ }
+
+ public void setExtraDHCPOptions(List<NeutronPort_ExtraDHCPOption> extraDHCPOptions) {
+ this.extraDHCPOptions = extraDHCPOptions;
+ }
+
+ public List<NeutronPort_VIFDetail> getVIFDetail() {
+ return vifDetails;
+ }
+
+ public void setVIFDetail(List<NeutronPort_VIFDetail> vifDetails) {
+ this.vifDetails = vifDetails;
+ }
+
+ public String getBindinghostID() {
+ return bindinghostID;
+ }
+
+ public void setBindinghostID(String bindinghostID) {
+ this.bindinghostID = bindinghostID;
+ }
+
+ public String getBindingvnicType() {
+ return bindingvnicType;
+ }
+
+ public void setBindingvnicType(String bindingvnicType) {
+ this.bindingvnicType = bindingvnicType;
+ }
+
+ public String getBindingvifType() {
+ return bindingvifType;
+ }
+
+ public void setBindingvifType(String bindingvifType) {
+ this.bindingvifType = bindingvifType;
+ }
+
+ public NeutronPort getOriginalPort() {
+ return originalPort;
+ }
+
+
+ public void setOriginalPort(NeutronPort originalPort) {
+ this.originalPort = originalPort;
+ }
+
+ /**
+ * This method copies selected fields from the object and returns them
+ * as a new object, suitable for marshaling.
+ *
+ * @param fields
+ * List of attributes to be extracted
+ * @return an OpenStackPorts object with only the selected fields
+ * populated
+ */
+
+ public NeutronPort extractFields(List<String> fields) {
+ NeutronPort ans = new NeutronPort();
+ for (String field: fields) {
+ if ("id".equals(field)) {
+ ans.setPortUUID(this.getPortUUID());
+ }
+ if ("network_id".equals(field)) {
+ ans.setNetworkUUID(this.getNetworkUUID());
+ }
+ if ("name".equals(field)) {
+ ans.setName(this.getName());
+ }
+ if ("admin_state_up".equals(field)) {
+ ans.setAdminStateUp(this.getAdminStateUp());
+ }
+ if ("status".equals(field)) {
+ ans.setStatus(this.getStatus());
+ }
+ if ("mac_address".equals(field)) {
+ ans.setMacAddress(this.getMacAddress());
+ }
+ if ("fixed_ips".equals(field)) {
+ ans.setFixedIPs(new ArrayList<Neutron_IPs>(this.getFixedIPs()));
+ }
+ if ("device_id".equals(field)) {
+ ans.setDeviceID(this.getDeviceID());
+ }
+ if ("device_owner".equals(field)) {
+ ans.setDeviceOwner(this.getDeviceOwner());
+ }
+ if ("tenant_id".equals(field)) {
+ ans.setTenantID(this.getTenantID());
+ }
+ if ("security_groups".equals(field)) {
+ ans.setSecurityGroups(new ArrayList<NeutronSecurityGroup>(this.getSecurityGroups()));
+ }
+ }
+ return ans;
+ }
+
+ public void initDefaults() {
+ adminStateUp = true;
+ if (status == null) {
+ status = "ACTIVE";
+ }
+ if (fixedIPs == null) {
+ fixedIPs = new ArrayList<Neutron_IPs>();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronPort [portUUID=" + portUUID + ", networkUUID=" + networkUUID + ", name=" + name
+ + ", adminStateUp=" + adminStateUp + ", status=" + status + ", macAddress=" + macAddress
+ + ", fixedIPs=" + fixedIPs + ", deviceID=" + deviceID + ", deviceOwner=" + deviceOwner + ", tenantID="
+ + tenantID + ", securityGroups=" + securityGroups
+ + ", bindinghostID=" + bindinghostID + ", bindingvnicType=" + bindingvnicType
+ + ", bindingvnicType=" + bindingvnicType + "]";
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPort_AllowedAddressPairs implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement (name = "port_id")
+ String portID;
+
+ @XmlElement (name = "mac_address")
+ String macAddress;
+
+ @XmlElement (name = "ip_address")
+ String ipAddress;
+
+ public NeutronPort_AllowedAddressPairs() {
+ }
+
+ public NeutronPort_AllowedAddressPairs(String portID, String macAddress, String ipAddress) {
+ this.portID = portID;
+ this.macAddress = macAddress;
+ this.ipAddress = ipAddress;
+ }
+
+ public String getPortID() { return(portID); }
+
+ public void setPortID(String portID) { this.portID = portID; }
+
+ public String getMacAddress() { return(macAddress); }
+
+ public void setMacAddress(String macAddress) { this.macAddress = macAddress; }
+
+ public String getIpAddress() { return(ipAddress); }
+
+ public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPort_ExtraDHCPOption implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement (name = "opt_value")
+ String value;
+
+ @XmlElement (name = "opt_name")
+ String name;
+
+ public NeutronPort_ExtraDHCPOption() {
+ }
+
+ public NeutronPort_ExtraDHCPOption(String value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ public String getValue() { return(value); }
+
+ public void setValue(String value) { this.value = value; }
+
+ public String getName() { return(name); }
+
+ public void setName(String name) { this.name = name; }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPort_VIFDetail implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement (name = "port_filter")
+ Boolean portFilter;
+
+ @XmlElement (name = "ovs_hybrid_plug")
+ Boolean ovsHybridPlug;
+
+ public NeutronPort_VIFDetail() {
+ }
+
+ public NeutronPort_VIFDetail(Boolean portFilter, Boolean ovsHybridPlug) {
+ this.portFilter = portFilter;
+ this.ovsHybridPlug = ovsHybridPlug;
+ }
+
+ public Boolean getPortFilter() { return(portFilter); }
+
+ public void setPortFilter(Boolean portFilter) { this.portFilter = portFilter; }
+
+ public Boolean getOvsHybridPlug() { return(ovsHybridPlug); }
+
+ public void setOvsHybridPlug(Boolean ovsHybridPlug) { this.ovsHybridPlug = ovsHybridPlug; }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronRouter implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+ @XmlElement (name = "id")
+ String routerUUID;
+
+ @XmlElement (name = "name")
+ String name;
+
+ @XmlElement (defaultValue = "true", name = "admin_state_up")
+ Boolean adminStateUp;
+
+ @XmlElement (name = "status")
+ String status;
+
+ @XmlElement (name = "tenant_id")
+ String tenantID;
+
+ @XmlElement (name = "external_gateway_info", nillable = true)
+ NeutronRouter_NetworkReference externalGatewayInfo;
+
+ @XmlElement (name = "distributed")
+ Boolean distributed;
+
+ @XmlElement (name = "gw_port_id", nillable = true)
+ String gatewayPortId;
+
+ @XmlElement (name = "routes")
+ List<String> routes;
+
+ /* Holds a map of OpenStackRouterInterfaces by subnet UUID
+ * used for internal mapping to DOVE
+ */
+ Map<String, NeutronRouter_Interface> interfaces;
+
+ public NeutronRouter() {
+ interfaces = new HashMap<String, NeutronRouter_Interface>();
+ }
+
+ public String getID() { return routerUUID; }
+
+ public void setID(String id) { this.routerUUID = id; }
+
+ public String getRouterUUID() {
+ return routerUUID;
+ }
+
+ public void setRouterUUID(String routerUUID) {
+ this.routerUUID = routerUUID;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isAdminStateUp() {
+ if (adminStateUp == null) {
+ return true;
+ }
+ return adminStateUp;
+ }
+
+ public Boolean getAdminStateUp() { return adminStateUp; }
+
+ public void setAdminStateUp(Boolean newValue) {
+ adminStateUp = newValue;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getTenantID() {
+ return tenantID;
+ }
+
+ public void setTenantID(String tenantID) {
+ this.tenantID = tenantID;
+ }
+
+ public NeutronRouter_NetworkReference getExternalGatewayInfo() {
+ return externalGatewayInfo;
+ }
+
+ public void setExternalGatewayInfo(NeutronRouter_NetworkReference externalGatewayInfo) {
+ this.externalGatewayInfo = externalGatewayInfo;
+ }
+
+ public Boolean getDistributed() {
+ return distributed;
+ }
+
+ public void setDistributed(Boolean distributed) {
+ this.distributed = distributed;
+ }
+
+ public String getGatewayPortId() {
+ return gatewayPortId;
+ }
+
+ public void setGatewayPortId(String gatewayPortId) {
+ this.gatewayPortId = gatewayPortId;
+ }
+
+ public List<String> getRoutes() {
+ return routes;
+ }
+
+ public void setRoutes(List<String> routes) {
+ this.routes = routes;
+ }
+
+ /**
+ * This method copies selected fields from the object and returns them
+ * as a new object, suitable for marshaling.
+ *
+ * @param fields
+ * List of attributes to be extracted
+ * @return an OpenStackRouters object with only the selected fields
+ * populated
+ */
+ public NeutronRouter extractFields(List<String> fields) {
+ NeutronRouter ans = new NeutronRouter();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setRouterUUID(this.getRouterUUID());
+ }
+ if (s.equals("name")) {
+ ans.setName(this.getName());
+ }
+ if (s.equals("admin_state_up")) {
+ ans.setAdminStateUp(this.getAdminStateUp());
+ }
+ if (s.equals("status")) {
+ ans.setStatus(this.getStatus());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setTenantID(this.getTenantID());
+ }
+ if (s.equals("external_gateway_info")) {
+ ans.setExternalGatewayInfo(this.getExternalGatewayInfo());
+ }
+ if (s.equals("distributed")) {
+ ans.setDistributed(this.getDistributed());
+ }
+ if (s.equals("gw_port_id")) {
+ ans.setGatewayPortId(this.getGatewayPortId());
+ }
+ if (s.equals("routes")){
+ ans.setRoutes(this.getRoutes());
+ }
+ }
+ return ans;
+ }
+
+ public void setInterfaces(Map<String, NeutronRouter_Interface> input) {
+ interfaces = input;
+ }
+
+ public Map<String, NeutronRouter_Interface> getInterfaces() {
+ return interfaces;
+ }
+
+ public void addInterface(String s, NeutronRouter_Interface i) {
+ interfaces.put(s, i);
+ }
+
+ public void removeInterface(String s) {
+ interfaces.remove(s);
+ }
+
+ public void initDefaults() {
+ adminStateUp = true;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronRouter [" +
+ "id=" + routerUUID +
+ ", name=" + name +
+ ", adminStateUp=" + adminStateUp +
+ ", status=" + status +
+ ", tenantID=" + tenantID +
+ ", external_gateway_info=" + externalGatewayInfo +
+ ", distributed=" + distributed +
+ ", gw_port_id=" + gatewayPortId +
+ ", routes=" + routes +
+ ", interfaces=" + interfaces +
+ "]";
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronRouter_Interface implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement (name = "subnet_id")
+ String subnetUUID;
+
+ @XmlElement (name = "port_id")
+ String portUUID;
+
+ @XmlElement (name = "id")
+ String id;
+
+ @XmlElement (name = "tenant_id")
+ String tenantID;
+
+ public NeutronRouter_Interface() {
+ }
+
+ public NeutronRouter_Interface(String subnetUUID, String portUUID) {
+ this.subnetUUID = subnetUUID;
+ this.portUUID = portUUID;
+ }
+
+ public String getSubnetUUID() {
+ return subnetUUID;
+ }
+
+ public void setSubnetUUID(String subnetUUID) {
+ this.subnetUUID = subnetUUID;
+ }
+
+ public String getPortUUID() {
+ return portUUID;
+ }
+
+ public void setPortUUID(String portUUID) {
+ this.portUUID = portUUID;
+ }
+
+ public String getID() {
+ return id;
+ }
+
+ public void setID(String id) {
+ this.id = id;
+ }
+
+ public void setTenantID(String tenantID) {
+ this.tenantID = tenantID;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronRouterInterface [" +
+ "subnetUUID=" + subnetUUID +
+ ", portUUID=" + portUUID +
+ ", id=" + id +
+ ", tenantID=" + tenantID + "]";
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronRouter_NetworkReference implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement(name = "network_id")
+ String networkID;
+
+ @XmlElement(name = "enable_snat")
+ Boolean enableSNAT;
+
+ @XmlElement(name = "external_fixed_ips")
+ List<Neutron_IPs> externalFixedIPs;
+
+ public NeutronRouter_NetworkReference() {
+ }
+
+ public String getNetworkID() {
+ return networkID;
+ }
+
+ public void setNetworkID(String networkID) {
+ this.networkID = networkID;
+ }
+
+ public Boolean getEnableSNAT() {
+ return enableSNAT;
+ }
+
+ public void setEnableSNAT(Boolean enableSNAT) {
+ this.enableSNAT = enableSNAT;
+ }
+
+ public List<Neutron_IPs> getExternalFixedIPs() {
+ return externalFixedIPs;
+ }
+
+ public void setExternalFixedIPs(List<Neutron_IPs> externalFixedIPs) {
+ this.externalFixedIPs = externalFixedIPs;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronRouterNetworkReference [networkID=" + networkID +
+ " enableSNAT=" + enableSNAT +
+ " externalFixedIPs=" + externalFixedIPs + "]";
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * OpenStack Neutron v2.0 Security Group bindings.
+ * See OpenStack Network API v2.0 Reference for description of
+ * annotated attributes. The current fields are as follows:
+ * <p>
+ * id uuid-str unique ID for the security group.
+ * name String name of the security group.
+ * description String name of the security group.
+ * tenant_id uuid-str Owner of security rule..
+ * security_group_rules List<NeutronSecurityRule> nested RO in the sec group.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSecurityGroup implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String securityGroupUUID;
+
+ @XmlElement(name = "name")
+ String securityGroupName;
+
+ @XmlElement(name = "description")
+ String securityGroupDescription;
+
+ @XmlElement(name = "tenant_id")
+ String securityGroupTenantID;
+
+ @XmlElement(name = "security_group_rules")
+ List<NeutronSecurityRule> neutronSecurityRule;
+
+ public NeutronSecurityGroup() {
+ neutronSecurityRule = new ArrayList<NeutronSecurityRule>();
+
+ }
+
+ public String getID() {
+ return securityGroupUUID;
+ }
+
+ public void setID(String id) {
+ securityGroupUUID = id;
+ }
+
+ // @deprecated use getID()
+ public String getSecurityGroupUUID() {
+ return securityGroupUUID;
+ }
+
+ // @deprecated use setID()
+ public void setSecurityGroupUUID(String securityGroupUUID) {
+ this.securityGroupUUID = securityGroupUUID;
+ }
+
+ public String getSecurityGroupName() {
+ return securityGroupName;
+ }
+
+ public void setSecurityGroupName(String securityGroupName) {
+ this.securityGroupName = securityGroupName;
+ }
+
+ public String getSecurityGroupDescription() {
+ return securityGroupDescription;
+ }
+
+ public void setSecurityGroupDescription(String securityGroupDescription) {
+ this.securityGroupDescription = securityGroupDescription;
+ }
+
+ public String getSecurityGroupTenantID() {
+ return securityGroupTenantID;
+ }
+
+ public void setSecurityGroupTenantID(String securityGroupTenantID) {
+ this.securityGroupTenantID = securityGroupTenantID;
+ }
+
+ // Rules In Group
+ public List<NeutronSecurityRule> getSecurityRules() {
+ return neutronSecurityRule;
+ }
+
+ public void setSecurityRules(List<NeutronSecurityRule> neutronSecurityRule) {
+ this.neutronSecurityRule = neutronSecurityRule;
+ }
+
+ public NeutronSecurityGroup extractFields(List<String> fields) {
+ NeutronSecurityGroup ans = new NeutronSecurityGroup ();
+ Iterator<String> i = fields.iterator ();
+ while (i.hasNext ()) {
+ String s = i.next ();
+ if (s.equals ("id")) {
+ ans.setID (this.getID ());
+ }
+ if (s.equals ("name")) {
+ ans.setSecurityGroupName (this.getSecurityGroupName ());
+ }
+ if (s.equals ("description")) {
+ ans.setSecurityGroupDescription (this.getSecurityGroupDescription ());
+ }
+ if (s.equals ("tenant_id")) {
+ ans.setSecurityGroupTenantID (this.getSecurityGroupTenantID ());
+ }
+ if (s.equals ("security_group_rules")) {
+ ans.setSecurityRules (this.getSecurityRules ());
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronSecurityGroup{" +
+ "securityGroupUUID='" + securityGroupUUID + '\'' +
+ ", securityGroupName='" + securityGroupName + '\'' +
+ ", securityGroupDescription='" + securityGroupDescription + '\'' +
+ ", securityGroupTenantID='" + securityGroupTenantID + '\'' +
+ ", securityRules=" + neutronSecurityRule + "]";
+ }
+
+ public void initDefaults() {
+ //TODO verify no defaults values are nessecary required.
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * See OpenStack Network API v2.0 Reference for description of
+ * annotated attributes. The current fields are as follows:
+ * <p>
+ * id uuid (String) UUID for the security group rule.
+ * security_rule_id uuid (String) The security group to associate rule.
+ * direction String Direction the VM traffic (ingress/egress).
+ * security_group_id The security group to associate rule with.
+ * protocol String IP Protocol (icmp, tcp, udp, etc).
+ * port_range_min Integer Port at start of range
+ * port_range_max Integer Port at end of range
+ * ethertype String ethertype in L2 packet (IPv4, IPv6, etc)
+ * remote_ip_prefix String (IP cidr) CIDR for address range.
+ * remote_group_id uuid-str Source security group to apply to rule.
+ * tenant_id uuid-str Owner of security rule. Admin only outside tenant.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSecurityRule implements Serializable, INeutronObject {
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "id")
+ String securityRuleUUID;
+
+ @XmlElement(name = "direction")
+ String securityRuleDirection;
+
+ @XmlElement(name = "protocol")
+ String securityRuleProtocol;
+
+ @XmlElement(name = "port_range_min")
+ Integer securityRulePortMin;
+
+ @XmlElement(name = "port_range_max")
+ Integer securityRulePortMax;
+
+ @XmlElement(name = "ethertype")
+ String securityRuleEthertype;
+
+ @XmlElement(name = "remote_ip_prefix")
+ String securityRuleRemoteIpPrefix;
+
+ @XmlElement(name = "remote_group_id")
+ String securityRemoteGroupID;
+
+ @XmlElement(name = "security_group_id")
+ String securityRuleGroupID;
+
+ @XmlElement(name = "tenant_id")
+ String securityRuleTenantID;
+
+ public NeutronSecurityRule() {
+ }
+
+ public String getID() {
+ return securityRuleUUID;
+ }
+
+ public void setID(String id) {
+ securityRuleUUID = id;
+ }
+
+ // @deprecated use getID()
+ public String getSecurityRuleUUID() {
+ return securityRuleUUID;
+ }
+
+ // @deprecated use setID()
+ public void setSecurityRuleUUID(String securityRuleUUID) {
+ this.securityRuleUUID = securityRuleUUID;
+ }
+
+ public String getSecurityRuleDirection() {
+ return securityRuleDirection;
+ }
+
+ public void setSecurityRuleDirection(String securityRuleDirection) {
+ this.securityRuleDirection = securityRuleDirection;
+ }
+
+ public String getSecurityRuleProtocol() {
+ return securityRuleProtocol;
+ }
+
+ public void setSecurityRuleProtocol(String securityRuleProtocol) {
+ this.securityRuleProtocol = securityRuleProtocol;
+ }
+
+ public Integer getSecurityRulePortMin() {
+ return securityRulePortMin;
+ }
+
+ public void setSecurityRulePortMin(Integer securityRulePortMin) {
+ this.securityRulePortMin = securityRulePortMin;
+ }
+
+ public Integer getSecurityRulePortMax() {
+ return securityRulePortMax;
+ }
+
+ public void setSecurityRulePortMax(Integer securityRulePortMax) {
+ this.securityRulePortMax = securityRulePortMax;
+ }
+
+ public String getSecurityRuleEthertype() {
+ return securityRuleEthertype;
+ }
+
+ public void setSecurityRuleEthertype(String securityRuleEthertype) {
+ this.securityRuleEthertype = securityRuleEthertype;
+ }
+
+ public String getSecurityRuleRemoteIpPrefix() {
+ return securityRuleRemoteIpPrefix;
+ }
+
+ public void setSecurityRuleRemoteIpPrefix(String securityRuleRemoteIpPrefix) {
+ this.securityRuleRemoteIpPrefix = securityRuleRemoteIpPrefix;
+ }
+
+ public String getSecurityRemoteGroupID() {
+ return securityRemoteGroupID;
+ }
+
+ public void setSecurityRemoteGroupID(String securityRemoteGroupID) {
+ this.securityRemoteGroupID = securityRemoteGroupID;
+ }
+
+ public String getSecurityRuleGroupID() {
+ return securityRuleGroupID;
+ }
+
+ public void setSecurityRuleGroupID(String securityRuleGroupID) {
+ this.securityRuleGroupID = securityRuleGroupID;
+ }
+
+ public String getSecurityRuleTenantID() {
+ return securityRuleTenantID;
+ }
+
+ public void setSecurityRuleTenantID(String securityRuleTenantID) {
+ this.securityRuleTenantID = securityRuleTenantID;
+ }
+
+ public NeutronSecurityRule extractFields(List<String> fields) {
+ NeutronSecurityRule ans = new NeutronSecurityRule();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setID(this.getID());
+ }
+ if (s.equals("direction")) {
+ ans.setSecurityRuleDirection(this.getSecurityRuleDirection());
+ }
+ if (s.equals("protocol")) {
+ ans.setSecurityRuleProtocol(this.getSecurityRuleProtocol());
+ }
+ if (s.equals("port_range_min")) {
+ ans.setSecurityRulePortMin(this.getSecurityRulePortMin());
+ }
+ if (s.equals("port_range_max")) {
+ ans.setSecurityRulePortMax(this.getSecurityRulePortMax());
+ }
+ if (s.equals("ethertype")) {
+ ans.setSecurityRuleEthertype(this.getSecurityRuleEthertype());
+ }
+ if (s.equals("remote_ip_prefix")) {
+ ans.setSecurityRuleRemoteIpPrefix(this.getSecurityRuleRemoteIpPrefix());
+ }
+ if (s.equals("remote_group_id")) {
+ ans.setSecurityRemoteGroupID(this.getSecurityRemoteGroupID());
+ }
+ if (s.equals("security_group_id")) {
+ ans.setSecurityRuleGroupID(this.getSecurityRuleGroupID());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setSecurityRuleTenantID(this.getSecurityRuleTenantID());
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronSecurityRule{" +
+ "securityRuleUUID='" + securityRuleUUID + '\'' +
+ ", securityRuleDirection='" + securityRuleDirection + '\'' +
+ ", securityRuleProtocol='" + securityRuleProtocol + '\'' +
+ ", securityRulePortMin=" + securityRulePortMin +
+ ", securityRulePortMax=" + securityRulePortMax +
+ ", securityRuleEthertype='" + securityRuleEthertype + '\'' +
+ ", securityRuleRemoteIpPrefix='" + securityRuleRemoteIpPrefix + '\'' +
+ ", securityRemoteGroupID=" + securityRemoteGroupID +
+ ", securityRuleGroupID='" + securityRuleGroupID + '\'' +
+ ", securityRuleTenantID='" + securityRuleTenantID + '\'' +
+ '}';
+ }
+
+ public void initDefaults() {
+ //TODO verify no defaults values are nessecary required.
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.commons.net.util.SubnetUtils;
+import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSubnet implements Serializable, INeutronObject {
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(NeutronCRUDInterfaces.class);
+
+ private static final long serialVersionUID = 1L;
+ private static final int IPV4_VERSION = 4;
+ private static final int IPV6_VERSION = 6;
+ private static final int IPV6_LENGTH = 128;
+ private static final int IPV6_LENGTH_BYTES = 8;
+ private static final long IPV6_LSB_MASK = 0x000000FF;
+ private static final int IPV6_BYTE_OFFSET = 7;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement (name = "id")
+ String subnetUUID;
+
+ @XmlElement (name = "network_id")
+ String networkUUID;
+
+ @XmlElement (name = "name")
+ String name;
+
+ @XmlElement (defaultValue = "4", name = "ip_version")
+ Integer ipVersion;
+
+ @XmlElement (name = "cidr")
+ String cidr;
+
+ @XmlElement (name = "gateway_ip")
+ String gatewayIP;
+
+ @XmlElement (name = "dns_nameservers")
+ List<String> dnsNameservers;
+
+ @XmlElement (name = "allocation_pools")
+ List<NeutronSubnetIPAllocationPool> allocationPools;
+
+ @XmlElement (name = "host_routes")
+ List<NeutronSubnet_HostRoute> hostRoutes;
+
+ @XmlElement (defaultValue = "true", name = "enable_dhcp")
+ Boolean enableDHCP;
+
+ @XmlElement (name = "tenant_id")
+ String tenantID;
+
+ @XmlElement (name = "ipv6_address_mode", nillable = true)
+ String ipV6AddressMode;
+
+ @XmlElement (name = "ipv6_ra_mode", nillable = true)
+ String ipV6RaMode;
+
+ /* stores the OpenStackPorts associated with an instance
+ * used to determine if that instance can be deleted.
+ *
+ * @deprecated, will be removed in Boron
+ */
+
+ List<NeutronPort> myPorts;
+
+ public NeutronSubnet() {
+ myPorts = new ArrayList<NeutronPort>();
+ }
+
+ // @deprecated - will be removed in Boron
+ public void setPorts(List<NeutronPort> arg) {
+ myPorts = arg;
+ }
+
+ public String getID() { return subnetUUID; }
+
+ public void setID(String id) { this.subnetUUID = id; }
+
+ public String getSubnetUUID() {
+ return subnetUUID;
+ }
+
+ public void setSubnetUUID(String subnetUUID) {
+ this.subnetUUID = subnetUUID;
+ }
+
+ public String getNetworkUUID() {
+ return networkUUID;
+ }
+
+ public void setNetworkUUID(String networkUUID) {
+ this.networkUUID = networkUUID;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getIpVersion() {
+ return ipVersion;
+ }
+
+ public void setIpVersion(Integer ipVersion) {
+ this.ipVersion = ipVersion;
+ }
+
+ public String getCidr() {
+ return cidr;
+ }
+
+ public void setCidr(String cidr) {
+ this.cidr = cidr;
+ }
+
+ public String getGatewayIP() {
+ return gatewayIP;
+ }
+
+ public void setGatewayIP(String gatewayIP) {
+ this.gatewayIP = gatewayIP;
+ }
+
+ public List<String> getDnsNameservers() {
+ return dnsNameservers;
+ }
+
+ public void setDnsNameservers(List<String> dnsNameservers) {
+ this.dnsNameservers = dnsNameservers;
+ }
+
+ public List<NeutronSubnetIPAllocationPool> getAllocationPools() {
+ return allocationPools;
+ }
+
+ public void setAllocationPools(List<NeutronSubnetIPAllocationPool> allocationPools) {
+ this.allocationPools = allocationPools;
+ }
+
+ public List<NeutronSubnet_HostRoute> getHostRoutes() {
+ return hostRoutes;
+ }
+
+ public void setHostRoutes(List<NeutronSubnet_HostRoute> hostRoutes) {
+ this.hostRoutes = hostRoutes;
+ }
+
+ public boolean isEnableDHCP() {
+ if (enableDHCP == null) {
+ return true;
+ }
+ return enableDHCP;
+ }
+
+ public Boolean getEnableDHCP() { return enableDHCP; }
+
+ public void setEnableDHCP(Boolean newValue) {
+ enableDHCP = newValue;
+ }
+
+ public String getTenantID() {
+ return tenantID;
+ }
+
+ public void setTenantID(String tenantID) {
+ this.tenantID = tenantID;
+ }
+
+ public String getIpV6AddressMode() { return ipV6AddressMode; }
+
+ public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
+
+ public String getIpV6RaMode() { return ipV6RaMode; }
+
+ public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
+
+ /**
+ * This method copies selected fields from the object and returns them
+ * as a new object, suitable for marshaling.
+ *
+ * @param fields
+ * List of attributes to be extracted
+ * @return an OpenStackSubnets object with only the selected fields
+ * populated
+ */
+
+ public NeutronSubnet extractFields(List<String> fields) {
+ NeutronSubnet ans = new NeutronSubnet();
+ Iterator<String> i = fields.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (s.equals("id")) {
+ ans.setSubnetUUID(this.getSubnetUUID());
+ }
+ if (s.equals("network_id")) {
+ ans.setNetworkUUID(this.getNetworkUUID());
+ }
+ if (s.equals("name")) {
+ ans.setName(this.getName());
+ }
+ if (s.equals("ip_version")) {
+ ans.setIpVersion(this.getIpVersion());
+ }
+ if (s.equals("cidr")) {
+ ans.setCidr(this.getCidr());
+ }
+ if (s.equals("gateway_ip")) {
+ ans.setGatewayIP(this.getGatewayIP());
+ }
+ if (s.equals("dns_nameservers")) {
+ List<String> nsList = new ArrayList<String>();
+ nsList.addAll(this.getDnsNameservers());
+ ans.setDnsNameservers(nsList);
+ }
+ if (s.equals("allocation_pools")) {
+ List<NeutronSubnetIPAllocationPool> aPools = new ArrayList<NeutronSubnetIPAllocationPool>();
+ aPools.addAll(this.getAllocationPools());
+ ans.setAllocationPools(aPools);
+ }
+ if (s.equals("host_routes")) {
+ List<NeutronSubnet_HostRoute> hRoutes = new ArrayList<NeutronSubnet_HostRoute>();
+ hRoutes.addAll(this.getHostRoutes());
+ ans.setHostRoutes(hRoutes);
+ }
+ if (s.equals("enable_dhcp")) {
+ ans.setEnableDHCP(this.getEnableDHCP());
+ }
+ if (s.equals("tenant_id")) {
+ ans.setTenantID(this.getTenantID());
+ }
+ if (s.equals("ipv6_address_mode")) {
+ ans.setIpV6AddressMode(this.getIpV6AddressMode());
+ }
+ if (s.equals("ipv6_ra_mode")) {
+ ans.setIpV6RaMode(this.getIpV6RaMode());
+ }
+ }
+ return ans;
+ }
+
+ // @deprecated - will be removed in Boron
+ public List<NeutronPort> getPortsInSubnet() {
+ return myPorts;
+ }
+
+ // @deprecated - will be removed in Boron
+ public List<NeutronPort> getPortsInSubnet(String ignore) {
+ List<NeutronPort> answer = new ArrayList<NeutronPort>();
+ for (NeutronPort port : myPorts) {
+ if (!port.getDeviceOwner().equalsIgnoreCase(ignore)) {
+ answer.add(port);
+ }
+ }
+ return answer;
+ }
+
+ /* test to see if the cidr address used to define this subnet
+ * is a valid network address (an necessary condition when creating
+ * a new subnet)
+ */
+ public boolean isValidCIDR() {
+ // fix for Bug 2290 - need to wrap the existing test as
+ // IPv4 because SubnetUtils doesn't support IPv6
+ if (ipVersion == IPV4_VERSION) {
+ try {
+ SubnetUtils util = new SubnetUtils(cidr);
+ SubnetInfo info = util.getInfo();
+ if (!info.getNetworkAddress().equals(info.getAddress())) {
+ return false;
+ }
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("Failure in isValidCIDR()", e);
+ return false;
+ }
+ return true;
+ }
+ if (ipVersion == IPV6_VERSION) {
+ // fix for Bug2290 - this is custom code because no classes
+ // with ODL-friendly licenses have been found
+ // extract address (in front of /) and length (after /)
+ String[] parts = cidr.split("/");
+ if (parts.length != 2) {
+ return false;
+ }
+ try {
+ int length = Integer.parseInt(parts[1]);
+ //TODO?: limit check on length
+ // convert to byte array
+ byte[] addrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
+ int i;
+ for (i = length; i < IPV6_LENGTH; i++) {
+ if (((((int) addrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) != 0) {
+ return(false);
+ }
+ }
+ return(true);
+ } catch (UnknownHostException e) {
+ LOGGER.warn("Failure in isValidCIDR()", e);
+ return(false);
+ }
+ }
+ return false;
+ }
+
+ /* test to see if the gateway IP specified overlaps with specified
+ * allocation pools (an error condition when creating a new subnet
+ * or assigning a gateway IP)
+ */
+ public boolean gatewayIP_Pool_overlap() {
+ Iterator<NeutronSubnetIPAllocationPool> i = allocationPools.iterator();
+ while (i.hasNext()) {
+ NeutronSubnetIPAllocationPool pool = i.next();
+ if (ipVersion == IPV4_VERSION && pool.contains(gatewayIP)) {
+ return true;
+ }
+ if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean initDefaults() {
+ if (enableDHCP == null) {
+ enableDHCP = true;
+ }
+ if (ipVersion == null) {
+ ipVersion = IPV4_VERSION;
+ }
+ dnsNameservers = new ArrayList<String>();
+ if (hostRoutes == null) {
+ hostRoutes = new ArrayList<NeutronSubnet_HostRoute>();
+ }
+ if (allocationPools == null) {
+ allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
+ if (ipVersion == IPV4_VERSION) {
+ try {
+ SubnetUtils util = new SubnetUtils(cidr);
+ SubnetInfo info = util.getInfo();
+ if (gatewayIP == null || ("").equals(gatewayIP)) {
+ gatewayIP = info.getLowAddress();
+ }
+ if (allocationPools.size() < 1) {
+ NeutronSubnetIPAllocationPool source =
+ new NeutronSubnetIPAllocationPool(info.getLowAddress(),
+ info.getHighAddress());
+ allocationPools = source.splitPool(gatewayIP);
+ }
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("Failure in initDefault()", e);
+ return false;
+ }
+ }
+ if (ipVersion == IPV6_VERSION) {
+ String[] parts = cidr.split("/");
+ if (parts.length != 2) {
+ return false;
+ }
+ try {
+ int length = Integer.parseInt(parts[1]);
+ BigInteger lowAddress_bi = NeutronSubnetIPAllocationPool.convertV6(parts[0]);
+ String lowAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(BigInteger.ONE));
+ BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
+ String highAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(mask).subtract(BigInteger.ONE));
+ if (gatewayIP == null || ("").equals(gatewayIP)) {
+ gatewayIP = lowAddress;
+ }
+ if (allocationPools.size() < 1) {
+ NeutronSubnetIPAllocationPool source =
+ new NeutronSubnetIPAllocationPool(lowAddress,
+ highAddress);
+ allocationPools = source.splitPoolV6(gatewayIP);
+ }
+ } catch (Exception e) {
+ LOGGER.warn("Failure in initDefault()", e);
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /* this method tests to see if the supplied IPv4 address
+ * is valid for this subnet or not
+ */
+ public boolean isValidIP(String ipAddress) {
+ if (ipVersion == IPV4_VERSION) {
+ try {
+ SubnetUtils util = new SubnetUtils(cidr);
+ SubnetInfo info = util.getInfo();
+ return info.isInRange(ipAddress);
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("Failure in isValidIP()", e);
+ return false;
+ }
+ }
+
+ if (ipVersion == IPV6_VERSION) {
+ String[] parts = cidr.split("/");
+ try {
+ int length = Integer.parseInt(parts[1]);
+ byte[] cidrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
+ byte[] ipBytes = ((Inet6Address) InetAddress.getByName(ipAddress)).getAddress();
+ int i;
+ for (i = 0; i < length; i++) {
+ if (((((int) cidrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) !=
+ ((((int) ipBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES))))) {
+ return(false);
+ }
+ }
+ return(true);
+ } catch (UnknownHostException e) {
+ LOGGER.warn("Failure in isValidIP()", e);
+ return(false);
+ }
+ }
+ return false;
+ }
+
+ /* method to get the lowest available address of the subnet.
+ * go through all the allocation pools and keep the lowest of their
+ * low addresses.
+ */
+ public String getLowAddr() {
+ String ans = null;
+ Iterator<NeutronSubnetIPAllocationPool> i = allocationPools.iterator();
+ while (i.hasNext()) {
+ NeutronSubnetIPAllocationPool pool = i.next();
+ if (ans == null) {
+ ans = pool.getPoolStart();
+ }
+ else {
+ if (ipVersion == IPV4_VERSION &&
+ NeutronSubnetIPAllocationPool.convert(pool.getPoolStart()) <
+ NeutronSubnetIPAllocationPool.convert(ans)) {
+ ans = pool.getPoolStart();
+ }
+ if (ipVersion == IPV6_VERSION &&
+ NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart()).compareTo(NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
+ ans = pool.getPoolStart();
+ }
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronSubnet [subnetUUID=" + subnetUUID + ", networkUUID=" + networkUUID + ", name=" + name
+ + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers="
+ + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes
+ + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID
+ + ", ipv6AddressMode=" + ipV6AddressMode
+ + ", ipv6RaMode=" + ipV6RaMode + "]";
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronSubnetIPAllocationPool implements Serializable {
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(NeutronSubnetIPAllocationPool.class);
+
+ private static final long serialVersionUID = 1L;
+
+ private static final int BYTE_LENGTH = 8;
+ private static final int IPV4_DOTTED_QUADS = 4;
+ private static final int IPV4_DOTTED_QUAD_OFFSET = 3;
+ private static final int IPV4_DOTTED_QUAD_MASK = 255;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement(name = "start")
+ String poolStart;
+
+ @XmlElement(name = "end")
+ String poolEnd;
+
+ public NeutronSubnetIPAllocationPool() {
+ }
+
+ public NeutronSubnetIPAllocationPool(String lowAddress, String highAddress) {
+ poolStart = lowAddress;
+ poolEnd = highAddress;
+ }
+
+ public String getPoolStart() {
+ return poolStart;
+ }
+
+ public void setPoolStart(String poolStart) {
+ this.poolStart = poolStart;
+ }
+
+ public String getPoolEnd() {
+ return poolEnd;
+ }
+
+ public void setPoolEnd(String poolEnd) {
+ this.poolEnd = poolEnd;
+ }
+
+ /**
+ * This method determines if this allocation pool contains the
+ * input IPv4 address
+ *
+ * @param inputString
+ * IPv4 address in dotted decimal format
+ * @return a boolean on whether the pool contains the address or not
+ */
+
+ public boolean contains(String inputString) {
+ long inputIP = convert(inputString);
+ long startIP = convert(poolStart);
+ long endIP = convert(poolEnd);
+ return (inputIP >= startIP && inputIP <= endIP);
+ }
+
+ /**
+ * This static method converts the supplied IPv4 address to a long
+ * integer for comparison
+ *
+ * @param inputString
+ * IPv4 address in dotted decimal format
+ * @return high-endian representation of the IPv4 address as a long.
+ * This method will return 0 if the input is null.
+ */
+
+ static long convert(String inputString) {
+ long ans = 0;
+ if (inputString != null) {
+ String[] parts = inputString.split("\\.");
+ for (String part: parts) {
+ ans <<= BYTE_LENGTH;
+ ans |= Integer.parseInt(part);
+ }
+ }
+ return ans;
+ }
+
+ /**
+ * This method determines if this allocation pool contains the
+ * input IPv4 address
+ *
+ * @param inputString
+ * IPv4 address in dotted decimal format
+ * @return a boolean on whether the pool contains the address or not
+ */
+
+ public boolean containsV6(String inputString) {
+ BigInteger inputIP = convertV6(inputString);
+ BigInteger startIP = convertV6(poolStart);
+ BigInteger endIP = convertV6(poolEnd);
+ return (inputIP.compareTo(startIP) >= 0 && inputIP.compareTo(endIP) <= 0);
+ }
+
+ /**
+ * This static method converts the supplied IPv4 address to a long
+ * integer for comparison
+ *
+ * @param inputString
+ * IPv6 address in dotted decimal format
+ * @return high-endian representation of the IPv4 address as a BigInteger.
+ * This method will return 0 if the input is null.
+ */
+
+ static BigInteger convertV6(String inputString) {
+ if (inputString == null) {
+ return BigInteger.ZERO;
+ }
+ try {
+ return new BigInteger(((Inet6Address) InetAddress.getByName(inputString)).getAddress());
+ } catch (Exception e) {
+ LOGGER.error("convertV6 error", e);
+ return BigInteger.ZERO;
+ }
+ }
+
+ /**
+ * This static method converts the supplied high-ending long back
+ * into a dotted decimal representation of an IPv4 address
+ *
+ * @param l
+ * high-endian representation of the IPv4 address as a long
+ * @return IPv4 address in dotted decimal format
+ */
+ static String longToIP(long input) {
+ int part;
+ long ipLong = input;
+ String[] parts = new String[IPV4_DOTTED_QUADS];
+ for (part = 0; part < IPV4_DOTTED_QUADS; part++) {
+ parts[IPV4_DOTTED_QUAD_OFFSET-part] = String.valueOf(ipLong & IPV4_DOTTED_QUAD_MASK);
+ ipLong >>= BYTE_LENGTH;
+ }
+ return join(parts,".");
+ }
+
+ /**
+ * This static method converts the supplied high-ending long back
+ * into a dotted decimal representation of an IPv4 address
+ *
+ * @param l
+ * high-endian representation of the IPv4 address as a long
+ * @return IPv4 address in dotted decimal format
+ */
+ static String bigIntegerToIP(BigInteger b) {
+ try {
+ return Inet6Address.getByAddress(b.toByteArray()).getHostAddress();
+ } catch (Exception e) {
+ LOGGER.error("bigIntegerToIP", e);
+ return "ERROR";
+ }
+ }
+
+ /*
+ * helper routine used by longToIP
+ */
+ public static String join(String r[],String separator)
+ {
+ if (r.length == 0) {
+ return "";
+ }
+ StringBuilder sb = new StringBuilder();
+ int i;
+ for(i = 0;i < r.length - 1;i++) {
+ sb.append(r[i]);
+ sb.append(separator);
+ }
+ return sb.toString() + r[i];
+ }
+
+ /*
+ * This method splits the current instance by removing the supplied
+ * parameter.
+ *
+ * If the parameter is either the low or high address,
+ * then that member is adjusted and a list containing just this instance
+ * is returned.
+ *
+ * If the parameter is in the middle of the pool, then
+ * create two new instances, one ranging from low to parameter-1
+ * the other ranging from parameter+1 to high
+ */
+ public List<NeutronSubnetIPAllocationPool> splitPool(String ipAddress) {
+ List<NeutronSubnetIPAllocationPool> ans = new ArrayList<NeutronSubnetIPAllocationPool>();
+ long gIP = NeutronSubnetIPAllocationPool.convert(ipAddress);
+ long sIP = NeutronSubnetIPAllocationPool.convert(poolStart);
+ long eIP = NeutronSubnetIPAllocationPool.convert(poolEnd);
+ long i;
+ NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+ boolean poolStarted = false;
+ for (i = sIP; i <= eIP; i++) {
+ if (i == sIP) {
+ if (i != gIP) {
+ p.setPoolStart(poolStart);
+ poolStarted = true;
+ } else {
+ //FIX for bug 533
+ p.setPoolStart(NeutronSubnetIPAllocationPool.longToIP(i+1));
+ }
+ }
+ if (i == eIP) {
+ if (i != gIP) {
+ p.setPoolEnd(poolEnd);
+ } else {
+ p.setPoolEnd(NeutronSubnetIPAllocationPool.longToIP(i-1));
+ }
+ ans.add(p);
+ }
+ if (i != sIP && i != eIP) {
+ if (i != gIP) {
+ if (!poolStarted) {
+ p.setPoolStart(NeutronSubnetIPAllocationPool.longToIP(i));
+ poolStarted = true;
+ }
+ } else {
+ p.setPoolEnd(NeutronSubnetIPAllocationPool.longToIP(i-1));
+ poolStarted = false;
+ ans.add(p);
+ p = new NeutronSubnetIPAllocationPool();
+ // Fix for 2120
+ p.setPoolStart(NeutronSubnetIPAllocationPool.longToIP(i+1));
+ poolStarted = true;
+ }
+ }
+ }
+ return ans;
+ }
+
+ @Override
+ public String toString() {
+ return "NeutronSubnetIPAllocationPool [" +
+ "start=" + poolStart +
+ ", end=" + poolEnd + "]";
+ }
+
+ /*
+ * This method splits the current instance by removing the supplied
+ * parameter.
+ *
+ * If the parameter is either the low or high address,
+ * then that member is adjusted and a list containing just this instance
+ * is returned.
+ new *
+ * If the parameter is in the middle of the pool, then
+ * create two new instances, one ranging from low to parameter-1
+ * the other ranging from parameter+1 to high
+ * If the pool is a single address, return null
+ */
+ public List<NeutronSubnetIPAllocationPool> splitPoolV6(String ipAddress) {
+ List<NeutronSubnetIPAllocationPool> ans = new ArrayList<NeutronSubnetIPAllocationPool>();
+ BigInteger gIP = NeutronSubnetIPAllocationPool.convertV6(ipAddress);
+ BigInteger sIP = NeutronSubnetIPAllocationPool.convertV6(poolStart);
+ BigInteger eIP = NeutronSubnetIPAllocationPool.convertV6(poolEnd);
+ if (gIP.compareTo(sIP) == 0 && gIP.compareTo(eIP) < 0) {
+ NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+ p.setPoolStart(NeutronSubnetIPAllocationPool.bigIntegerToIP(sIP.add(BigInteger.ONE)));
+ p.setPoolEnd(poolEnd);
+ ans.add(p);
+ return(ans);
+ }
+ if (gIP.compareTo(eIP) == 0 && gIP.compareTo(sIP) > 0) {
+ NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+ p.setPoolStart(poolStart);
+ p.setPoolEnd(NeutronSubnetIPAllocationPool.bigIntegerToIP(eIP.subtract(BigInteger.ONE)));
+ ans.add(p);
+ return(ans);
+ }
+ if (gIP.compareTo(eIP) < 0 && gIP.compareTo(sIP) > 0) {
+ NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+ p.setPoolStart(poolStart);
+ p.setPoolEnd(NeutronSubnetIPAllocationPool.bigIntegerToIP(gIP.subtract(BigInteger.ONE)));
+ ans.add(p);
+ NeutronSubnetIPAllocationPool p2 = new NeutronSubnetIPAllocationPool();
+ p2.setPoolStart(NeutronSubnetIPAllocationPool.bigIntegerToIP(gIP.add(BigInteger.ONE)));
+ p2.setPoolEnd(poolEnd);
+ ans.add(p2);
+ return ans;
+ }
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronSubnet_HostRoute implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement(name = "destination")
+ String destination;
+
+ @XmlElement(name = "nexthop")
+ String nextHop;
+
+ /**
+ * HostRoute constructor
+ */
+ public NeutronSubnet_HostRoute() { }
+
+ @Override
+ public String toString() {
+ return "NeutronSubnetHostRoute [" +
+ "destination=" + destination +
+ ", nextHop=" + nextHop + "]";
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class Neutron_ID implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement(name = "id")
+ String uuid;
+
+ public Neutron_ID() { }
+
+ public Neutron_ID(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getID() {
+ return uuid;
+ }
+
+ public void setID(String uuid) {
+ this.uuid = uuid;
+ }
+
+ @Override
+ public String toString() {
+ return "Neutron_ID{" + "id='" + uuid + '\'' + "}";
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class Neutron_IPs implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ // See OpenStack Network API v2.0 Reference for description of
+ // annotated attributes
+
+ @XmlElement(name = "ip_address")
+ String ipAddress;
+
+ @XmlElement(name = "subnet_id")
+ String subnetUUID;
+
+ public Neutron_IPs() { }
+
+ public Neutron_IPs(String uuid) {
+ subnetUUID = uuid;
+ }
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ public String getSubnetUUID() {
+ return subnetUUID;
+ }
+
+ public void setSubnetUUID(String subnetUUID) {
+ this.subnetUUID = subnetUUID;
+ }
+
+ @Override
+ public String toString() {
+ return "Neutron_IPs{" +
+ "ipAddress='" + ipAddress + '\'' +
+ ", subnetUUID='" + subnetUUID + '\'' + "}";
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Firewall objects
+ */
+
+public interface INeutronFirewallCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ *Firewall object exists
+ *
+ * @param uuid
+ * UUID of the Firewall object
+ * @return boolean
+ */
+
+ boolean neutronFirewallExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * Firewall object exists
+ *
+ * @param uuid
+ * UUID of the Firewall object
+ * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall}
+ * OpenStackFirewall class
+ */
+
+ NeutronFirewall getNeutronFirewall(String uuid);
+
+ /**
+ * Applications call this interface method to return all Firewall objects
+ *
+ * @return List of OpenStackNetworks objects
+ */
+
+ List<NeutronFirewall> getAllNeutronFirewalls();
+
+ /**
+ * Applications call this interface method to add a Firewall object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackNetwork object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronFirewall(NeutronFirewall input);
+
+ /**
+ * Applications call this interface method to remove a Neutron Firewall object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the Firewall object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronFirewall(String uuid);
+
+ /**
+ * Applications call this interface method to edit a Firewall object
+ *
+ * @param uuid
+ * identifier of the Firewall object
+ * @param delta
+ * OpenStackFirewall object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronFirewall(String uuid, NeutronFirewall delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid
+ * identifier of the Firewall object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ boolean neutronFirewallInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Firewall Policy objects
+ *
+ */
+
+public interface INeutronFirewallPolicyCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ *FirewallPolicy object exists
+ *
+ * @param uuid
+ * UUID of the Firewall Policy object
+ * @return boolean
+ */
+
+ boolean neutronFirewallPolicyExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * FirewallPolicy object exists
+ *
+ * @param uuid
+ * UUID of the Firewall Policy object
+ * @return {@link NeutronFirewallPolicy}
+ * OpenStackFirewallPolicy class
+ */
+
+ NeutronFirewallPolicy getNeutronFirewallPolicy(String uuid);
+
+ /**
+ * Applications call this interface method to return all Firewall Policy objects
+ *
+ * @return List of OpenStack Firewall Policy objects
+ */
+
+ List<NeutronFirewallPolicy> getAllNeutronFirewallPolicies();
+
+ /**
+ * Applications call this interface method to add a Firewall Policy object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackNetwork object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronFirewallPolicy(NeutronFirewallPolicy input);
+
+ /**
+ * Applications call this interface method to remove a Neutron FirewallPolicy object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the Firewall Policy object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronFirewallPolicy(String uuid);
+
+ /**
+ * Applications call this interface method to edit a FirewallPolicy object
+ *
+ * @param uuid
+ * identifier of the Firewall Policy object
+ * @param delta
+ * OpenStackFirewallPolicy object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronFirewallPolicy(String uuid, NeutronFirewallPolicy delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid
+ * identifier of the Firewall Policy object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ boolean neutronFirewallPolicyInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Firewall Rule objects
+ *
+ */
+
+public interface INeutronFirewallRuleCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ *FirewallRule object exists
+ *
+ * @param uuid
+ * UUID of the Firewall Rule object
+ * @return boolean
+ */
+
+ boolean neutronFirewallRuleExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * FirewallRule object exists
+ *
+ * @param uuid
+ * UUID of the Firewall Rule object
+ * @return {@link NeutronFirewallRule}
+ * OpenStackFirewall Rule class
+ */
+
+ NeutronFirewallRule getNeutronFirewallRule(String uuid);
+
+ /**
+ * Applications call this interface method to return all Firewall Rule objects
+ *
+ * @return List of OpenStackNetworks objects
+ */
+
+ List<NeutronFirewallRule> getAllNeutronFirewallRules();
+
+ /**
+ * Applications call this interface method to add a Firewall Rule object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackNetwork object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronFirewallRule(NeutronFirewallRule input);
+
+ /**
+ * Applications call this interface method to remove a Neutron FirewallRule object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the Firewall Rule object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronFirewallRule(String uuid);
+
+ /**
+ * Applications call this interface method to edit a FirewallRule object
+ *
+ * @param uuid
+ * identifier of the Firewall Rule object
+ * @param delta
+ * OpenStackFirewallRule object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronFirewallRule(String uuid, NeutronFirewallRule delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid
+ * identifier of the Firewall Rule object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ boolean neutronFirewallRuleInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+
+/**
+ * This interface defines the methods for CRUD of NB FloatingIP objects
+ *
+ */
+
+public interface INeutronFloatingIPCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ * FloatingIP object exists
+ *
+ * @param uuid
+ * UUID of the FloatingIP object
+ * @return boolean
+ */
+
+ boolean floatingIPExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * FloatingIP object exists
+ *
+ * @param uuid
+ * UUID of the FloatingIP object
+ * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP}
+ * OpenStack FloatingIP class
+ */
+
+ NeutronFloatingIP getFloatingIP(String uuid);
+
+ /**
+ * Applications call this interface method to return all FloatingIP objects
+ *
+ * @return a Set of OpenStackFloatingIPs objects
+ */
+
+ List<NeutronFloatingIP> getAllFloatingIPs();
+
+ /**
+ * Applications call this interface method to add a FloatingIP object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackFloatingIP object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addFloatingIP(NeutronFloatingIP input);
+
+ /**
+ * Applications call this interface method to remove a FloatingIP object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the FloatingIP object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeFloatingIP(String uuid);
+
+ /**
+ * Applications call this interface method to edit a FloatingIP object
+ *
+ * @param uuid
+ * identifier of the FloatingIP object
+ * @param delta
+ * OpenStackFloatingIP object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateFloatingIP(String uuid, NeutronFloatingIP delta);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancer objects
+ *
+ */
+
+public interface INeutronLoadBalancerCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ *LoadBalancer object exists
+ *
+ * @param uuid
+ * UUID of the LoadBalancer object
+ * @return boolean
+ */
+
+ boolean neutronLoadBalancerExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * LoadBalancer object exists
+ *
+ * @param uuid
+ * UUID of the LoadBalancer object
+ * @return {@link NeutronLoadBalancer}
+ * OpenStackLoadBalancer class
+ */
+
+ NeutronLoadBalancer getNeutronLoadBalancer(String uuid);
+
+ /**
+ * Applications call this interface method to return all LoadBalancer objects
+ *
+ * @return List of OpenStackNetworks objects
+ */
+
+ List<NeutronLoadBalancer> getAllNeutronLoadBalancers();
+
+ /**
+ * Applications call this interface method to add a LoadBalancer object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackNetwork object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronLoadBalancer(NeutronLoadBalancer input);
+
+ /**
+ * Applications call this interface method to remove a Neutron LoadBalancer object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the LoadBalancer object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronLoadBalancer(String uuid);
+
+ /**
+ * Applications call this interface method to edit a LoadBalancer object
+ *
+ * @param uuid
+ * identifier of the LoadBalancer object
+ * @param delta
+ * OpenStackLoadBalancer object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronLoadBalancer(String uuid, NeutronLoadBalancer delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid
+ * identifier of the LoadBalancer object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ boolean neutronLoadBalancerInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerHealthMonitor;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerHealthMonitor objects
+ *
+ */
+
+public interface INeutronLoadBalancerHealthMonitorCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ *LoadBalancerHealthMonitor object exists
+ *
+ * @param uuid
+ * UUID of the LoadBalancerHealthMonitor object
+ * @return boolean
+ */
+
+ boolean neutronLoadBalancerHealthMonitorExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * LoadBalancerHealthMonitor object exists
+ *
+ * @param uuid
+ * UUID of the LoadBalancerHealthMonitor object
+ * @return {@link NeutronLoadBalancerHealthMonitor}
+ * OpenStackLoadBalancerHealthMonitor class
+ */
+
+ NeutronLoadBalancerHealthMonitor getNeutronLoadBalancerHealthMonitor(String uuid);
+
+ /**
+ * Applications call this interface method to return all LoadBalancerHealthMonitor objects
+ *
+ * @return List of OpenStackNetworks objects
+ */
+
+ List<NeutronLoadBalancerHealthMonitor> getAllNeutronLoadBalancerHealthMonitors();
+
+ /**
+ * Applications call this interface method to add a LoadBalancerHealthMonitor object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackNetwork object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor input);
+
+ /**
+ * Applications call this interface method to remove a Neutron LoadBalancerHealthMonitor object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the LoadBalancerHealthMonitor object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronLoadBalancerHealthMonitor(String uuid);
+
+ /**
+ * Applications call this interface method to edit a LoadBalancerHealthMonitor object
+ *
+ * @param uuid
+ * identifier of the LoadBalancerHealthMonitor object
+ * @param delta
+ * OpenStackLoadBalancerHealthMonitor object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronLoadBalancerHealthMonitor(String uuid, NeutronLoadBalancerHealthMonitor delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid
+ * identifier of the LoadBalancerHealthMonitor object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ boolean neutronLoadBalancerHealthMonitorInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerListener;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerListener objects
+ *
+ */
+
+public interface INeutronLoadBalancerListenerCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ *LoadBalancerListener object exists
+ *
+ * @param uuid
+ * UUID of the LoadBalancerListener object
+ * @return boolean
+ */
+
+ boolean neutronLoadBalancerListenerExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * LoadBalancerListener object exists
+ *
+ * @param uuid
+ * UUID of the LoadBalancerListener object
+ * @return {@link NeutronLoadBalancerListener}
+ * OpenStackLoadBalancerListener class
+ */
+
+ NeutronLoadBalancerListener getNeutronLoadBalancerListener(String uuid);
+
+ /**
+ * Applications call this interface method to return all LoadBalancerListener objects
+ *
+ * @return List of OpenStackNetworks objects
+ */
+
+ List<NeutronLoadBalancerListener> getAllNeutronLoadBalancerListeners();
+
+ /**
+ * Applications call this interface method to add a LoadBalancerListener object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackNetwork object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronLoadBalancerListener(NeutronLoadBalancerListener input);
+
+ /**
+ * Applications call this interface method to remove a Neutron LoadBalancerListener object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the LoadBalancerListener object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronLoadBalancerListener(String uuid);
+
+ /**
+ * Applications call this interface method to edit a LoadBalancerListener object
+ *
+ * @param uuid
+ * identifier of the LoadBalancerListener object
+ * @param delta
+ * OpenStackLoadBalancerListener object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronLoadBalancerListener(String uuid, NeutronLoadBalancerListener delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid
+ * identifier of the LoadBalancerListener object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ boolean neutronLoadBalancerListenerInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerPool objects
+ *
+ */
+
+public interface INeutronLoadBalancerPoolCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ *LoadBalancerPool object exists
+ *
+ * @param uuid
+ * UUID of the LoadBalancerPool object
+ * @return boolean
+ */
+
+ boolean neutronLoadBalancerPoolExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * LoadBalancerPool object exists
+ *
+ * @param uuid
+ * UUID of the LoadBalancerPool object
+ * @return {@link NeutronLoadBalancerPool}
+ * OpenStackLoadBalancerPool class
+ */
+
+ NeutronLoadBalancerPool getNeutronLoadBalancerPool(String uuid);
+
+ /**
+ * Applications call this interface method to return all LoadBalancerPool objects
+ *
+ * @return List of OpenStackNetworks objects
+ */
+
+ List<NeutronLoadBalancerPool> getAllNeutronLoadBalancerPools();
+
+ /**
+ * Applications call this interface method to add a LoadBalancerPool object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackNetwork object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronLoadBalancerPool(NeutronLoadBalancerPool input);
+
+ /**
+ * Applications call this interface method to remove a Neutron LoadBalancerPool object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the LoadBalancerPool object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronLoadBalancerPool(String uuid);
+
+ /**
+ * Applications call this interface method to edit a LoadBalancerPool object
+ *
+ * @param uuid
+ * identifier of the LoadBalancerPool object
+ * @param delta
+ * OpenStackLoadBalancerPool object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronLoadBalancerPool(String uuid, NeutronLoadBalancerPool delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid
+ * identifier of the LoadBalancerPool object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ boolean neutronLoadBalancerPoolInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+
+public interface INeutronLoadBalancerPoolMemberCRUD {
+
+ /**
+ * Applications call this interface method to determine if a particular
+ *NeutronLoadBalancerPoolMember object exists
+ *
+ * @param uuid
+ * UUID of the NeutronLoadBalancerPoolMember object
+ * @return boolean
+ */
+
+ boolean neutronLoadBalancerPoolMemberExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * NeutronLoadBalancerPoolMember object exists
+ *
+ * @param uuid
+ * UUID of the NeutronLoadBalancerPoolMember object
+ * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember}
+ * OpenStackNeutronLoadBalancerPoolMember class
+ */
+
+ NeutronLoadBalancerPoolMember getNeutronLoadBalancerPoolMember(String uuid);
+
+ /**
+ * Applications call this interface method to return all NeutronLoadBalancerPoolMember objects
+ *
+ * @return List of OpenStackNetworks objects
+ */
+
+ List<NeutronLoadBalancerPoolMember> getAllNeutronLoadBalancerPoolMembers();
+
+ /**
+ * Applications call this interface method to add a NeutronLoadBalancerPoolMember object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackNetwork object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember input);
+
+ /**
+ * Applications call this interface method to remove a Neutron NeutronLoadBalancerPoolMember object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the NeutronLoadBalancerPoolMember object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronLoadBalancerPoolMember(String uuid);
+
+ /**
+ * Applications call this interface method to edit a NeutronLoadBalancerPoolMember object
+ *
+ * @param uuid
+ * identifier of the NeutronLoadBalancerPoolMember object
+ * @param delta
+ * OpenStackNeutronLoadBalancerPoolMember object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronLoadBalancerPoolMember(String uuid, NeutronLoadBalancerPoolMember delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid
+ * identifier of the NeutronLoadBalancerPoolMember object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ boolean neutronLoadBalancerPoolMemberInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+
+/**
+ * This interface defines the methods for CRUD of NB network objects
+ *
+ */
+
+public interface INeutronNetworkCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ * Network object exists
+ *
+ * @param uuid
+ * UUID of the Network object
+ * @return boolean
+ */
+
+ boolean networkExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * Network object exists
+ *
+ * @param uuid
+ * UUID of the Network object
+ * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork}
+ * OpenStack Network class
+ */
+
+ NeutronNetwork getNetwork(String uuid);
+
+ /**
+ * Applications call this interface method to return all Network objects
+ *
+ * @return List of OpenStackNetworks objects
+ */
+
+ List<NeutronNetwork> getAllNetworks();
+
+ /**
+ * Applications call this interface method to add a Network object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackNetwork object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNetwork(NeutronNetwork input);
+
+ /**
+ * Applications call this interface method to remove a Network object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the network object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNetwork(String uuid);
+
+ /**
+ * Applications call this interface method to edit a Network object
+ *
+ * @param uuid
+ * identifier of the network object
+ * @param delta
+ * OpenStackNetwork object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNetwork(String uuid, NeutronNetwork delta);
+
+ /**
+ * Applications call this interface method to determine if a Network object
+ * is use
+ *
+ * @param netUUID
+ * identifier of the network object
+ *
+ * @return boolean on whether the network is in use or not
+ */
+
+ boolean networkInUse(String netUUID);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+
+/**
+ * This interface defines the methods for CRUD of NB Port objects
+ *
+ */
+
+public interface INeutronPortCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ * Port object exists
+ *
+ * @param uuid
+ * UUID of the Port object
+ * @return boolean
+ */
+
+ boolean portExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * Port object exists
+ *
+ * @param uuid
+ * UUID of the Port object
+ * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort}
+ * OpenStack Port class
+ */
+
+ NeutronPort getPort(String uuid);
+
+ /**
+ * Applications call this interface method to return all Port objects
+ *
+ * @return List of OpenStackPorts objects
+ */
+
+ List<NeutronPort> getAllPorts();
+
+ /**
+ * Applications call this interface method to add a Port object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackPort object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addPort(NeutronPort input);
+
+ /**
+ * Applications call this interface method to remove a Port object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the Port object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removePort(String uuid);
+
+ /**
+ * Applications call this interface method to edit a Port object
+ *
+ * @param uuid
+ * identifier of the Port object
+ * @param delta
+ * OpenStackPort object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updatePort(String uuid, NeutronPort delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param macAddress
+ * mac Address to be tested
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ *
+ * @deprecated - will be removed in Boron
+ */
+
+ boolean macInUse(String macAddress);
+
+ /**
+ * Applications call this interface method to retrieve the port associated with
+ * the gateway address of a subnet
+ *
+ * @param subnetUUID
+ * identifier of the subnet
+ * @return OpenStackPorts object if the port exists and null if it does not
+ *
+ * @deprecated - will be removed in Boron
+ */
+
+ NeutronPort getGatewayPort(String subnetUUID);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+
+/**
+ * This interface defines the methods for CRUD of NB Router objects
+ *
+ */
+
+public interface INeutronRouterCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ * Router object exists
+ *
+ * @param uuid
+ * UUID of the Router object
+ * @return boolean
+ */
+
+ boolean routerExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * Router object exists
+ *
+ * @param uuid
+ * UUID of the Router object
+ * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter}
+ * OpenStack Router class
+ */
+
+ NeutronRouter getRouter(String uuid);
+
+ /**
+ * Applications call this interface method to return all Router objects
+ *
+ * @return List of OpenStackRouters objects
+ */
+
+ List<NeutronRouter> getAllRouters();
+
+ /**
+ * Applications call this interface method to add a Router object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackRouter object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addRouter(NeutronRouter input);
+
+ /**
+ * Applications call this interface method to remove a Router object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the Router object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeRouter(String uuid);
+
+ /**
+ * Applications call this interface method to edit a Router object
+ *
+ * @param uuid
+ * identifier of the Router object
+ * @param delta
+ * OpenStackRouter object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateRouter(String uuid, NeutronRouter delta);
+
+ /**
+ * Applications call this interface method to check if a router is in use
+ *
+ * @param routerUUID
+ * identifier of the Router object
+ * @return boolean on whether the router is in use or not
+ */
+
+ boolean routerInUse(String routerUUID);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Security Group objects
+ */
+
+public interface INeutronSecurityGroupCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ * Security Group object exists
+ *
+ * @param uuid UUID of the Security Group object
+ * @return boolean
+ */
+
+ boolean neutronSecurityGroupExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * Security Group object exists
+ *
+ * @param uuid UUID of the Security Group object
+ * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup}
+ * OpenStack Security Group class
+ */
+
+ NeutronSecurityGroup getNeutronSecurityGroup(String uuid);
+
+ /**
+ * Applications call this interface method to return all Security Group objects
+ *
+ * @return List of OpenStackSecurity Groups objects
+ */
+
+ List<NeutronSecurityGroup> getAllNeutronSecurityGroups();
+
+ /**
+ * Applications call this interface method to add a Security Group object to the
+ * concurrent map
+ *
+ * @param input OpenStackSecurity Group object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronSecurityGroup(NeutronSecurityGroup input);
+
+ /**
+ * Applications call this interface method to remove a Neutron Security Group object to the
+ * concurrent map
+ *
+ * @param uuid identifier for the security group object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronSecurityGroup(String uuid);
+
+ /**
+ * Applications call this interface method to edit a Security Group object
+ *
+ * @param uuid identifier of the security group object
+ * @param delta OpenStackSecurity Group object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronSecurityGroup(String uuid, NeutronSecurityGroup delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid identifier of the security group object
+ * @return boolean on whether the Security Groups is already in use
+ */
+
+ boolean neutronSecurityGroupInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Security Rule objects
+ */
+
+public interface INeutronSecurityRuleCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ * Security Rule object exists
+ *
+ * @param uuid UUID of theSecurity Rule object
+ * @return boolean
+ */
+
+ boolean neutronSecurityRuleExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * Security Rule object exists
+ *
+ * @param uuid UUID of the security rule object
+ * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule}
+ * OpenStackSecurity Rule class
+ */
+
+ NeutronSecurityRule getNeutronSecurityRule(String uuid);
+
+ /**
+ * Applications call this interface method to return all Security Rule objects
+ *
+ * @return List of OpenStack SecurityRules objects
+ */
+
+ List<NeutronSecurityRule> getAllNeutronSecurityRules();
+
+ /**
+ * Applications call this interface method to add a Security Rule object to the
+ * concurrent map
+ *
+ * @param input OpenStack security rule object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addNeutronSecurityRule(NeutronSecurityRule input);
+
+ /**
+ * Applications call this interface method to remove a Neutron Security Rule object to the
+ * concurrent map
+ *
+ * @param uuid identifier for the security rule object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeNeutronSecurityRule(String uuid);
+
+ /**
+ * Applications call this interface method to edit aSecurity Rule object
+ *
+ * @param uuid identifier of the security rule object
+ * @param delta OpenStackSecurity Rule object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateNeutronSecurityRule(String uuid, NeutronSecurityRule delta);
+
+ /**
+ * Applications call this interface method to see if a MAC address is in use
+ *
+ * @param uuid identifier of the security rule object
+ * @return boolean on whether the macAddress is already associated with a
+ * port or not
+ */
+
+ boolean neutronSecurityRuleInUse(String uuid);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+
+/**
+ * This interface defines the methods for CRUD of NB Subnet objects
+ *
+ */
+
+public interface INeutronSubnetCRUD {
+ /**
+ * Applications call this interface method to determine if a particular
+ * Subnet object exists
+ *
+ * @param uuid
+ * UUID of the Subnet object
+ * @return boolean
+ */
+
+ boolean subnetExists(String uuid);
+
+ /**
+ * Applications call this interface method to return if a particular
+ * Subnet object exists
+ *
+ * @param uuid
+ * UUID of the Subnet object
+ * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet}
+ * OpenStack Subnet class
+ */
+
+ NeutronSubnet getSubnet(String uuid);
+
+ /**
+ * Applications call this interface method to return all Subnet objects
+ *
+ * @return List of OpenStackSubnets objects
+ */
+
+ List<NeutronSubnet> getAllSubnets();
+
+ /**
+ * Applications call this interface method to add a Subnet object to the
+ * concurrent map
+ *
+ * @param input
+ * OpenStackSubnet object
+ * @return boolean on whether the object was added or not
+ */
+
+ boolean addSubnet(NeutronSubnet input);
+
+ /**
+ * Applications call this interface method to remove a Subnet object to the
+ * concurrent map
+ *
+ * @param uuid
+ * identifier for the Subnet object
+ * @return boolean on whether the object was removed or not
+ */
+
+ boolean removeSubnet(String uuid);
+
+ /**
+ * Applications call this interface method to edit a Subnet object
+ *
+ * @param uuid
+ * identifier of the Subnet object
+ * @param delta
+ * OpenStackSubnet object containing changes to apply
+ * @return boolean on whether the object was updated or not
+ */
+
+ boolean updateSubnet(String uuid, NeutronSubnet delta);
+
+ /**
+ * Applications call this interface method to determine if a Subnet object
+ * is use
+ *
+ * @param subnetUUID
+ * identifier of the subnet object
+ *
+ * @return boolean on whether the subnet is in use or not
+ *
+ * @deprecated - will be removed in Boron
+ */
+
+ boolean subnetInUse(String subnetUUID);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronCRUDInterfaces {
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(NeutronCRUDInterfaces.class);
+
+ private INeutronNetworkCRUD networkInterface;
+ private INeutronSubnetCRUD subnetInterface;
+ private INeutronPortCRUD portInterface;
+ private INeutronRouterCRUD routerInterface;
+ private INeutronFloatingIPCRUD fipInterface;
+ private INeutronSecurityGroupCRUD sgInterface;
+ private INeutronSecurityRuleCRUD srInterface;
+ private INeutronFirewallCRUD fwInterface;
+ private INeutronFirewallPolicyCRUD fwpInterface;
+ private INeutronFirewallRuleCRUD fwrInterface;
+ private INeutronLoadBalancerCRUD lbInterface;
+ private INeutronLoadBalancerPoolCRUD lbpInterface;
+ private INeutronLoadBalancerListenerCRUD lblInterface;
+ private INeutronLoadBalancerHealthMonitorCRUD lbhmInterface;
+ private INeutronLoadBalancerPoolMemberCRUD lbpmInterface;
+ public NeutronCRUDInterfaces() {
+ }
+
+ public INeutronNetworkCRUD getNetworkInterface() {
+ return networkInterface;
+ }
+
+ public INeutronSubnetCRUD getSubnetInterface() {
+ return subnetInterface;
+ }
+
+ public INeutronPortCRUD getPortInterface() {
+ return portInterface;
+ }
+
+ public INeutronRouterCRUD getRouterInterface() {
+ return routerInterface;
+ }
+
+ public INeutronFloatingIPCRUD getFloatingIPInterface() {
+ return fipInterface;
+ }
+
+ public INeutronSecurityGroupCRUD getSecurityGroupInterface() {
+ return sgInterface;
+ }
+
+ public INeutronSecurityRuleCRUD getSecurityRuleInterface() {
+ return srInterface;
+ }
+
+ public INeutronFirewallCRUD getFirewallInterface() {
+ return fwInterface;
+ }
+
+ public INeutronFirewallPolicyCRUD getFirewallPolicyInterface() {
+ return fwpInterface;
+ }
+
+ public INeutronFirewallRuleCRUD getFirewallRuleInterface() {
+ return fwrInterface;
+ }
+
+ public INeutronLoadBalancerCRUD getLoadBalancerInterface() {
+ return lbInterface;
+ }
+
+ public INeutronLoadBalancerPoolCRUD getLoadBalancerPoolInterface() {
+ return lbpInterface;
+ }
+
+ public INeutronLoadBalancerListenerCRUD getLoadBalancerListenerInterface() {
+ return lblInterface;
+ }
+
+ public INeutronLoadBalancerHealthMonitorCRUD getLoadBalancerHealthMonitorInterface() {
+ return lbhmInterface;
+ }
+
+ public INeutronLoadBalancerPoolMemberCRUD getLoadBalancerPoolMemberInterface() {
+ return lbpmInterface;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronNetworkCRUD(Object obj) {
+ networkInterface = (INeutronNetworkCRUD) getInstances(INeutronNetworkCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronSubnetCRUD(Object obj) {
+ subnetInterface = (INeutronSubnetCRUD) getInstances(INeutronSubnetCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronPortCRUD(Object obj) {
+ portInterface = (INeutronPortCRUD) getInstances(INeutronPortCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronRouterCRUD(Object obj) {
+ routerInterface = (INeutronRouterCRUD) getInstances(INeutronRouterCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronFloatingIPCRUD(Object obj) {
+ fipInterface = (INeutronFloatingIPCRUD) getInstances(INeutronFloatingIPCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronSecurityGroupCRUD(Object obj) {
+ sgInterface = (INeutronSecurityGroupCRUD) getInstances(INeutronSecurityGroupCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronSecurityRuleCRUD(Object obj) {
+ srInterface = (INeutronSecurityRuleCRUD) getInstances(INeutronSecurityRuleCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronFirewallCRUD(Object obj) {
+ fwInterface = (INeutronFirewallCRUD) getInstances(INeutronFirewallCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronFirewallPolicyCRUD(Object obj) {
+ fwpInterface = (INeutronFirewallPolicyCRUD) getInstances(INeutronFirewallPolicyCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronFirewallRuleCRUD(Object obj) {
+ fwrInterface = (INeutronFirewallRuleCRUD) getInstances(INeutronFirewallRuleCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronLoadBalancerCRUD(Object obj) {
+ lbInterface = (INeutronLoadBalancerCRUD) getInstances(INeutronLoadBalancerCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronLoadBalancerPoolCRUD(Object obj) {
+ lbpInterface = (INeutronLoadBalancerPoolCRUD) getInstances(INeutronLoadBalancerPoolCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronLoadBalancerListenerCRUD(Object obj) {
+ lblInterface = (INeutronLoadBalancerListenerCRUD) getInstances(INeutronLoadBalancerListenerCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronLoadBalancerHealthMonitorCRUD(Object obj) {
+ lbhmInterface = (INeutronLoadBalancerHealthMonitorCRUD) getInstances(INeutronLoadBalancerHealthMonitorCRUD.class, obj);
+ return this;
+ }
+
+ public NeutronCRUDInterfaces fetchINeutronLoadBalancerPoolMemberCRUD(Object obj) {
+ lbpmInterface = (INeutronLoadBalancerPoolMemberCRUD) getInstances(INeutronLoadBalancerPoolMemberCRUD.class, obj);
+ return this;
+ }
+
+ public Object getInstances(Class<?> clazz, Object bundle) {
+ try {
+ BundleContext bCtx = FrameworkUtil.getBundle(bundle.getClass()).getBundleContext();
+
+ ServiceReference<?>[] services = null;
+ services = bCtx.getServiceReferences(clazz.getName(), null);
+ if (services != null) {
+ return bCtx.getService(services[0]);
+ }
+ } catch (Exception e) {
+ LOGGER.error("Error in getInstances", e);
+ }
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, 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.openstack.netvirt.translator.crud.impl;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.ExecutionException;
+
+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.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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;
+
+
+public abstract class AbstractNeutronInterface<T extends DataObject, S extends INeutronObject> implements AutoCloseable {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractNeutronInterface.class);
+ private static final int DEDASHED_UUID_LENGTH = 32;
+ private static final int DEDASHED_UUID_START = 0;
+ private static final int DEDASHED_UUID_DIV1 = 8;
+ private static final int DEDASHED_UUID_DIV2 = 12;
+ private static final int DEDASHED_UUID_DIV3 = 16;
+ private static final int DEDASHED_UUID_DIV4 = 20;
+
+ private DataBroker db;
+
+ AbstractNeutronInterface(ProviderContext providerContext) {
+ this.db = providerContext.getSALService(DataBroker.class);
+ }
+
+ public DataBroker getDataBroker() {
+ return db;
+ }
+
+ protected abstract InstanceIdentifier<T> createInstanceIdentifier(T item);
+
+ protected abstract T toMd(S neutronObject);
+
+ protected abstract T toMd(String uuid);
+
+ protected <T extends org.opendaylight.yangtools.yang.binding.DataObject> T readMd(InstanceIdentifier<T> path) {
+ T result = null;
+ final ReadOnlyTransaction transaction = getDataBroker().newReadOnlyTransaction();
+ CheckedFuture<Optional<T>, ReadFailedException> future = transaction.read(LogicalDatastoreType.CONFIGURATION, path);
+ if (future != null) {
+ Optional<T> optional;
+ try {
+ optional = future.checkedGet();
+ if (optional.isPresent()) {
+ result = optional.get();
+ }
+ } catch (ReadFailedException e) {
+ LOGGER.warn("Failed to read {}", path, e);
+ }
+ }
+ transaction.close();
+ return result;
+ }
+
+ protected boolean addMd(S neutronObject) {
+ // TODO think about adding existence logic
+ return updateMd(neutronObject);
+ }
+
+ protected boolean updateMd(S neutronObject) {
+ WriteTransaction transaction = getDataBroker().newWriteOnlyTransaction();
+ T item = toMd(neutronObject);
+ InstanceIdentifier<T> iid = createInstanceIdentifier(item);
+ transaction.put(LogicalDatastoreType.CONFIGURATION, iid, item,true);
+ CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+ try {
+ future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.warn("Transation failed ",e);
+ return false;
+ }
+ return true;
+ }
+
+ protected boolean removeMd(T item) {
+ WriteTransaction transaction = getDataBroker().newWriteOnlyTransaction();
+ InstanceIdentifier<T> iid = createInstanceIdentifier(item);
+ transaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+ try {
+ future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.warn("Transation failed ",e);
+ return false;
+ }
+ return true;
+ }
+
+ protected Uuid toUuid(String uuid) {
+ Preconditions.checkNotNull(uuid);
+ Uuid result;
+ try {
+ result = new Uuid(uuid);
+ } catch(IllegalArgumentException e) {
+ // OK... someone didn't follow RFC 4122... lets try this the hard way
+ String dedashed = uuid.replace("-", "");
+ if(dedashed.length() == DEDASHED_UUID_LENGTH) {
+ String redashed = dedashed.substring(DEDASHED_UUID_START, DEDASHED_UUID_DIV1)
+ + "-"
+ + dedashed.substring(DEDASHED_UUID_DIV1, DEDASHED_UUID_DIV2)
+ + "-"
+ + dedashed.substring(DEDASHED_UUID_DIV2, DEDASHED_UUID_DIV3)
+ + "-"
+ + dedashed.substring(DEDASHED_UUID_DIV3, DEDASHED_UUID_DIV4)
+ + "-"
+ + dedashed.substring(DEDASHED_UUID_DIV4, DEDASHED_UUID_LENGTH);
+ result = new Uuid(redashed);
+ } else {
+ throw e;
+ }
+ }
+ return result;
+ }
+
+ // this method uses reflection to update an object from it's delta.
+
+ protected boolean overwrite(Object target, Object delta) {
+ Method[] methods = target.getClass().getMethods();
+
+ for(Method toMethod: methods){
+ if(toMethod.getDeclaringClass().equals(target.getClass())
+ && toMethod.getName().startsWith("set")){
+
+ String toName = toMethod.getName();
+ String fromName = toName.replace("set", "get");
+
+ try {
+ Method fromMethod = delta.getClass().getMethod(fromName);
+ Object value = fromMethod.invoke(delta, (Object[])null);
+ if(value != null){
+ toMethod.invoke(target, value);
+ }
+ } catch (Exception e) {
+ LOGGER.error("Error in overwrite", e);
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void close() throws Exception {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFirewallCRUD;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronFirewallInterface extends AbstractNeutronInterface implements INeutronFirewallCRUD {
+
+ NeutronFirewallInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronFirewallInterface neutronFirewallInterface = new NeutronFirewallInterface(providerContext);
+ ServiceRegistration<INeutronFirewallCRUD> neutronFirewallInterfaceRegistration = context.registerService(INeutronFirewallCRUD.class, neutronFirewallInterface, null);
+ if(neutronFirewallInterfaceRegistration != null) {
+ registrations.add(neutronFirewallInterfaceRegistration);
+ }
+ }
+
+ @Override
+ public boolean neutronFirewallExists(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public NeutronFirewall getNeutronFirewall(String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<NeutronFirewall> getAllNeutronFirewalls() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean addNeutronFirewall(NeutronFirewall input) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean removeNeutronFirewall(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean updateNeutronFirewall(String uuid, NeutronFirewall delta) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean neutronFirewallInUse(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ protected InstanceIdentifier createInstanceIdentifier(DataObject item) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected DataObject toMd(INeutronObject neutronObject) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected DataObject toMd(String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFirewallPolicyCRUD;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ */
+
+public class NeutronFirewallPolicyInterface extends AbstractNeutronInterface implements INeutronFirewallPolicyCRUD {
+
+ NeutronFirewallPolicyInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ @Override
+ public boolean neutronFirewallPolicyExists(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public NeutronFirewallPolicy getNeutronFirewallPolicy(String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<NeutronFirewallPolicy> getAllNeutronFirewallPolicies() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean addNeutronFirewallPolicy(NeutronFirewallPolicy input) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean removeNeutronFirewallPolicy(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean updateNeutronFirewallPolicy(String uuid,
+ NeutronFirewallPolicy delta) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean neutronFirewallPolicyInUse(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ protected InstanceIdentifier createInstanceIdentifier(DataObject item) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected DataObject toMd(INeutronObject neutronObject) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected DataObject toMd(String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronFirewallPolicyInterface neutronFirewallPolicyInterface = new NeutronFirewallPolicyInterface(providerContext);
+ ServiceRegistration<INeutronFirewallPolicyCRUD> neutronFirewallPolicyInterfaceRegistration = context.registerService(INeutronFirewallPolicyCRUD.class, neutronFirewallPolicyInterface, null);
+ if(neutronFirewallPolicyInterfaceRegistration != null) {
+ registrations.add(neutronFirewallPolicyInterfaceRegistration);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFirewallRuleCRUD;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronFirewallRuleInterface extends AbstractNeutronInterface implements INeutronFirewallRuleCRUD {
+
+ NeutronFirewallRuleInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ @Override
+ public boolean neutronFirewallRuleExists(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public NeutronFirewallRule getNeutronFirewallRule(String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<NeutronFirewallRule> getAllNeutronFirewallRules() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean addNeutronFirewallRule(NeutronFirewallRule input) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean removeNeutronFirewallRule(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean updateNeutronFirewallRule(String uuid,
+ NeutronFirewallRule delta) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean neutronFirewallRuleInUse(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ protected InstanceIdentifier createInstanceIdentifier(DataObject item) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected DataObject toMd(INeutronObject neutronObject) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected DataObject toMd(String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronFirewallRuleInterface neutronFirewallRuleInterface = new NeutronFirewallRuleInterface(providerContext);
+ ServiceRegistration<INeutronFirewallRuleCRUD> neutronFirewallRuleInterfaceRegistration = context.registerService(INeutronFirewallRuleCRUD.class, neutronFirewallRuleInterface, null);
+ if(neutronFirewallRuleInterfaceRegistration != null) {
+ registrations.add(neutronFirewallRuleInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.FloatingipBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronFloatingIPInterface extends AbstractNeutronInterface<Floatingip, NeutronFloatingIP> implements INeutronFloatingIPCRUD {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NeutronFloatingIPInterface.class);
+
+ NeutronFloatingIPInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ // IfNBFloatingIPCRUD interface methods
+
+ @Override
+ public boolean floatingIPExists(String uuid) {
+ Floatingip fip = readMd(createInstanceIdentifier(toMd(uuid)));
+ return (fip != null);
+ }
+
+ @Override
+ public NeutronFloatingIP getFloatingIP(String uuid) {
+ Floatingip fip = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (fip == null) {
+ return null;
+ }
+ return fromMd(fip);
+ }
+
+ @Override
+ public List<NeutronFloatingIP> getAllFloatingIPs() {
+ Set<NeutronFloatingIP> allIPs = new HashSet<NeutronFloatingIP>();
+ Floatingips fips = readMd(createInstanceIdentifier());
+ if (fips != null) {
+ for (Floatingip fip: fips.getFloatingip()) {
+ allIPs.add(fromMd(fip));
+ }
+ }
+ LOGGER.debug("Exiting getAllFloatingIPs, Found {} FloatingIPs", allIPs.size());
+ List<NeutronFloatingIP> ans = new ArrayList<NeutronFloatingIP>();
+ ans.addAll(allIPs);
+ return ans;
+ }
+
+ @Override
+ public boolean addFloatingIP(NeutronFloatingIP input) {
+ if (floatingIPExists(input.getID())) {
+ return false;
+ }
+ return addMd(input);
+ }
+
+ @Override
+ public boolean removeFloatingIP(String uuid) {
+ NeutronFloatingIP fip = getFloatingIP(uuid);
+ if (fip == null) {
+ return false;
+ }
+ return removeMd(toMd(uuid));
+ }
+
+ @Override
+ public boolean updateFloatingIP(String uuid, NeutronFloatingIP delta) {
+ NeutronFloatingIP target = getFloatingIP(uuid);
+ if (target == null) {
+ return false;
+ }
+ delta.setPortUUID(target.getPortUUID());
+ delta.setFixedIPAddress(target.getFixedIPAddress());
+ return updateMd(delta);
+ }
+
+ @Override
+ protected Floatingip toMd(String uuid) {
+ FloatingipBuilder floatingipBuilder = new FloatingipBuilder();
+ floatingipBuilder.setUuid(toUuid(uuid));
+ return floatingipBuilder.build();
+ }
+
+ @Override
+ protected Floatingip toMd(NeutronFloatingIP floatingIp) {
+ FloatingipBuilder floatingipBuilder = new FloatingipBuilder();
+ if (floatingIp.getFixedIPAddress() != null) {
+ floatingipBuilder.setFixedIpAddress(new IpAddress(floatingIp.getFixedIPAddress().toCharArray()));
+ }
+ if(floatingIp.getFloatingIPAddress() != null) {
+ floatingipBuilder.setFloatingIpAddress(new IpAddress(floatingIp.getFloatingIPAddress().toCharArray()));
+ }
+ if (floatingIp.getFloatingNetworkUUID() != null) {
+ floatingipBuilder.setFloatingNetworkId(toUuid(floatingIp.getFloatingNetworkUUID()));
+ }
+ if (floatingIp.getPortUUID() != null) {
+ floatingipBuilder.setPortId(toUuid(floatingIp.getPortUUID()));
+ }
+ if (floatingIp.getRouterUUID() != null) {
+ floatingipBuilder.setRouterId(toUuid(floatingIp.getRouterUUID()));
+ }
+ if (floatingIp.getStatus() != null) {
+ floatingipBuilder.setStatus(floatingIp.getStatus());
+ }
+ if (floatingIp.getTenantUUID() != null) {
+ floatingipBuilder.setTenantId(toUuid(floatingIp.getTenantUUID()));
+ }
+ if (floatingIp.getID() != null) {
+ floatingipBuilder.setUuid(toUuid(floatingIp.getID()));
+ }
+ else {
+ LOGGER.warn("Attempting to write neutron floating IP without UUID");
+ }
+ return floatingipBuilder.build();
+ }
+
+ protected NeutronFloatingIP fromMd(Floatingip fip) {
+ NeutronFloatingIP result = new NeutronFloatingIP();
+ result.setID(String.valueOf(fip.getUuid().getValue()));
+ if (fip.getFloatingNetworkId() != null) {
+ result.setFloatingNetworkUUID(String.valueOf(fip.getFloatingNetworkId().getValue()));
+ }
+ if (fip.getPortId() != null) {
+ result.setPortUUID(String.valueOf(fip.getPortId().getValue()));
+ }
+ if (fip.getFixedIpAddress() != null ) {
+ result.setFixedIPAddress(String.valueOf(fip.getFixedIpAddress().getValue()));
+ }
+ if (fip.getFloatingIpAddress() != null) {
+ result.setFloatingIPAddress(String.valueOf(fip.getFloatingIpAddress().getValue()));
+ }
+ if (fip.getTenantId() != null) {
+ result.setTenantUUID(String.valueOf(fip.getTenantId().getValue()));
+ }
+ if (fip.getRouterId() != null) {
+ result.setRouterUUID(String.valueOf(fip.getRouterId().getValue()));
+ }
+ result.setStatus(fip.getStatus());
+ return result;
+ }
+
+ @Override
+ protected InstanceIdentifier<Floatingip> createInstanceIdentifier(
+ Floatingip item) {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Floatingips.class)
+ .child(Floatingip.class,item.getKey());
+ }
+
+ protected InstanceIdentifier<Floatingips> createInstanceIdentifier() {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Floatingips.class);
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+ ServiceRegistration<INeutronFloatingIPCRUD> neutronFloatingIPInterfaceRegistration = context.registerService(INeutronFloatingIPCRUD.class, neutronFloatingIPInterface, null);
+ if (neutronFloatingIPInterfaceRegistration != null) {
+ registrations.add(neutronFloatingIPInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerHealthMonitor;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerHealthMonitorCRUD;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Healthmonitors;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronLoadBalancerHealthMonitorInterface extends AbstractNeutronInterface<Healthmonitors, NeutronLoadBalancerHealthMonitor> implements INeutronLoadBalancerHealthMonitorCRUD {
+
+ NeutronLoadBalancerHealthMonitorInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ @Override
+ public boolean neutronLoadBalancerHealthMonitorExists(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public NeutronLoadBalancerHealthMonitor getNeutronLoadBalancerHealthMonitor(
+ String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<NeutronLoadBalancerHealthMonitor> getAllNeutronLoadBalancerHealthMonitors() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean addNeutronLoadBalancerHealthMonitor(
+ NeutronLoadBalancerHealthMonitor input) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean removeNeutronLoadBalancerHealthMonitor(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean updateNeutronLoadBalancerHealthMonitor(String uuid,
+ NeutronLoadBalancerHealthMonitor delta) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean neutronLoadBalancerHealthMonitorInUse(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ protected InstanceIdentifier<Healthmonitors> createInstanceIdentifier(
+ Healthmonitors item) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Healthmonitors toMd(NeutronLoadBalancerHealthMonitor neutronObject) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Healthmonitors toMd(String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronLoadBalancerHealthMonitorInterface neutronLoadBalancerHealthMonitorInterface = new NeutronLoadBalancerHealthMonitorInterface(providerContext);
+ ServiceRegistration<INeutronLoadBalancerHealthMonitorCRUD> neutronLoadBalancerHealthMonitorInterfaceRegistration = context.registerService(INeutronLoadBalancerHealthMonitorCRUD.class, neutronLoadBalancerHealthMonitorInterface, null);
+ if(neutronLoadBalancerHealthMonitorInterfaceRegistration != null) {
+ registrations.add(neutronLoadBalancerHealthMonitorInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Loadbalancers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.loadbalancers.Loadbalancer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.loadbalancers.LoadbalancerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TODO: Migrate this to consume the MD-SAL data store, so that it can read all the data from data store.
+ * No need to worry about the write/update related methods here. OVSDB net-virt will use these CRUD Interface
+ * only for reading. We will cleanup these interface/methods later.
+ */
+public class NeutronLoadBalancerInterface extends AbstractNeutronInterface<Loadbalancer, NeutronLoadBalancer> implements INeutronLoadBalancerCRUD {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NeutronLoadBalancerInterface.class);
+ private ConcurrentMap<String, NeutronLoadBalancer> loadBalancerDB = new ConcurrentHashMap<String, NeutronLoadBalancer>();
+
+
+ NeutronLoadBalancerInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ @Override
+ public boolean neutronLoadBalancerExists(String uuid) {
+ return loadBalancerDB.containsKey(uuid);
+ }
+
+ @Override
+ public NeutronLoadBalancer getNeutronLoadBalancer(String uuid) {
+ if (!neutronLoadBalancerExists(uuid)) {
+ LOGGER.debug("No LoadBalancer Have Been Defined");
+ return null;
+ }
+ return loadBalancerDB.get(uuid);
+ }
+
+ @Override
+ public List<NeutronLoadBalancer> getAllNeutronLoadBalancers() {
+ Set<NeutronLoadBalancer> allLoadBalancers = new HashSet<NeutronLoadBalancer>();
+ for (Entry<String, NeutronLoadBalancer> entry : loadBalancerDB.entrySet()) {
+ NeutronLoadBalancer loadBalancer = entry.getValue();
+ allLoadBalancers.add(loadBalancer);
+ }
+ LOGGER.debug("Exiting getLoadBalancers, Found {} OpenStackLoadBalancer", allLoadBalancers.size());
+ List<NeutronLoadBalancer> ans = new ArrayList<NeutronLoadBalancer>();
+ ans.addAll(allLoadBalancers);
+ return ans;
+ }
+
+ @Override
+ public boolean addNeutronLoadBalancer(NeutronLoadBalancer input) {
+ if (neutronLoadBalancerExists(input.getID())) {
+ return false;
+ }
+ loadBalancerDB.putIfAbsent(input.getID(), input);
+ //TODO: add code to find INeutronLoadBalancerAware services and call newtorkCreated on them
+ return true;
+ }
+
+ @Override
+ public boolean removeNeutronLoadBalancer(String uuid) {
+ if (!neutronLoadBalancerExists(uuid)) {
+ return false;
+ }
+ loadBalancerDB.remove(uuid);
+ //TODO: add code to find INeutronLoadBalancerAware services and call newtorkDeleted on them
+ return true;
+ }
+
+ @Override
+ public boolean updateNeutronLoadBalancer(String uuid, NeutronLoadBalancer delta) {
+ if (!neutronLoadBalancerExists(uuid)) {
+ return false;
+ }
+ NeutronLoadBalancer target = loadBalancerDB.get(uuid);
+ return overwrite(target, delta);
+ }
+
+ @Override
+ public boolean neutronLoadBalancerInUse(String loadBalancerUUID) {
+ return !neutronLoadBalancerExists(loadBalancerUUID);
+ }
+
+ @Override
+ protected Loadbalancer toMd(String uuid) {
+ LoadbalancerBuilder loadBalancersBuilder = new LoadbalancerBuilder();
+ loadBalancersBuilder.setUuid(toUuid(uuid));
+ return loadBalancersBuilder.build();
+ }
+
+ @Override
+ protected InstanceIdentifier<Loadbalancer> createInstanceIdentifier(
+ Loadbalancer loadBalancer) {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Loadbalancers.class)
+ .child(Loadbalancer.class, loadBalancer.getKey());
+ }
+
+ @Override
+ protected Loadbalancer toMd(NeutronLoadBalancer loadBalancer) {
+ LoadbalancerBuilder loadBalancersBuilder = new LoadbalancerBuilder();
+ loadBalancersBuilder.setAdminStateUp(loadBalancer.getLoadBalancerAdminStateUp());
+ if (loadBalancer.getLoadBalancerDescription() != null) {
+ loadBalancersBuilder.setDescr(loadBalancer.getLoadBalancerDescription());
+ }
+ if (loadBalancer.getLoadBalancerName() != null) {
+ loadBalancersBuilder.setName(loadBalancer.getLoadBalancerName());
+ }
+ if (loadBalancer.getLoadBalancerStatus() != null) {
+ loadBalancersBuilder.setStatus(loadBalancer.getLoadBalancerStatus());
+ }
+ if (loadBalancer.getLoadBalancerTenantID() != null) {
+ loadBalancersBuilder.setTenantId(toUuid(loadBalancer.getLoadBalancerTenantID()));
+ }
+ if (loadBalancer.getLoadBalancerVipAddress() != null) {
+ loadBalancersBuilder.setVipAddress(new IpAddress(loadBalancer.getLoadBalancerVipAddress().toCharArray()));
+ }
+ if (loadBalancer.getLoadBalancerVipSubnetID() != null) {
+ loadBalancersBuilder.setVipSubnetId(toUuid(loadBalancer.getLoadBalancerVipSubnetID()));
+ }
+ if (loadBalancer.getID() != null) {
+ loadBalancersBuilder.setUuid(toUuid(loadBalancer.getID()));
+ } else {
+ LOGGER.warn("Attempting to write neutron load balancer without UUID");
+ }
+ return loadBalancersBuilder.build();
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronLoadBalancerInterface neutronLoadBalancerInterface = new NeutronLoadBalancerInterface(providerContext);
+ ServiceRegistration<INeutronLoadBalancerCRUD> neutronLoadBalancerInterfaceRegistration = context.registerService(INeutronLoadBalancerCRUD.class, neutronLoadBalancerInterface, null);
+ if(neutronLoadBalancerInterfaceRegistration != null) {
+ registrations.add(neutronLoadBalancerInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerListenerCRUD;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Listeners;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronLoadBalancerListenerInterface extends AbstractNeutronInterface<Listeners, NeutronLoadBalancerListener> implements INeutronLoadBalancerListenerCRUD {
+
+ NeutronLoadBalancerListenerInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ @Override
+ public boolean neutronLoadBalancerListenerExists(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public NeutronLoadBalancerListener getNeutronLoadBalancerListener(
+ String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<NeutronLoadBalancerListener> getAllNeutronLoadBalancerListeners() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean addNeutronLoadBalancerListener(
+ NeutronLoadBalancerListener input) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean removeNeutronLoadBalancerListener(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean updateNeutronLoadBalancerListener(String uuid,
+ NeutronLoadBalancerListener delta) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean neutronLoadBalancerListenerInUse(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ protected InstanceIdentifier<Listeners> createInstanceIdentifier(
+ Listeners item) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Listeners toMd(NeutronLoadBalancerListener neutronObject) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Listeners toMd(String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronLoadBalancerListenerInterface neutronLoadBalancerListenerInterface = new NeutronLoadBalancerListenerInterface(providerContext);
+ ServiceRegistration<INeutronLoadBalancerListenerCRUD> neutronLoadBalancerListenerInterfaceRegistration = context.registerService(INeutronLoadBalancerListenerCRUD.class, neutronLoadBalancerListenerInterface, null);
+ if(neutronLoadBalancerListenerInterfaceRegistration != null) {
+ registrations.add(neutronLoadBalancerListenerInterfaceRegistration);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer_SessionPersistence;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_ID;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Pools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.Pool;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.PoolBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.pool.attributes.SessionPersistenceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+/**
+ * TODO: Migrate this to consume the MD-SAL data store, so that it can read all the data from data store.
+ * No need to worry about the write/update related methods here. OVSDB net-virt will use these CRUD Interface
+ * only for reading. We will cleanup these interface/methods later.
+ */
+
+public class NeutronLoadBalancerPoolInterface extends AbstractNeutronInterface<Pool, NeutronLoadBalancerPool> implements INeutronLoadBalancerPoolCRUD {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NeutronLoadBalancerPoolInterface.class);
+ private ConcurrentMap<String, NeutronLoadBalancerPool> loadBalancerPoolDB = new ConcurrentHashMap<String, NeutronLoadBalancerPool>();
+
+ private static final ImmutableBiMap<Class<? extends ProtocolBase>,String> PROTOCOL_MAP
+ = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>,String>()
+ .put(ProtocolHttp.class,"HTTP")
+ .put(ProtocolHttps.class,"HTTPS")
+ .put(ProtocolTcp.class,"TCP")
+ .build();
+
+ NeutronLoadBalancerPoolInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ @Override
+ public boolean neutronLoadBalancerPoolExists(String uuid) {
+ return loadBalancerPoolDB.containsKey(uuid);
+ }
+
+ @Override
+ public NeutronLoadBalancerPool getNeutronLoadBalancerPool(String uuid) {
+ if (!neutronLoadBalancerPoolExists(uuid)) {
+ LOGGER.debug("No LoadBalancerPool has Been Defined");
+ return null;
+ }
+ return loadBalancerPoolDB.get(uuid);
+ }
+
+ @Override
+ public List<NeutronLoadBalancerPool> getAllNeutronLoadBalancerPools() {
+ Set<NeutronLoadBalancerPool> allLoadBalancerPools = new HashSet<NeutronLoadBalancerPool>();
+ for (Entry<String, NeutronLoadBalancerPool> entry : loadBalancerPoolDB.entrySet()) {
+ NeutronLoadBalancerPool loadBalancerPool = entry.getValue();
+ allLoadBalancerPools.add(loadBalancerPool);
+ }
+ LOGGER.debug("Exiting getLoadBalancerPools, Found {} OpenStackLoadBalancerPool", allLoadBalancerPools.size());
+ List<NeutronLoadBalancerPool> ans = new ArrayList<NeutronLoadBalancerPool>();
+ ans.addAll(allLoadBalancerPools);
+ return ans;
+ }
+
+ @Override
+ public boolean addNeutronLoadBalancerPool(NeutronLoadBalancerPool input) {
+ if (neutronLoadBalancerPoolExists(input.getID())) {
+ return false;
+ }
+ loadBalancerPoolDB.putIfAbsent(input.getID(), input);
+ //TODO: add code to find INeutronLoadBalancerPoolAware services and call newtorkCreated on them
+ return true;
+ }
+
+ @Override
+ public boolean removeNeutronLoadBalancerPool(String uuid) {
+ if (!neutronLoadBalancerPoolExists(uuid)) {
+ return false;
+ }
+ loadBalancerPoolDB.remove(uuid);
+ //TODO: add code to find INeutronLoadBalancerPoolAware services and call newtorkDeleted on them
+ return true;
+ }
+
+ @Override
+ public boolean updateNeutronLoadBalancerPool(String uuid, NeutronLoadBalancerPool delta) {
+ if (!neutronLoadBalancerPoolExists(uuid)) {
+ return false;
+ }
+ NeutronLoadBalancerPool target = loadBalancerPoolDB.get(uuid);
+ return overwrite(target, delta);
+ }
+
+ @Override
+ public boolean neutronLoadBalancerPoolInUse(String loadBalancerPoolUUID) {
+ return !neutronLoadBalancerPoolExists(loadBalancerPoolUUID);
+ }
+
+ @Override
+ protected Pool toMd(String uuid) {
+ PoolBuilder poolsBuilder = new PoolBuilder();
+ poolsBuilder.setUuid(toUuid(uuid));
+ return poolsBuilder.build();
+ }
+
+ @Override
+ protected InstanceIdentifier<Pool> createInstanceIdentifier(Pool pools) {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Pools.class)
+ .child(Pool.class, pools.getKey());
+ }
+
+ @Override
+ protected Pool toMd(NeutronLoadBalancerPool pool) {
+ PoolBuilder poolBuilder = new PoolBuilder();
+ poolBuilder.setAdminStateUp(pool.getLoadBalancerPoolAdminIsStateIsUp());
+ if (pool.getLoadBalancerPoolDescription() != null) {
+ poolBuilder.setDescr(pool.getLoadBalancerPoolDescription());
+ }
+ if (pool.getNeutronLoadBalancerPoolHealthMonitorID() != null) {
+ poolBuilder.setHealthmonitorId(toUuid(pool.getNeutronLoadBalancerPoolHealthMonitorID()));
+ }
+ if (pool.getLoadBalancerPoolLbAlgorithm() != null) {
+ poolBuilder.setLbAlgorithm(pool.getLoadBalancerPoolLbAlgorithm());
+ }
+ if (pool.getLoadBalancerPoolListeners() != null) {
+ List<Uuid> listListener = new ArrayList<Uuid>();
+ for (Neutron_ID neutron_id : pool.getLoadBalancerPoolListeners()) {
+ listListener.add(toUuid(neutron_id.getID()));
+ }
+ poolBuilder.setListeners(listListener);
+ }
+ // because members are another container, we don't want to copy
+ // it over, so just skip it here
+ if (pool.getLoadBalancerPoolName() != null) {
+ poolBuilder.setName(pool.getLoadBalancerPoolName());
+ }
+ if (pool.getLoadBalancerPoolProtocol() != null) {
+ ImmutableBiMap<String, Class<? extends ProtocolBase>> mapper =
+ PROTOCOL_MAP.inverse();
+ poolBuilder.setProtocol((Class<? extends ProtocolBase>) mapper.get(pool.getLoadBalancerPoolProtocol()));
+ }
+ if (pool.getLoadBalancerPoolSessionPersistence() != null) {
+ NeutronLoadBalancer_SessionPersistence sessionPersistence = pool.getLoadBalancerPoolSessionPersistence();
+ SessionPersistenceBuilder sessionPersistenceBuilder = new SessionPersistenceBuilder();
+ sessionPersistenceBuilder.setCookieName(sessionPersistence.getCookieName());
+ sessionPersistenceBuilder.setType(sessionPersistence.getType());
+ poolBuilder.setSessionPersistence(sessionPersistenceBuilder.build());
+ }
+ if (pool.getLoadBalancerPoolTenantID() != null) {
+ poolBuilder.setTenantId(toUuid(pool.getLoadBalancerPoolTenantID()));
+ }
+ if (pool.getID() != null) {
+ poolBuilder.setUuid(toUuid(pool.getID()));
+ } else {
+ LOGGER.warn("Attempting to write neutron load balancer pool without UUID");
+ }
+ return poolBuilder.build();
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronLoadBalancerPoolInterface neutronLoadBalancerPoolInterface = new NeutronLoadBalancerPoolInterface(providerContext);
+ ServiceRegistration<INeutronLoadBalancerPoolCRUD> neutronLoadBalancerPoolInterfaceRegistration = context.registerService(INeutronLoadBalancerPoolCRUD.class, neutronLoadBalancerPoolInterface, null);
+ if(neutronLoadBalancerPoolInterfaceRegistration != null) {
+ registrations.add(neutronLoadBalancerPoolInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolMemberCRUD;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.Members;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronLoadBalancerPoolMemberInterface extends
+ AbstractNeutronInterface<Members, NeutronLoadBalancerPoolMember> implements INeutronLoadBalancerPoolMemberCRUD {
+
+ NeutronLoadBalancerPoolMemberInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ @Override
+ public boolean neutronLoadBalancerPoolMemberExists(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public NeutronLoadBalancerPoolMember getNeutronLoadBalancerPoolMember(
+ String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<NeutronLoadBalancerPoolMember> getAllNeutronLoadBalancerPoolMembers() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean addNeutronLoadBalancerPoolMember(
+ NeutronLoadBalancerPoolMember input) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean removeNeutronLoadBalancerPoolMember(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean updateNeutronLoadBalancerPoolMember(String uuid,
+ NeutronLoadBalancerPoolMember delta) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean neutronLoadBalancerPoolMemberInUse(String uuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ protected InstanceIdentifier<Members> createInstanceIdentifier(Members item) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Members toMd(NeutronLoadBalancerPoolMember neutronObject) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Members toMd(String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronLoadBalancerPoolMemberInterface neutronLoadBalancerPoolMemberInterface = new NeutronLoadBalancerPoolMemberInterface(providerContext);
+ ServiceRegistration<INeutronLoadBalancerPoolMemberCRUD> neutronLoadBalancerPoolMemberInterfaceRegistration = context.registerService(INeutronLoadBalancerPoolMemberCRUD.class, neutronLoadBalancerPoolMemberInterface, null);
+ if(neutronLoadBalancerPoolMemberInterfaceRegistration != null) {
+ registrations.add(neutronLoadBalancerPoolMemberInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork_Segment;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3Extension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3ExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.SegmentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronNetworkInterface extends AbstractNeutronInterface<Network,NeutronNetwork> implements INeutronNetworkCRUD {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NeutronNetworkInterface.class);
+
+ private static final ImmutableBiMap<Class<? extends NetworkTypeBase>,String> NETWORK_MAP
+ = new ImmutableBiMap.Builder<Class<? extends NetworkTypeBase>,String>()
+ .put(NetworkTypeFlat.class,"flat")
+ .put(NetworkTypeGre.class,"gre")
+ .put(NetworkTypeVlan.class,"vlan")
+ .put(NetworkTypeVxlan.class,"vxlan")
+ .build();
+
+ NeutronNetworkInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ // IfNBNetworkCRUD methods
+
+ @Override
+ public boolean networkExists(String uuid) {
+ Network network = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (network == null) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public NeutronNetwork getNetwork(String uuid) {
+ Network network = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (network == null) {
+ return null;
+ }
+ return fromMd(network);
+ }
+
+ @Override
+ public List<NeutronNetwork> getAllNetworks() {
+ Set<NeutronNetwork> allNetworks = new HashSet<NeutronNetwork>();
+ Networks networks = readMd(createInstanceIdentifier());
+ if (networks != null) {
+ for (Network network: networks.getNetwork()) {
+ allNetworks.add(fromMd(network));
+ }
+ }
+ LOGGER.debug("Exiting getAllNetworks, Found {} OpenStackNetworks", allNetworks.size());
+ List<NeutronNetwork> ans = new ArrayList<NeutronNetwork>();
+ ans.addAll(allNetworks);
+ return ans;
+ }
+
+ @Override
+ public boolean addNetwork(NeutronNetwork input) {
+ if (networkExists(input.getID())) {
+ return false;
+ }
+ addMd(input);
+ return true;
+ }
+
+ @Override
+ public boolean removeNetwork(String uuid) {
+ if (!networkExists(uuid)) {
+ return false;
+ }
+ return removeMd(toMd(uuid));
+ }
+
+ @Override
+ public boolean updateNetwork(String uuid, NeutronNetwork delta) {
+ if (!networkExists(uuid)) {
+ return false;
+ }
+/* note: because what we get is *not* a delta but (at this point) the updated
+ * object, this is much simpler - just replace the value and update the mdsal
+ * with it */
+ updateMd(delta);
+ return true;
+ }
+
+ @Override
+ public boolean networkInUse(String netUUID) {
+ if (!networkExists(netUUID)) {
+ return true;
+ }
+ return false;
+ }
+
+ protected NeutronNetwork fromMd(Network network) {
+ NeutronNetwork result = new NeutronNetwork();
+ result.setAdminStateUp(network.isAdminStateUp());
+ result.setNetworkName(network.getName());
+ result.setShared(network.isShared());
+ result.setStatus(network.getStatus());
+ if (network.getSubnets() != null) {
+ List<String> neutronSubnets = new ArrayList<String>();
+ for( Uuid subnet : network.getSubnets()) {
+ neutronSubnets.add(subnet.getValue());
+ }
+ result.setSubnets(neutronSubnets);
+ }
+// todo remove '-' chars as tenant id doesn't use them
+ result.setTenantID(network.getTenantId().getValue());
+ result.setID(network.getUuid().getValue());
+
+ NetworkL3Extension l3Extension = network.getAugmentation(NetworkL3Extension.class);
+ result.setRouterExternal(l3Extension.isExternal());
+
+ NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+ result.setProviderPhysicalNetwork(providerExtension.getPhysicalNetwork());
+ result.setProviderSegmentationID(providerExtension.getSegmentationId());
+ result.setProviderNetworkType(NETWORK_MAP.get(providerExtension.getNetworkType()));
+ List<NeutronNetwork_Segment> segments = new ArrayList<NeutronNetwork_Segment>();
+ if (providerExtension.getSegments() != null) {
+ for (Segments segment: providerExtension.getSegments()) {
+ NeutronNetwork_Segment neutronSegment = new NeutronNetwork_Segment();
+ neutronSegment.setProviderPhysicalNetwork(segment.getPhysicalNetwork());
+ neutronSegment.setProviderSegmentationID(segment.getSegmentationId());
+ neutronSegment.setProviderNetworkType(NETWORK_MAP.get(segment.getNetworkType()));
+ segments.add(neutronSegment);
+ }
+ }
+ result.setSegments(segments);
+ return result;
+ }
+
+ private void fillExtensions(NetworkBuilder networkBuilder,
+ NeutronNetwork network) {
+ NetworkL3ExtensionBuilder l3ExtensionBuilder = new NetworkL3ExtensionBuilder();
+ if (network.getRouterExternal() != null) {
+ l3ExtensionBuilder.setExternal(network.getRouterExternal());
+ }
+
+ NetworkProviderExtensionBuilder providerExtensionBuilder = new NetworkProviderExtensionBuilder();
+ if (network.getProviderPhysicalNetwork() != null) {
+ providerExtensionBuilder.setPhysicalNetwork(network.getProviderPhysicalNetwork());
+ }
+ if (network.getProviderSegmentationID() != null) {
+ providerExtensionBuilder.setSegmentationId(network.getProviderSegmentationID());
+ }
+ if (network.getProviderNetworkType() != null) {
+ ImmutableBiMap<String, Class<? extends NetworkTypeBase>> mapper =
+ NETWORK_MAP.inverse();
+ providerExtensionBuilder.setNetworkType((Class<? extends NetworkTypeBase>) mapper.get(network.getProviderNetworkType()));
+ }
+ if (network.getSegments() != null) {
+ List<Segments> segments = new ArrayList<Segments>();
+ long count = 0;
+ for( NeutronNetwork_Segment segment : network.getSegments()) {
+ count++;
+ SegmentsBuilder segmentsBuilder = new SegmentsBuilder();
+ if (segment.getProviderPhysicalNetwork() != null) {
+ segmentsBuilder.setPhysicalNetwork(segment.getProviderPhysicalNetwork());
+ }
+ if (segment.getProviderSegmentationID() != null) {
+ segmentsBuilder.setSegmentationId(segment.getProviderSegmentationID());
+ }
+ if (segment.getProviderNetworkType() != null) {
+ ImmutableBiMap<String, Class<? extends NetworkTypeBase>> mapper =
+ NETWORK_MAP.inverse();
+ segmentsBuilder.setNetworkType((Class<? extends NetworkTypeBase>) mapper.get(segment.getProviderNetworkType()));
+ }
+ segmentsBuilder.setSegmentationIndex(Long.valueOf(count));
+ segments.add(segmentsBuilder.build());
+ }
+ providerExtensionBuilder.setSegments(segments);
+ }
+ if (network.getProviderSegmentationID() != null) {
+ providerExtensionBuilder.setSegmentationId(network.getProviderSegmentationID());
+ }
+
+ networkBuilder.addAugmentation(NetworkL3Extension.class,
+ l3ExtensionBuilder.build());
+ networkBuilder.addAugmentation(NetworkProviderExtension.class,
+ providerExtensionBuilder.build());
+ }
+
+ protected Network toMd(NeutronNetwork network) {
+ NetworkBuilder networkBuilder = new NetworkBuilder();
+ fillExtensions(networkBuilder, network);
+
+ networkBuilder.setAdminStateUp(network.getAdminStateUp());
+ if (network.getNetworkName() != null) {
+ networkBuilder.setName(network.getNetworkName());
+ }
+ if (network.getShared() != null) {
+ networkBuilder.setShared(network.getShared());
+ }
+ if (network.getStatus() != null) {
+ networkBuilder.setStatus(network.getStatus());
+ }
+ if (network.getSubnets() != null) {
+ List<Uuid> subnets = new ArrayList<Uuid>();
+ for( String subnet : network.getSubnets()) {
+ subnets.add(toUuid(subnet));
+ }
+ networkBuilder.setSubnets(subnets);
+ }
+ if (network.getTenantID() != null) {
+ networkBuilder.setTenantId(toUuid(network.getTenantID()));
+ }
+ if (network.getNetworkUUID() != null) {
+ networkBuilder.setUuid(toUuid(network.getNetworkUUID()));
+ } else {
+ LOGGER.warn("Attempting to write neutron network without UUID");
+ }
+ return networkBuilder.build();
+ }
+
+ protected Network toMd(String uuid) {
+ NetworkBuilder networkBuilder = new NetworkBuilder();
+ networkBuilder.setUuid(toUuid(uuid));
+ return networkBuilder.build();
+ }
+
+ @Override
+ protected InstanceIdentifier<Network> createInstanceIdentifier(Network network) {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Networks.class)
+ .child(Network.class,network.getKey());
+ }
+
+ protected InstanceIdentifier<Networks> createInstanceIdentifier() {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Networks.class);
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronNetworkInterface neutronNetworkInterface = new NeutronNetworkInterface(providerContext);
+ ServiceRegistration<INeutronNetworkCRUD> neutronNetworkInterfaceRegistration = context.registerService(INeutronNetworkCRUD.class, neutronNetworkInterface, null);
+ if(neutronNetworkInterfaceRegistration != null) {
+ registrations.add(neutronNetworkInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_AllowedAddressPairs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_ExtraDHCPOption;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_VIFDetail;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetailsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOpts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOptsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronPortInterface extends AbstractNeutronInterface<Port, NeutronPort> implements INeutronPortCRUD {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NeutronPortInterface.class);
+
+ NeutronPortInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ // IfNBPortCRUD methods
+
+ @Override
+ public boolean portExists(String uuid) {
+ Port port = readMd(createInstanceIdentifier(toMd(uuid)));
+ return port != null;
+ }
+
+ @Override
+ public NeutronPort getPort(String uuid) {
+ Port port = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (port == null) {
+ return null;
+ }
+ return fromMd(port);
+ }
+
+ @Override
+ public List<NeutronPort> getAllPorts() {
+ Set<NeutronPort> allPorts = new HashSet<NeutronPort>();
+ Ports ports = readMd(createInstanceIdentifier());
+ if (ports != null) {
+ for (Port port : ports.getPort()) {
+ allPorts.add(fromMd(port));
+ }
+ }
+ LOGGER.debug("Exiting getAllPorts, Found {} OpenStackPorts", allPorts.size());
+ List<NeutronPort> ans = new ArrayList<NeutronPort>();
+ ans.addAll(allPorts);
+ return ans;
+ }
+
+ @Override
+ public boolean addPort(NeutronPort input) {
+ if (portExists(input.getID())) {
+ return false;
+ }
+ addMd(input);
+ return true;
+ }
+
+ @Override
+ public boolean removePort(String uuid) {
+ if (!portExists(uuid)) {
+ return false;
+ }
+ return removeMd(toMd(uuid));
+ }
+
+ @Override
+ public boolean updatePort(String uuid, NeutronPort delta) {
+ if (!portExists(uuid)) {
+ return false;
+ }
+ updateMd(delta);
+ return true;
+ }
+
+ // @deprecated, will be removed in Boron
+ @Override
+ public boolean macInUse(String macAddress) {
+ return false;
+ }
+
+ // @deprecated, will be removed in Boron
+ @Override
+ public NeutronPort getGatewayPort(String subnetUUID) {
+ return null;
+ }
+
+ @Override
+ protected InstanceIdentifier<Port> createInstanceIdentifier(Port port) {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Ports.class)
+ .child(Port.class, port.getKey());
+ }
+
+ protected InstanceIdentifier<Ports> createInstanceIdentifier() {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Ports.class);
+ }
+
+ protected void addExtensions(Port port, NeutronPort result) {
+ PortBindingExtension binding = port.getAugmentation(PortBindingExtension.class);
+ result.setBindinghostID(binding.getHostId());
+ if (binding.getVifDetails() != null) {
+ List<NeutronPort_VIFDetail> details = new ArrayList<NeutronPort_VIFDetail>();
+ for (VifDetails vifDetail : binding.getVifDetails()) {
+ NeutronPort_VIFDetail detail = new NeutronPort_VIFDetail();
+ detail.setPortFilter(vifDetail.isPortFilter());
+ detail.setOvsHybridPlug(vifDetail.isOvsHybridPlug());
+ details.add(detail);
+ }
+ result.setVIFDetail(details);
+ }
+ result.setBindingvifType(binding.getVifType());
+ result.setBindingvnicType(binding.getVnicType());
+ }
+
+ protected NeutronPort fromMd(Port port) {
+ NeutronPort result = new NeutronPort();
+ result.setAdminStateUp(port.isAdminStateUp());
+ if (port.getAllowedAddressPairs() != null) {
+ List<NeutronPort_AllowedAddressPairs> pairs = new ArrayList<NeutronPort_AllowedAddressPairs>();
+ for (AllowedAddressPairs mdPair : port.getAllowedAddressPairs()) {
+ NeutronPort_AllowedAddressPairs pair = new NeutronPort_AllowedAddressPairs();
+ pair.setIpAddress(mdPair.getIpAddress());
+ pair.setMacAddress(mdPair.getMacAddress());
+ pair.setPortID(mdPair.getPortId());
+ pairs.add(pair);
+ }
+ result.setAllowedAddressPairs(pairs);
+ }
+ result.setDeviceID(port.getDeviceId());
+ result.setDeviceOwner(port.getDeviceOwner());
+ if (port.getExtraDhcpOpts() != null) {
+ List<NeutronPort_ExtraDHCPOption> options = new ArrayList<NeutronPort_ExtraDHCPOption>();
+ for (ExtraDhcpOpts opt : port.getExtraDhcpOpts()) {
+ NeutronPort_ExtraDHCPOption arg = new NeutronPort_ExtraDHCPOption();
+ arg.setName(opt.getOptName());
+ arg.setValue(opt.getOptValue());
+ options.add(arg);
+ }
+ result.setExtraDHCPOptions(options);
+ }
+ if (port.getFixedIps() != null) {
+ List<Neutron_IPs> ips = new ArrayList<Neutron_IPs>();
+ for (FixedIps mdIP : port.getFixedIps()) {
+ Neutron_IPs ip = new Neutron_IPs();
+ ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
+ ip.setSubnetUUID(mdIP.getSubnetId().getValue());
+ ips.add(ip);
+ }
+ result.setFixedIPs(ips);
+ }
+ result.setMacAddress(port.getMacAddress());
+ result.setName(port.getName());
+ result.setNetworkUUID(String.valueOf(port.getNetworkId().getValue()));
+ if (port.getSecurityGroups() != null) {
+ Set<NeutronSecurityGroup> allGroups = new HashSet<NeutronSecurityGroup>();
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces().fetchINeutronSecurityGroupCRUD(this);
+ INeutronSecurityGroupCRUD sgIf = interfaces.getSecurityGroupInterface();
+ for (Uuid sgUuid : port.getSecurityGroups()) {
+ allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+ }
+ List<NeutronSecurityGroup> groups = new ArrayList<NeutronSecurityGroup>();
+ groups.addAll(allGroups);
+ result.setSecurityGroups(groups);
+ }
+ result.setStatus(port.getStatus());
+ if (port.getTenantId() != null) {
+ result.setTenantID(String.valueOf(port.getTenantId().getValue()).replace("-", ""));
+ }
+ result.setPortUUID(String.valueOf(port.getUuid().getValue()));
+ addExtensions(port, result);
+ return result;
+ }
+
+ @Override
+ protected Port toMd(NeutronPort neutronPort) {
+ PortBindingExtensionBuilder bindingBuilder = new PortBindingExtensionBuilder();
+ if (neutronPort.getBindinghostID() != null) {
+ bindingBuilder.setHostId(neutronPort.getBindinghostID());
+ }
+ if (neutronPort.getVIFDetail() != null) {
+ List<VifDetails> listVifDetail = new ArrayList<VifDetails>();
+ for (NeutronPort_VIFDetail detail: neutronPort.getVIFDetail()) {
+ VifDetailsBuilder vifDetailsBuilder = new VifDetailsBuilder();
+ if (detail.getPortFilter() != null) {
+ vifDetailsBuilder.setPortFilter(detail.getPortFilter());
+ }
+ if (detail.getOvsHybridPlug() != null) {
+ vifDetailsBuilder.setOvsHybridPlug(detail.getOvsHybridPlug());
+ }
+ listVifDetail.add(vifDetailsBuilder.build());
+ }
+ bindingBuilder.setVifDetails(listVifDetail);
+ }
+ if (neutronPort.getBindingvifType() != null) {
+ bindingBuilder.setVifType(neutronPort.getBindingvifType());
+ }
+ if (neutronPort.getBindingvnicType() != null) {
+ bindingBuilder.setVnicType(neutronPort.getBindingvnicType());
+ }
+
+ PortBuilder portBuilder = new PortBuilder();
+ portBuilder.addAugmentation(PortBindingExtension.class,
+ bindingBuilder.build());
+ portBuilder.setAdminStateUp(neutronPort.isAdminStateUp());
+ if(neutronPort.getAllowedAddressPairs() != null) {
+ List<AllowedAddressPairs> listAllowedAddressPairs = new ArrayList<AllowedAddressPairs>();
+ for (NeutronPort_AllowedAddressPairs allowedAddressPairs : neutronPort.getAllowedAddressPairs()) {
+ AllowedAddressPairsBuilder allowedAddressPairsBuilder = new AllowedAddressPairsBuilder();
+ allowedAddressPairsBuilder.setIpAddress(allowedAddressPairs.getIpAddress());
+ allowedAddressPairsBuilder.setMacAddress(allowedAddressPairs.getMacAddress());
+ allowedAddressPairsBuilder.setPortId(allowedAddressPairs.getPortID());
+ listAllowedAddressPairs.add(allowedAddressPairsBuilder.build());
+ }
+ portBuilder.setAllowedAddressPairs(listAllowedAddressPairs);
+ }
+ if (neutronPort.getDeviceID() != null) {
+ portBuilder.setDeviceId(neutronPort.getDeviceID());
+ }
+ if (neutronPort.getDeviceOwner() != null) {
+ portBuilder.setDeviceOwner(neutronPort.getDeviceOwner());
+ }
+ if (neutronPort.getExtraDHCPOptions() != null) {
+ List<ExtraDhcpOpts> listExtraDHCPOptions = new ArrayList<ExtraDhcpOpts>();
+ for (NeutronPort_ExtraDHCPOption extraDHCPOption : neutronPort.getExtraDHCPOptions()) {
+ ExtraDhcpOptsBuilder extraDHCPOptsBuilder = new ExtraDhcpOptsBuilder();
+ extraDHCPOptsBuilder.setOptName(extraDHCPOption.getName());
+ extraDHCPOptsBuilder.setOptValue(extraDHCPOption.getValue());
+ listExtraDHCPOptions.add(extraDHCPOptsBuilder.build());
+ }
+ portBuilder.setExtraDhcpOpts(listExtraDHCPOptions);
+ }
+ if (neutronPort.getFixedIPs() != null) {
+ List<FixedIps> listNeutronIPs = new ArrayList<FixedIps>();
+ for (Neutron_IPs neutron_IPs : neutronPort.getFixedIPs()) {
+ FixedIpsBuilder fixedIpsBuilder = new FixedIpsBuilder();
+ fixedIpsBuilder.setIpAddress(new IpAddress(neutron_IPs.getIpAddress().toCharArray()));
+ fixedIpsBuilder.setSubnetId(toUuid(neutron_IPs.getSubnetUUID()));
+ listNeutronIPs.add(fixedIpsBuilder.build());
+ }
+ portBuilder.setFixedIps(listNeutronIPs);
+ }
+ if (neutronPort.getMacAddress() != null) {
+ portBuilder.setMacAddress(neutronPort.getMacAddress());
+ }
+ if (neutronPort.getName() != null) {
+ portBuilder.setName(neutronPort.getName());
+ }
+ if (neutronPort.getNetworkUUID() != null) {
+ portBuilder.setNetworkId(toUuid(neutronPort.getNetworkUUID()));
+ }
+ if (neutronPort.getSecurityGroups() != null) {
+ List<Uuid> listSecurityGroups = new ArrayList<Uuid>();
+ for (NeutronSecurityGroup neutronSecurityGroup : neutronPort.getSecurityGroups()) {
+ listSecurityGroups.add(toUuid(neutronSecurityGroup.getID()));
+ }
+ portBuilder.setSecurityGroups(listSecurityGroups);
+ }
+ if (neutronPort.getStatus() != null) {
+ portBuilder.setStatus(neutronPort.getStatus());
+ }
+ if (neutronPort.getTenantID() != null) {
+ portBuilder.setTenantId(toUuid(neutronPort.getTenantID()));
+ }
+ if (neutronPort.getPortUUID() != null) {
+ portBuilder.setUuid(toUuid(neutronPort.getPortUUID()));
+ } else {
+ LOGGER.warn("Attempting to write neutron port without UUID");
+ }
+ return portBuilder.build();
+ }
+
+ @Override
+ protected Port toMd(String uuid) {
+ PortBuilder portBuilder = new PortBuilder();
+ portBuilder.setUuid(toUuid(uuid));
+ return portBuilder.build();
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronPortInterface neutronPortInterface = new NeutronPortInterface(providerContext);
+ ServiceRegistration<INeutronPortCRUD> neutronPortInterfaceRegistration = context.registerService(INeutronPortCRUD.class, neutronPortInterface, null);
+ if(neutronPortInterfaceRegistration != null) {
+ registrations.add(neutronPortInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_NetworkReference;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronRouterCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.ExternalGatewayInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.ExternalGatewayInfoBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronRouterInterface extends AbstractNeutronInterface<Router, NeutronRouter> implements INeutronRouterCRUD {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NeutronRouterInterface.class);
+ // methods needed for creating caches
+
+
+ NeutronRouterInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+
+ // IfNBRouterCRUD Interface methods
+
+ @Override
+ public boolean routerExists(String uuid) {
+ Router router = readMd(createInstanceIdentifier(toMd(uuid)));
+ return router != null;
+ }
+
+ @Override
+ public NeutronRouter getRouter(String uuid) {
+ Router router = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (router == null) {
+ return null;
+ }
+ return fromMd(router);
+ }
+
+ @Override
+ public List<NeutronRouter> getAllRouters() {
+ Set<NeutronRouter> allRouters = new HashSet<NeutronRouter>();
+ Routers routers = readMd(createInstanceIdentifier());
+ if (routers != null) {
+ for (Router router: routers.getRouter()) {
+ allRouters.add(fromMd(router));
+ }
+ }
+ LOGGER.debug("Exiting getAllRouters, Found {} Routers", allRouters.size());
+ List<NeutronRouter> ans = new ArrayList<NeutronRouter>();
+ ans.addAll(allRouters);
+ return ans;
+ }
+
+ @Override
+ public boolean addRouter(NeutronRouter input) {
+ if (routerExists(input.getID())) {
+ return false;
+ }
+ addMd(input);
+ return true;
+ }
+
+ @Override
+ public boolean removeRouter(String uuid) {
+ if (!routerExists(uuid)) {
+ return false;
+ }
+ return removeMd(toMd(uuid));
+ }
+
+ @Override
+ public boolean updateRouter(String uuid, NeutronRouter delta) {
+ if (!routerExists(uuid)) {
+ return false;
+ }
+ updateMd(delta);
+ return true;
+ }
+
+ @Override
+ public boolean routerInUse(String routerUUID) {
+ if (!routerExists(routerUUID)) {
+ return true;
+ }
+ NeutronRouter target = getRouter(routerUUID);
+ return (target.getInterfaces().size() > 0);
+ }
+
+ @Override
+ protected Router toMd(NeutronRouter router) {
+
+ RouterBuilder routerBuilder = new RouterBuilder();
+
+ if (router.getRouterUUID() != null) {
+ routerBuilder.setUuid(toUuid(router.getRouterUUID()));
+ }
+ if (router.getName() != null) {
+ routerBuilder.setName(router.getName());
+ }
+ if (router.getTenantID() != null && !router.getTenantID().isEmpty()) {
+ routerBuilder.setTenantId(toUuid(router.getTenantID()));
+ }
+ if (router.getStatus() != null) {
+ routerBuilder.setStatus(router.getStatus());
+ }
+ if (router.getGatewayPortId() != null && !router.getGatewayPortId().isEmpty()) {
+ routerBuilder.setGatewayPortId(toUuid(router.getGatewayPortId()));
+ }
+ routerBuilder.setAdminStateUp(router.getAdminStateUp());
+ routerBuilder.setDistributed(router.getDistributed());
+ if (router.getRoutes() != null) {
+ List<String> routes = new ArrayList<String>();
+ for (String route : router.getRoutes()) {
+ routes.add(route);
+ }
+ routerBuilder.setRoutes(routes);
+ }
+ if (router.getExternalGatewayInfo() != null) {
+ ExternalGatewayInfo externalGatewayInfo = null;
+ List<NeutronRouter_NetworkReference> neutronRouter_NetworkReferences = new ArrayList<NeutronRouter_NetworkReference>();
+ neutronRouter_NetworkReferences.add(router.getExternalGatewayInfo());
+ for (NeutronRouter_NetworkReference externalGatewayInfos : neutronRouter_NetworkReferences) {
+ ExternalGatewayInfoBuilder builder = new ExternalGatewayInfoBuilder();
+ builder.setEnableSnat(externalGatewayInfos.getEnableSNAT());
+ builder.setExternalNetworkId(toUuid(externalGatewayInfos.getNetworkID()));
+ if (externalGatewayInfos.getExternalFixedIPs() != null) {
+ List<ExternalFixedIps> externalFixedIps = new ArrayList<ExternalFixedIps>();
+ for (Neutron_IPs eIP : externalGatewayInfos.getExternalFixedIPs()) {
+ ExternalFixedIpsBuilder eFixedIpBuilder = new ExternalFixedIpsBuilder();
+ eFixedIpBuilder.setIpAddress(new IpAddress(eIP.getIpAddress().toCharArray()));
+ eFixedIpBuilder.setSubnetId(toUuid(eIP.getSubnetUUID()));
+ externalFixedIps.add(eFixedIpBuilder.build());
+ }
+ builder.setExternalFixedIps(externalFixedIps);
+ }
+ externalGatewayInfo = builder.build();
+ }
+ routerBuilder.setExternalGatewayInfo(externalGatewayInfo);
+ }
+ if (router.getInterfaces() != null) {
+ Map<String, NeutronRouter_Interface> mapInterfaces = new HashMap<String, NeutronRouter_Interface>();
+ List<Interfaces> interfaces = new ArrayList<Interfaces>();
+ for (Entry<String, NeutronRouter_Interface> entry : mapInterfaces.entrySet()) {
+ interfaces.add((Interfaces) entry.getValue());
+ }
+ routerBuilder.setInterfaces(interfaces);
+ }
+ if (router.getID() != null) {
+ routerBuilder.setUuid(toUuid(router.getID()));
+ } else {
+ LOGGER.warn("Attempting to write neutron router without UUID");
+ }
+ return routerBuilder.build();
+ }
+
+ @Override
+ protected InstanceIdentifier<Router> createInstanceIdentifier(Router router) {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Routers.class)
+ .child(Router.class, router.getKey());
+ }
+
+ protected InstanceIdentifier<Routers> createInstanceIdentifier() {
+ return InstanceIdentifier.create(Neutron.class).child(Routers.class);
+ }
+
+ @Override
+ protected Router toMd(String uuid) {
+ RouterBuilder routerBuilder = new RouterBuilder();
+ routerBuilder.setUuid(toUuid(uuid));
+ return routerBuilder.build();
+ }
+
+ public NeutronRouter fromMd(Router router) {
+ NeutronRouter result = new NeutronRouter();
+ result.setID(String.valueOf(router.getUuid().getValue()));
+ result.setName(router.getName());
+ result.setTenantID(String.valueOf(router.getTenantId().getValue()));
+ result.setAdminStateUp(router.isAdminStateUp());
+ result.setStatus(router.getStatus());
+ result.setDistributed(router.isDistributed());
+ if (router.getGatewayPortId() != null) {
+ result.setGatewayPortId(String.valueOf(router.getGatewayPortId().getValue()));
+ }
+ if (router.getRoutes() != null) {
+ List<String> routes = new ArrayList<String>();
+ for (String route : router.getRoutes()) {
+ routes.add(route);
+ }
+ result.setRoutes(routes);
+ }
+
+ if (router.getExternalGatewayInfo() != null) {
+ NeutronRouter_NetworkReference extGwInfo = new NeutronRouter_NetworkReference();
+ extGwInfo.setNetworkID(String.valueOf(router.getExternalGatewayInfo().getExternalNetworkId().getValue()));
+ extGwInfo.setEnableSNAT(router.getExternalGatewayInfo().isEnableSnat());
+ if (router.getExternalGatewayInfo().getExternalFixedIps() != null) {
+ List<Neutron_IPs> fixedIPs = new ArrayList<Neutron_IPs>();
+ for (ExternalFixedIps mdFixedIP : router.getExternalGatewayInfo().getExternalFixedIps()) {
+ Neutron_IPs fixedIP = new Neutron_IPs();
+ fixedIP.setSubnetUUID(String.valueOf(mdFixedIP.getSubnetId().getValue()));
+ fixedIP.setIpAddress(String.valueOf(mdFixedIP.getIpAddress().getValue()));
+ fixedIPs.add(fixedIP);
+ }
+ extGwInfo.setExternalFixedIPs(fixedIPs);
+ }
+ result.setExternalGatewayInfo(extGwInfo);
+ }
+
+ if (router.getInterfaces() != null) {
+ Map<String, NeutronRouter_Interface> interfaces = new HashMap<String, NeutronRouter_Interface>();
+ for (Interfaces mdInterface : router.getInterfaces()) {
+ NeutronRouter_Interface pojoInterface = new NeutronRouter_Interface();
+ String id = String.valueOf(mdInterface.getUuid().getValue());
+ pojoInterface.setID(id);
+ pojoInterface.setTenantID(String.valueOf(mdInterface.getTenantId().getValue()));
+ pojoInterface.setSubnetUUID(String.valueOf(mdInterface.getSubnetId().getValue()));
+ pojoInterface.setPortUUID(String.valueOf(mdInterface.getPortId().getValue()));
+ interfaces.put(id, pojoInterface);
+ }
+ result.setInterfaces(interfaces);
+ }
+ return result;
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronRouterInterface neutronRouterInterface = new NeutronRouterInterface(providerContext);
+ ServiceRegistration<INeutronRouterCRUD> neutronRouterInterfaceRegistration = context.registerService(INeutronRouterCRUD.class, neutronRouterInterface, null);
+ if(neutronRouterInterfaceRegistration != null) {
+ registrations.add(neutronRouterInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroups;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroupBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class NeutronSecurityGroupInterface extends AbstractNeutronInterface<SecurityGroup,NeutronSecurityGroup> implements INeutronSecurityGroupCRUD {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NeutronSecurityGroupInterface.class);
+
+ NeutronSecurityGroupInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ @Override
+ public boolean neutronSecurityGroupExists(String uuid) {
+ SecurityGroup group = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (group == null) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public NeutronSecurityGroup getNeutronSecurityGroup(String uuid) {
+ SecurityGroup group = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (group == null) {
+ return null;
+ }
+ return fromMd(group);
+ }
+
+ @Override
+ public List<NeutronSecurityGroup> getAllNeutronSecurityGroups() {
+ Set<NeutronSecurityGroup> allSecurityGroups = new HashSet<NeutronSecurityGroup>();
+ SecurityGroups groups = readMd(createInstanceIdentifier());
+ if (groups != null) {
+ for (SecurityGroup group: groups.getSecurityGroup()) {
+ allSecurityGroups.add(fromMd(group));
+ }
+ }
+ LOGGER.debug("Exiting getSecurityGroups, Found {} OpenStackSecurityGroup", allSecurityGroups.size());
+ List<NeutronSecurityGroup> ans = new ArrayList<NeutronSecurityGroup>();
+ ans.addAll(allSecurityGroups);
+ return ans;
+ }
+
+ @Override
+ public boolean addNeutronSecurityGroup(NeutronSecurityGroup input) {
+ if (neutronSecurityGroupExists(input.getID())) {
+ return false;
+ }
+ addMd(input);
+ return true;
+ }
+
+ @Override
+ public boolean removeNeutronSecurityGroup(String uuid) {
+ if (!neutronSecurityGroupExists(uuid)) {
+ return false;
+ }
+ removeMd(toMd(uuid));
+ return true;
+ }
+
+ @Override
+ public boolean updateNeutronSecurityGroup(String uuid, NeutronSecurityGroup delta) {
+ if (!neutronSecurityGroupExists(uuid)) {
+ return false;
+ }
+ updateMd(delta);
+ return true;
+ }
+
+ @Override
+ public boolean neutronSecurityGroupInUse(String securityGroupUUID) {
+ return !neutronSecurityGroupExists(securityGroupUUID);
+ }
+
+ protected NeutronSecurityGroup fromMd(SecurityGroup group) {
+ NeutronSecurityGroup answer = new NeutronSecurityGroup();
+ if (group.getName() != null) {
+ answer.setSecurityGroupName(group.getName());
+ }
+ if (group.getDescription() != null) {
+ answer.setSecurityGroupDescription(group.getDescription());
+ }
+ if (group.getTenantId() != null) {
+ answer.setSecurityGroupTenantID(group.getTenantId().getValue().replace("-",""));
+ }
+ if (group.getSecurityRules() != null) {
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+ .fetchINeutronSecurityRuleCRUD(this);
+ INeutronSecurityRuleCRUD srCrud = interfaces.getSecurityRuleInterface();
+
+ List<NeutronSecurityRule> rules = new ArrayList<NeutronSecurityRule>();
+ for (Uuid uuid: group.getSecurityRules()) {
+ rules.add(srCrud.getNeutronSecurityRule(uuid.getValue()));
+ }
+ answer.setSecurityRules(rules);
+ }
+ if (group.getUuid() != null) {
+ answer.setID(group.getUuid().getValue());
+ }
+ return answer;
+ }
+
+ @Override
+ protected SecurityGroup toMd(NeutronSecurityGroup securityGroup) {
+ SecurityGroupBuilder securityGroupBuilder = new SecurityGroupBuilder();
+ if (securityGroup.getSecurityGroupName() != null) {
+ securityGroupBuilder.setName(securityGroup.getSecurityGroupName());
+ }
+ if (securityGroup.getSecurityGroupDescription() != null) {
+ securityGroupBuilder.setDescription(securityGroup.getSecurityGroupDescription());
+ }
+ if (securityGroup.getSecurityGroupTenantID() != null) {
+ securityGroupBuilder.setTenantId(toUuid(securityGroup.getSecurityGroupTenantID()));
+ }
+ if (securityGroup.getSecurityRules() != null) {
+ List<Uuid> neutronSecurityRule = new ArrayList<Uuid>();
+ for (NeutronSecurityRule securityRule : securityGroup.getSecurityRules()) {
+ if (securityRule.getID() != null) {
+ neutronSecurityRule.add(toUuid(securityRule.getID()));
+ }
+ }
+ securityGroupBuilder.setSecurityRules(neutronSecurityRule);
+ }
+ if (securityGroup.getID() != null) {
+ securityGroupBuilder.setUuid(toUuid(securityGroup.getID()));
+ } else {
+ LOGGER.warn("Attempting to write neutron securityGroup without UUID");
+ }
+
+ return securityGroupBuilder.build();
+ }
+
+ @Override
+ protected InstanceIdentifier<SecurityGroup> createInstanceIdentifier(SecurityGroup securityGroup) {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(SecurityGroups.class).child(SecurityGroup.class,
+ securityGroup.getKey());
+ }
+
+ protected InstanceIdentifier<SecurityGroups> createInstanceIdentifier() {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(SecurityGroups.class);
+ }
+
+ @Override
+ protected SecurityGroup toMd(String uuid) {
+ SecurityGroupBuilder securityGroupBuilder = new SecurityGroupBuilder();
+ securityGroupBuilder.setUuid(toUuid(uuid));
+ return securityGroupBuilder.build();
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronSecurityGroupInterface neutronSecurityGroupInterface = new NeutronSecurityGroupInterface(providerContext);
+ ServiceRegistration<INeutronSecurityGroupCRUD> neutronSecurityGroupInterfaceRegistration = context.registerService(INeutronSecurityGroupCRUD.class, neutronSecurityGroupInterface, null);
+ if(neutronSecurityGroupInterfaceRegistration != null) {
+ registrations.add(neutronSecurityGroupInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmpV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolUdp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRuleBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+
+public class NeutronSecurityRuleInterface extends AbstractNeutronInterface<SecurityRule, NeutronSecurityRule> implements INeutronSecurityRuleCRUD {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NeutronSecurityRuleInterface.class);
+
+ private static final ImmutableBiMap<Class<? extends DirectionBase>,String> DIRECTION_MAP
+ = new ImmutableBiMap.Builder<Class<? extends DirectionBase>,String>()
+ .put(DirectionEgress.class,"egress")
+ .put(DirectionIngress.class,"ingress")
+ .build();
+ private static final ImmutableBiMap<Class<? extends ProtocolBase>,String> PROTOCOL_MAP
+ = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>,String>()
+ .put(ProtocolIcmp.class,"icmp")
+ .put(ProtocolTcp.class,"tcp")
+ .put(ProtocolUdp.class,"udp")
+ .put(ProtocolIcmpV6.class,"icmpv6")
+ .build();
+ private static final ImmutableBiMap<Class<? extends EthertypeBase>,String> ETHERTYPE_MAP
+ = new ImmutableBiMap.Builder<Class<? extends EthertypeBase>,String>()
+ .put(EthertypeV4.class,"IPv4")
+ .put(EthertypeV6.class,"IPv6")
+ .build();
+
+ NeutronSecurityRuleInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ private void updateSecGroupRuleInSecurityGroup(NeutronSecurityRule input) {
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+ .fetchINeutronSecurityGroupCRUD(this);
+ INeutronSecurityGroupCRUD sgCrud = interfaces.getSecurityGroupInterface();
+ NeutronSecurityGroup sg = sgCrud.getNeutronSecurityGroup(input.getSecurityRuleGroupID());
+ if(sg != null && sg.getSecurityRules() != null) {
+ for(NeutronSecurityRule sgr :sg.getSecurityRules()) {
+ if(sgr != null && sgr.getID() != null && sgr.getID().equals(input.getID())) {
+ int index = sg.getSecurityRules().indexOf(sgr);
+ sg.getSecurityRules().set(index, input);
+ }
+ }
+ }
+ if (sg != null) {
+ sg.getSecurityRules().add(input);
+ }
+ }
+
+ private void removeSecGroupRuleFromSecurityGroup(NeutronSecurityRule input) {
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+ .fetchINeutronSecurityGroupCRUD(this);
+ INeutronSecurityGroupCRUD sgCrud = interfaces.getSecurityGroupInterface();
+ NeutronSecurityGroup sg = sgCrud.getNeutronSecurityGroup(input.getSecurityRuleGroupID());
+ if(sg != null && sg.getSecurityRules() != null) {
+ List<NeutronSecurityRule> toRemove = new ArrayList<NeutronSecurityRule>();
+ for(NeutronSecurityRule sgr :sg.getSecurityRules()) {
+ if(sgr.getID() != null && sgr.getID().equals(input.getID())) {
+ toRemove.add(sgr);
+ }
+ }
+ sg.getSecurityRules().removeAll(toRemove);
+ }
+ }
+
+ @Override
+ public boolean neutronSecurityRuleExists(String uuid) {
+ SecurityRule rule = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (rule == null) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public NeutronSecurityRule getNeutronSecurityRule(String uuid) {
+ SecurityRule rule = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (rule == null) {
+ return null;
+ }
+ return fromMd(rule);
+ }
+
+ @Override
+ public List<NeutronSecurityRule> getAllNeutronSecurityRules() {
+ Set<NeutronSecurityRule> allSecurityRules = new HashSet<NeutronSecurityRule>();
+ SecurityRules rules = readMd(createInstanceIdentifier());
+ if (rules != null) {
+ for (SecurityRule rule: rules.getSecurityRule()) {
+ allSecurityRules.add(fromMd(rule));
+ }
+ }
+ LOGGER.debug("Exiting getSecurityRule, Found {} OpenStackSecurityRule", allSecurityRules.size());
+ List<NeutronSecurityRule> ans = new ArrayList<NeutronSecurityRule>();
+ ans.addAll(allSecurityRules);
+ return ans;
+ }
+
+ @Override
+ public boolean addNeutronSecurityRule(NeutronSecurityRule input) {
+ if (neutronSecurityRuleExists(input.getID())) {
+ return false;
+ }
+ updateSecGroupRuleInSecurityGroup(input);
+ addMd(input);
+ return true;
+ }
+
+ @Override
+ public boolean removeNeutronSecurityRule(String uuid) {
+ if (!neutronSecurityRuleExists(uuid)) {
+ return false;
+ }
+ removeSecGroupRuleFromSecurityGroup(getNeutronSecurityRule(uuid));
+ removeMd(toMd(uuid));
+ return true;
+ }
+
+ @Override
+ public boolean updateNeutronSecurityRule(String uuid, NeutronSecurityRule delta) {
+ if (!neutronSecurityRuleExists(uuid)) {
+ return false;
+ }
+ updateSecGroupRuleInSecurityGroup(delta);
+ updateMd(delta);
+ return true;
+ }
+
+ @Override
+ public boolean neutronSecurityRuleInUse(String securityRuleUUID) {
+ return !neutronSecurityRuleExists(securityRuleUUID);
+ }
+
+ protected NeutronSecurityRule fromMd(SecurityRule rule) {
+ NeutronSecurityRule answer = new NeutronSecurityRule();
+ if (rule.getTenantId() != null) {
+ answer.setSecurityRuleTenantID(rule.getTenantId().getValue().replace("-",""));
+ }
+ if (rule.getDirection() != null) {
+ answer.setSecurityRuleDirection(DIRECTION_MAP.get(rule.getDirection()));
+ }
+ if (rule.getSecurityGroupId() != null) {
+ answer.setSecurityRuleGroupID(rule.getSecurityGroupId().getValue());
+ }
+ if (rule.getRemoteGroupId() != null) {
+ answer.setSecurityRemoteGroupID(rule.getRemoteGroupId().getValue());
+ }
+ if (rule.getRemoteIpPrefix() != null) {
+ answer.setSecurityRuleRemoteIpPrefix(rule.getRemoteIpPrefix().getIpv4Prefix() != null?
+ rule.getRemoteIpPrefix().getIpv4Prefix().getValue():rule.getRemoteIpPrefix().getIpv6Prefix().getValue());
+ }
+ if (rule.getProtocol() != null) {
+ answer.setSecurityRuleProtocol(PROTOCOL_MAP.get(rule.getProtocol()));
+ }
+ if (rule.getEthertype() != null) {
+ answer.setSecurityRuleEthertype(ETHERTYPE_MAP.get(rule.getEthertype()));
+ }
+ if (rule.getPortRangeMin() != null) {
+ answer.setSecurityRulePortMin(Integer.valueOf(rule.getPortRangeMin()));
+ }
+ if (rule.getPortRangeMax() != null) {
+ answer.setSecurityRulePortMax(Integer.valueOf(rule.getPortRangeMax()));
+ }
+ if (rule.getId() != null) {
+ answer.setID(rule.getId().getValue());
+ }
+ return answer;
+ }
+
+ @Override
+ protected SecurityRule toMd(NeutronSecurityRule securityRule) {
+ SecurityRuleBuilder securityRuleBuilder = new SecurityRuleBuilder();
+
+ if (securityRule.getSecurityRuleTenantID() != null) {
+ securityRuleBuilder.setTenantId(toUuid(securityRule.getSecurityRuleTenantID()));
+ }
+ if (securityRule.getSecurityRuleDirection() != null) {
+ ImmutableBiMap<String, Class<? extends DirectionBase>> mapper =
+ DIRECTION_MAP.inverse();
+ securityRuleBuilder.setDirection((Class<? extends DirectionBase>) mapper.get(securityRule.getSecurityRuleDirection()));
+ }
+ if (securityRule.getSecurityRuleGroupID() != null) {
+ securityRuleBuilder.setSecurityGroupId(toUuid(securityRule.getSecurityRuleGroupID()));
+ }
+ if (securityRule.getSecurityRemoteGroupID() != null) {
+ securityRuleBuilder.setRemoteGroupId(toUuid(securityRule.getSecurityRemoteGroupID()));
+ }
+ if (securityRule.getSecurityRuleRemoteIpPrefix() != null) {
+ securityRuleBuilder.setRemoteIpPrefix(new IpPrefix(securityRule.getSecurityRuleRemoteIpPrefix().toCharArray()));
+ }
+ if (securityRule.getSecurityRuleProtocol() != null) {
+ ImmutableBiMap<String, Class<? extends ProtocolBase>> mapper =
+ PROTOCOL_MAP.inverse();
+ securityRuleBuilder.setProtocol((Class<? extends ProtocolBase>) mapper.get(securityRule.getSecurityRuleProtocol()));
+ }
+ if (securityRule.getSecurityRuleEthertype() != null) {
+ ImmutableBiMap<String, Class<? extends EthertypeBase>> mapper =
+ ETHERTYPE_MAP.inverse();
+ securityRuleBuilder.setEthertype((Class<? extends EthertypeBase>) mapper.get(securityRule.getSecurityRuleEthertype()));
+ }
+ if (securityRule.getSecurityRulePortMin() != null) {
+ securityRuleBuilder.setPortRangeMin(Integer.valueOf(securityRule.getSecurityRulePortMin()));
+ }
+ if (securityRule.getSecurityRulePortMax() != null) {
+ securityRuleBuilder.setPortRangeMax(Integer.valueOf(securityRule.getSecurityRulePortMax()));
+ }
+ if (securityRule.getID() != null) {
+ securityRuleBuilder.setId(toUuid(securityRule.getID()));
+ } else {
+ LOGGER.warn("Attempting to write neutron securityRule without UUID");
+ }
+ return securityRuleBuilder.build();
+ }
+
+ @Override
+ protected InstanceIdentifier<SecurityRule> createInstanceIdentifier(SecurityRule securityRule) {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(SecurityRules.class).child(SecurityRule.class,
+ securityRule.getKey());
+ }
+
+ protected InstanceIdentifier<SecurityRules> createInstanceIdentifier() {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(SecurityRules.class);
+ }
+
+ @Override
+ protected SecurityRule toMd(String uuid) {
+ SecurityRuleBuilder securityRuleBuilder = new SecurityRuleBuilder();
+ securityRuleBuilder.setId(toUuid(uuid));
+ return securityRuleBuilder.build();
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronSecurityRuleInterface neutronSecurityRuleInterface = new NeutronSecurityRuleInterface(providerContext);
+ ServiceRegistration<INeutronSecurityRuleCRUD> neutronSecurityRuleInterfaceRegistration = context.registerService(INeutronSecurityRuleCRUD.class, neutronSecurityRuleInterface, null);
+ if(neutronSecurityRuleInterfaceRegistration != null) {
+ registrations.add(neutronSecurityRuleInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnetIPAllocationPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Base;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Off;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Slaac;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateful;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateless;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPoolsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronSubnetInterface extends AbstractNeutronInterface<Subnet, NeutronSubnet> implements INeutronSubnetCRUD {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NeutronSubnetInterface.class);
+
+ private static final ImmutableBiMap<Class<? extends IpVersionBase>,Integer> IPV_MAP
+ = new ImmutableBiMap.Builder<Class<? extends IpVersionBase>,Integer>()
+ .put(IpVersionV4.class,Integer.valueOf(4))
+ .put(IpVersionV6.class,Integer.valueOf(6))
+ .build();
+
+ private static final ImmutableBiMap<Class<? extends Dhcpv6Base>,String> DHCPV6_MAP
+ = new ImmutableBiMap.Builder<Class<? extends Dhcpv6Base>,String>()
+ .put(Dhcpv6Off.class,"off")
+ .put(Dhcpv6Stateful.class,"dhcpv6-stateful")
+ .put(Dhcpv6Slaac.class,"slaac")
+ .put(Dhcpv6Stateless.class,"dhcpv6-stateless")
+ .build();
+
+ NeutronSubnetInterface(ProviderContext providerContext) {
+ super(providerContext);
+ }
+
+ // IfNBSubnetCRUD methods
+
+ @Override
+ public boolean subnetExists(String uuid) {
+ Subnet subnet = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (subnet == null) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public NeutronSubnet getSubnet(String uuid) {
+ Subnet subnet = readMd(createInstanceIdentifier(toMd(uuid)));
+ if (subnet == null) {
+ return null;
+ }
+ return fromMd(subnet);
+ }
+
+ @Override
+ public List<NeutronSubnet> getAllSubnets() {
+ Set<NeutronSubnet> allSubnets = new HashSet<NeutronSubnet>();
+ Subnets subnets = readMd(createInstanceIdentifier());
+ if (subnets != null) {
+ for (Subnet subnet: subnets.getSubnet()) {
+ allSubnets.add(fromMd(subnet));
+ }
+ }
+ LOGGER.debug("Exiting getAllSubnets, Found {} OpenStackSubnets", allSubnets.size());
+ List<NeutronSubnet> ans = new ArrayList<NeutronSubnet>();
+ ans.addAll(allSubnets);
+ return ans;
+ }
+
+ @Override
+ public boolean addSubnet(NeutronSubnet input) {
+ String id = input.getID();
+ if (subnetExists(id)) {
+ return false;
+ }
+ addMd(input);
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+ .fetchINeutronNetworkCRUD(this);
+ INeutronNetworkCRUD networkIf = interfaces.getNetworkInterface();
+
+ NeutronNetwork targetNet = networkIf.getNetwork(input.getNetworkUUID());
+ targetNet.addSubnet(id);
+ return true;
+ }
+
+ @Override
+ public boolean removeSubnet(String uuid) {
+ NeutronSubnet target = getSubnet(uuid);
+ if (target == null) {
+ return false;
+ }
+ removeMd(toMd(uuid));
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+ .fetchINeutronNetworkCRUD(this);
+ INeutronNetworkCRUD networkIf = interfaces.getNetworkInterface();
+
+ NeutronNetwork targetNet = networkIf.getNetwork(target.getNetworkUUID());
+ targetNet.removeSubnet(uuid);
+ return true;
+ }
+
+ @Override
+ public boolean updateSubnet(String uuid, NeutronSubnet delta) {
+ if (!subnetExists(uuid)) {
+ return false;
+ }
+/* note: because what we get is *not* a delta but (at this point) the updated
+ * object, this is much simpler - just replace the value and update the mdsal
+ * with it */
+ updateMd(delta);
+ return true;
+ }
+
+// note: this is being set to false in preparation for deprecation and removal
+ @Override
+ public boolean subnetInUse(String subnetUUID) {
+ return false;
+ }
+
+ protected NeutronSubnet fromMd(Subnet subnet) {
+ NeutronSubnet result = new NeutronSubnet();
+ result.setName(subnet.getName());
+ result.setTenantID(String.valueOf(subnet.getTenantId().getValue()).replace("-",""));
+ result.setNetworkUUID(subnet.getNetworkId().getValue());
+ result.setIpVersion(IPV_MAP.get(subnet.getIpVersion()));
+ result.setCidr(subnet.getCidr());
+ result.setGatewayIP(String.valueOf(subnet.getGatewayIp().getValue()));
+ result.setIpV6RaMode(DHCPV6_MAP.get(subnet.getIpv6RaMode()));
+ result.setIpV6AddressMode(DHCPV6_MAP.get(subnet.getIpv6AddressMode()));
+ result.setEnableDHCP(subnet.isEnableDhcp());
+ if (subnet.getAllocationPools() != null) {
+ List<NeutronSubnetIPAllocationPool> allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
+ for (AllocationPools allocationPool : subnet.getAllocationPools()) {
+ NeutronSubnetIPAllocationPool pool = new NeutronSubnetIPAllocationPool();
+ pool.setPoolStart(allocationPool.getStart());
+ pool.setPoolEnd(allocationPool.getEnd());
+ allocationPools.add(pool);
+ }
+ result.setAllocationPools(allocationPools);
+ }
+ if (subnet.getDnsNameservers() != null) {
+ List<String> dnsNameServers = new ArrayList<String>();
+ for (IpAddress dnsNameServer : subnet.getDnsNameservers()) {
+ dnsNameServers.add(String.valueOf(dnsNameServer.getValue()));
+ }
+ result.setDnsNameservers(dnsNameServers);
+ }
+ result.setID(subnet.getUuid().getValue());
+// read through the ports and put the ones in this subnet into the internal
+// myPorts object.
+// @deprecated and will be removed in Boron
+ Set<NeutronPort> allPorts = new HashSet<NeutronPort>();
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+ .fetchINeutronPortCRUD(this);
+ INeutronPortCRUD portIf = interfaces.getPortInterface();
+ for (NeutronPort port : portIf.getAllPorts()) {
+ if (port.getFixedIPs() != null) {
+ for (Neutron_IPs ip : port.getFixedIPs()) {
+ if (ip.getSubnetUUID().equals(result.getID())) {
+ allPorts.add(port);
+ }
+ }
+ }
+ }
+ List<NeutronPort> ports = new ArrayList<NeutronPort>();
+ ports.addAll(allPorts);
+ result.setPorts(ports);
+ return result;
+ }
+
+ protected Subnet toMd(NeutronSubnet subnet) {
+ SubnetBuilder subnetBuilder = new SubnetBuilder();
+ if (subnet.getName() != null) {
+ subnetBuilder.setName(subnet.getName());
+ }
+ if (subnet.getTenantID() != null) {
+ subnetBuilder.setTenantId(toUuid(subnet.getTenantID()));
+ }
+ if (subnet.getNetworkUUID() != null) {
+ subnetBuilder.setNetworkId(toUuid(subnet.getNetworkUUID()));
+ }
+ if (subnet.getIpVersion() != null) {
+ ImmutableBiMap<Integer, Class<? extends IpVersionBase>> mapper =
+ IPV_MAP.inverse();
+ subnetBuilder.setIpVersion((Class<? extends IpVersionBase>) mapper.get(subnet
+ .getIpVersion()));
+ }
+ if (subnet.getCidr() != null) {
+ subnetBuilder.setCidr(subnet.getCidr());
+ }
+ if (subnet.getGatewayIP() != null) {
+ IpAddress ipAddress = new IpAddress(subnet.getGatewayIP()
+ .toCharArray());
+ subnetBuilder.setGatewayIp(ipAddress);
+ }
+ if (subnet.getIpV6RaMode() != null) {
+ ImmutableBiMap<String, Class<? extends Dhcpv6Base>> mapper =
+ DHCPV6_MAP.inverse();
+ subnetBuilder.setIpv6RaMode((Class<? extends Dhcpv6Base>) mapper.get(subnet.getIpV6RaMode()));
+ }
+ if (subnet.getIpV6AddressMode() != null) {
+ ImmutableBiMap<String, Class<? extends Dhcpv6Base>> mapper =
+ DHCPV6_MAP.inverse();
+ subnetBuilder.setIpv6AddressMode((Class<? extends Dhcpv6Base>) mapper.get(subnet.getIpV6AddressMode()));
+ }
+ subnetBuilder.setEnableDhcp(subnet.getEnableDHCP());
+ if (subnet.getAllocationPools() != null) {
+ List<AllocationPools> allocationPools = new ArrayList<AllocationPools>();
+ for (NeutronSubnetIPAllocationPool allocationPool : subnet
+ .getAllocationPools()) {
+ AllocationPoolsBuilder builder = new AllocationPoolsBuilder();
+ builder.setStart(allocationPool.getPoolStart());
+ builder.setEnd(allocationPool.getPoolEnd());
+ AllocationPools temp = builder.build();
+ allocationPools.add(temp);
+ }
+ subnetBuilder.setAllocationPools(allocationPools);
+ }
+ if (subnet.getDnsNameservers() != null) {
+ List<IpAddress> dnsNameServers = new ArrayList<IpAddress>();
+ for (String dnsNameServer : subnet.getDnsNameservers()) {
+ IpAddress ipAddress = new IpAddress(dnsNameServer.toCharArray());
+ dnsNameServers.add(ipAddress);
+ }
+ subnetBuilder.setDnsNameservers(dnsNameServers);
+ }
+ if (subnet.getID() != null) {
+ subnetBuilder.setUuid(toUuid(subnet.getID()));
+ } else {
+ LOGGER.warn("Attempting to write neutron subnet without UUID");
+ }
+ return subnetBuilder.build();
+ }
+
+ @Override
+ protected InstanceIdentifier<Subnet> createInstanceIdentifier(Subnet subnet) {
+ return InstanceIdentifier.create(Neutron.class).child(Subnets.class)
+ .child(Subnet.class, subnet.getKey());
+ }
+
+ protected InstanceIdentifier<Subnets> createInstanceIdentifier() {
+ return InstanceIdentifier.create(Neutron.class)
+ .child(Subnets.class);
+ }
+
+ @Override
+ protected Subnet toMd(String uuid) {
+ SubnetBuilder subnetBuilder = new SubnetBuilder();
+ subnetBuilder.setUuid(toUuid(uuid));
+ return subnetBuilder.build();
+ }
+
+ public static void registerNewInterface(BundleContext context,
+ ProviderContext providerContext,
+ List<ServiceRegistration<?>> registrations) {
+ NeutronSubnetInterface neutronSubnetInterface = new NeutronSubnetInterface(providerContext);
+ ServiceRegistration<INeutronSubnetCRUD> neutronSubnetInterfaceRegistration = context.registerService(INeutronSubnetCRUD.class, neutronSubnetInterface, null);
+ if(neutronSubnetInterfaceRegistration != null) {
+ registrations.add(neutronSubnetInterfaceRegistration);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Firewall Rules needs to implement
+ *
+ */
+
+public interface INeutronFirewallAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified firewall can be created
+ *
+ * @param firewall
+ * instance of proposed new Firewall object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronFirewall(NeutronFirewall firewall);
+
+ /**
+ * Services provide this interface method for taking action after a firewall has been created
+ *
+ * @param firewall
+ * instance of new Firewall object
+ */
+ void neutronFirewallCreated(NeutronFirewall firewall);
+
+ /**
+ * Services provide this interface method to indicate if the specified firewall can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the firewall object using patch semantics
+ * @param original
+ * instance of the Firewall object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronFirewall(NeutronFirewall delta, NeutronFirewall original);
+
+ /**
+ * Services provide this interface method for taking action after a firewall has been updated
+ *
+ * @param firewall
+ * instance of modified Firewall object
+ */
+ void neutronFirewallUpdated(NeutronFirewall firewall);
+
+ /**
+ * Services provide this interface method to indicate if the specified firewall can be deleted
+ *
+ * @param firewall
+ * instance of the Firewall object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronFirewall(NeutronFirewall firewall);
+
+ /**
+ * Services provide this interface method for taking action after a firewall has been deleted
+ *
+ * @param firewall
+ * instance of deleted Firewall object
+ */
+ void neutronFirewallDeleted(NeutronFirewall firewall);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Firewall Policys needs to implement
+ *
+ */
+
+public interface INeutronFirewallPolicyAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified firewallPolicy can be created
+ *
+ * @param firewallPolicy
+ * instance of proposed new Firewall Policy object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronFirewallPolicy(NeutronFirewallPolicy firewallPolicy);
+
+ /**
+ * Services provide this interface method for taking action after a firewallPolicy has been created
+ *
+ * @param firewallPolicy
+ * instance of new Firewall Policy object
+ */
+ void neutronFirewallPolicyCreated(NeutronFirewallPolicy firewallPolicy);
+
+ /**
+ * Services provide this interface method to indicate if the specified firewallPolicy can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the firewallPolicy object using patch semantics
+ * @param original
+ * instance of the Firewall Policy object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronFirewallPolicy(NeutronFirewallPolicy delta, NeutronFirewallPolicy original);
+
+ /**
+ * Services provide this interface method for taking action after a firewallPolicy has been updated
+ *
+ * @param firewallPolicy
+ * instance of modified Firewall Policy object
+ */
+ void neutronFirewallPolicyUpdated(NeutronFirewallPolicy firewallPolicy);
+
+ /**
+ * Services provide this interface method to indicate if the specified firewallPolicy can be deleted
+ *
+ * @param firewallPolicy
+ * instance of the Firewall Policy object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronFirewallPolicy(NeutronFirewallPolicy firewallPolicy);
+
+ /**
+ * Services provide this interface method for taking action after a firewallPolicy has been deleted
+ *
+ * @param firewallPolicy
+ * instance of deleted Firewall Policy object
+ */
+ void neutronFirewallPolicyDeleted(NeutronFirewallPolicy firewallPolicy);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Firewall Rules needs to implement
+ *
+ */
+
+public interface INeutronFirewallRuleAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified firewallRule can be created
+ *
+ * @param firewallRule
+ * instance of proposed new Firewall Rule object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronFirewallRule(NeutronFirewallRule firewallRule);
+
+ /**
+ * Services provide this interface method for taking action after a firewallRule has been created
+ *
+ * @param firewallRule
+ * instance of new Firewall Rule object
+ */
+ void neutronFirewallRuleCreated(NeutronFirewallRule firewallRule);
+
+ /**
+ * Services provide this interface method to indicate if the specified firewallRule can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the firewallRule object using patch semantics
+ * @param original
+ * instance of the Firewall Rule object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronFirewallRule(NeutronFirewallRule delta, NeutronFirewallRule original);
+
+ /**
+ * Services provide this interface method for taking action after a firewallRule has been updated
+ *
+ * @param firewallRule
+ * instance of modified Firewall Rule object
+ */
+ void neutronFirewallRuleUpdated(NeutronFirewallRule firewallRule);
+
+ /**
+ * Services provide this interface method to indicate if the specified firewallRule can be deleted
+ *
+ * @param firewallRule
+ * instance of the Firewall Rule object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronFirewallRule(NeutronFirewallRule firewallRule);
+
+ /**
+ * Services provide this interface method for taking action after a firewallRule has been deleted
+ *
+ * @param firewallRule
+ * instance of deleted Firewall Rule object
+ */
+ void neutronFirewallRuleDeleted(NeutronFirewallRule firewallRule);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron FloatingIPs needs to implement
+ *
+ */
+
+public interface INeutronFloatingIPAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified floatingIP can be created
+ *
+ * @param floatingIP
+ * instance of proposed new Neutron FloatingIP object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateFloatingIP(NeutronFloatingIP floatingIP);
+
+ /**
+ * Services provide this interface method for taking action after a floatingIP has been created
+ *
+ * @param floatingIP
+ * instance of new Neutron FloatingIP object
+ */
+ void neutronFloatingIPCreated(NeutronFloatingIP floatingIP);
+
+ /**
+ * Services provide this interface method to indicate if the specified floatingIP can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the floatingIP object using patch semantics
+ * @param original
+ * instance of the Neutron FloatingIP object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateFloatingIP(NeutronFloatingIP delta, NeutronFloatingIP original);
+
+ /**
+ * Services provide this interface method for taking action after a floatingIP has been updated
+ *
+ * @param floatingIP
+ * instance of modified Neutron FloatingIP object
+ */
+ void neutronFloatingIPUpdated(NeutronFloatingIP floatingIP);
+
+ /**
+ * Services provide this interface method to indicate if the specified floatingIP can be deleted
+ *
+ * @param floatingIP
+ * instance of the Neutron FloatingIP object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteFloatingIP(NeutronFloatingIP floatingIP);
+
+ /**
+ * Services provide this interface method for taking action after a floatingIP has been deleted
+ *
+ * @param floatingIP
+ * instance of deleted Neutron FloatingIP object
+ */
+ void neutronFloatingIPDeleted(NeutronFloatingIP floatingIP);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancer Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancer can be created
+ *
+ * @param loadBalancer
+ * instance of proposed new LoadBalancer object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronLoadBalancer(NeutronLoadBalancer loadBalancer);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancer has been created
+ *
+ * @param loadBalancer
+ * instance of new LoadBalancer object
+ */
+ void neutronLoadBalancerCreated(NeutronLoadBalancer loadBalancer);
+
+ /**
+ * Services provide this interface method to indicate if the
+ * specified loadBalancer can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the loadBalancer object using patch semantics
+ * @param original
+ * instance of the LoadBalancer object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronLoadBalancer(NeutronLoadBalancer delta, NeutronLoadBalancer original);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancer has been updated
+ *
+ * @param loadBalancer
+ * instance of modified LoadBalancer object
+ */
+ void neutronLoadBalancerUpdated(NeutronLoadBalancer loadBalancer);
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancer can be deleted
+ *
+ * @param loadBalancer
+ * instance of the LoadBalancer object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronLoadBalancer(NeutronLoadBalancer loadBalancer);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancer has been deleted
+ *
+ * @param loadBalancer
+ * instance of deleted LoadBalancer object
+ */
+ void neutronLoadBalancerDeleted(NeutronLoadBalancer loadBalancer);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerHealthMonitor;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerHealthMonitor Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerHealthMonitorAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be created
+ *
+ * @param loadBalancerHealthMonitor
+ * instance of proposed new LoadBalancerHealthMonitor object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been created
+ *
+ * @param loadBalancerHealthMonitor
+ * instance of new LoadBalancerHealthMonitor object
+ */
+ void neutronLoadBalancerHealthMonitorCreated(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the loadBalancerHealthMonitor object using patch semantics
+ * @param original
+ * instance of the LoadBalancerHealthMonitor object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor delta,
+ NeutronLoadBalancerHealthMonitor original);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been updated
+ *
+ * @param loadBalancerHealthMonitor
+ * instance of modified LoadBalancerHealthMonitor object
+ */
+ void neutronLoadBalancerHealthMonitorUpdated(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be deleted
+ *
+ * @param loadBalancerHealthMonitor
+ * instance of the LoadBalancerHealthMonitor object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been deleted
+ *
+ * @param loadBalancerHealthMonitor
+ * instance of deleted LoadBalancerHealthMonitor object
+ */
+ void neutronLoadBalancerHealthMonitorDeleted(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerListener;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerListener Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerListenerAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerListener can be created
+ *
+ * @param loadBalancerListener
+ * instance of proposed new LoadBalancerListener object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronLoadBalancerListener(NeutronLoadBalancerListener loadBalancerListener);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerListener has been created
+ *
+ * @param loadBalancerListener
+ * instance of new LoadBalancerListener object
+ */
+ void neutronLoadBalancerListenerCreated(NeutronLoadBalancerListener loadBalancerListener);
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerListener can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the loadBalancerListener object using patch semantics
+ * @param original
+ * instance of the LoadBalancerListener object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronLoadBalancerListener(NeutronLoadBalancerListener delta,
+ NeutronLoadBalancerListener original);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerListener has been updated
+ *
+ * @param loadBalancerListener
+ * instance of modified LoadBalancerListener object
+ */
+ void neutronLoadBalancerListenerUpdated(NeutronLoadBalancerListener loadBalancerListener);
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerListener can be deleted
+ *
+ * @param loadBalancerListener
+ * instance of the LoadBalancerListener object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronLoadBalancerListener(NeutronLoadBalancerListener loadBalancerListener);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerListener has been deleted
+ *
+ * @param loadBalancerListener
+ * instance of deleted LoadBalancerListener object
+ */
+ void neutronLoadBalancerListenerDeleted(NeutronLoadBalancerListener loadBalancerListener);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerPool Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerPoolAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerPool can be created
+ *
+ * @param loadBalancerPool
+ * instance of proposed new LoadBalancerPool object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronLoadBalancerPool(NeutronLoadBalancerPool loadBalancerPool);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerPool has been created
+ *
+ * @param loadBalancerPool
+ * instance of new LoadBalancerPool object
+ */
+ void neutronLoadBalancerPoolCreated(NeutronLoadBalancerPool loadBalancerPool);
+
+ /**
+ * Services provide this interface method to indicate if the
+ * specified loadBalancerPool can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the loadBalancerPool object using patch semantics
+ * @param original
+ * instance of the LoadBalancerPool object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronLoadBalancerPool(NeutronLoadBalancerPool delta, NeutronLoadBalancerPool original);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerPool has been updated
+ *
+ * @param loadBalancerPool
+ * instance of modified LoadBalancerPool object
+ */
+ void neutronLoadBalancerPoolUpdated(NeutronLoadBalancerPool loadBalancerPool);
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerPool can be deleted
+ *
+ * @param loadBalancerPool
+ * instance of the LoadBalancerPool object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronLoadBalancerPool(NeutronLoadBalancerPool loadBalancerPool);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerPool has been deleted
+ *
+ * @param loadBalancerPool
+ * instance of deleted LoadBalancerPool object
+ */
+ void neutronLoadBalancerPoolDeleted(NeutronLoadBalancerPool loadBalancerPool);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+
+public interface INeutronLoadBalancerPoolMemberAware {
+
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be created
+ *
+ * @param loadBalancerPoolMember
+ * instance of proposed new LoadBalancerPool object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerPoolMember has been created
+ *
+ * @param loadBalancerPoolMember
+ * instance of new LoadBalancerPool object
+ */
+ void neutronLoadBalancerPoolMemberCreated(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the loadBalancerPoolMember object using patch semantics
+ * @param original
+ * instance of the LoadBalancerPool object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember delta,
+ NeutronLoadBalancerPoolMember original);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerPoolMember has been updated
+ *
+ * @param loadBalancerPoolMember
+ * instance of modified LoadBalancerPool object
+ */
+ void neutronLoadBalancerPoolMemberUpdated(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+ /**
+ * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be deleted
+ *
+ * @param loadBalancerPoolMember
+ * instance of the LoadBalancerPool object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+ /**
+ * Services provide this interface method for taking action after a loadBalancerPoolMember has been deleted
+ *
+ * @param loadBalancerPoolMember
+ * instance of deleted LoadBalancerPool object
+ */
+ void neutronLoadBalancerPoolMemberDeleted(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Networks needs to implement
+ *
+ */
+
+public interface INeutronNetworkAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified network can be created
+ *
+ * @param network
+ * instance of proposed new Neutron Network object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNetwork(NeutronNetwork network);
+
+ /**
+ * Services provide this interface method for taking action after a network has been created
+ *
+ * @param network
+ * instance of new Neutron Network object
+ */
+ void neutronNetworkCreated(NeutronNetwork network);
+
+ /**
+ * Services provide this interface method to indicate if the specified network can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the network object using patch semantics
+ * @param original
+ * instance of the Neutron Network object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNetwork(NeutronNetwork delta, NeutronNetwork original);
+
+ /**
+ * Services provide this interface method for taking action after a network has been updated
+ *
+ * @param network
+ * instance of modified Neutron Network object
+ */
+ void neutronNetworkUpdated(NeutronNetwork network);
+
+ /**
+ * Services provide this interface method to indicate if the specified network can be deleted
+ *
+ * @param network
+ * instance of the Neutron Network object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNetwork(NeutronNetwork network);
+
+ /**
+ * Services provide this interface method for taking action after a network has been deleted
+ *
+ * @param network
+ * instance of deleted Neutron Network object
+ */
+ void neutronNetworkDeleted(NeutronNetwork network);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Ports needs to implement
+ *
+ */
+
+public interface INeutronPortAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified port can be created
+ *
+ * @param port
+ * instance of proposed new Neutron Port object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreatePort(NeutronPort port);
+
+ /**
+ * Services provide this interface method for taking action after a port has been created
+ *
+ * @param port
+ * instance of new Neutron Port object
+ */
+ void neutronPortCreated(NeutronPort port);
+
+ /**
+ * Services provide this interface method to indicate if the specified port can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the port object using patch semantics
+ * @param original
+ * instance of the Neutron Port object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdatePort(NeutronPort delta, NeutronPort original);
+
+ /**
+ * Services provide this interface method for taking action after a port has been updated
+ *
+ * @param port
+ * instance of modified Neutron Port object
+ */
+ void neutronPortUpdated(NeutronPort port);
+
+ /**
+ * Services provide this interface method to indicate if the specified port can be deleted
+ *
+ * @param port
+ * instance of the Neutron Port object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeletePort(NeutronPort port);
+
+ /**
+ * Services provide this interface method for taking action after a port has been deleted
+ *
+ * @param port
+ * instance of deleted Port Network object
+ */
+ void neutronPortDeleted(NeutronPort port);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Routers needs to implement
+ *
+ */
+
+public interface INeutronRouterAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified router can be created
+ *
+ * @param router
+ * instance of proposed new Neutron Router object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateRouter(NeutronRouter router);
+
+ /**
+ * Services provide this interface method for taking action after a router has been created
+ *
+ * @param router
+ * instance of new Neutron Router object
+ */
+ void neutronRouterCreated(NeutronRouter router);
+
+ /**
+ * Services provide this interface method to indicate if the specified router can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the router object using patch semantics
+ * @param original
+ * instance of the Neutron Router object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateRouter(NeutronRouter delta, NeutronRouter original);
+
+ /**
+ * Services provide this interface method for taking action after a router has been updated
+ *
+ * @param router
+ * instance of modified Neutron Router object
+ */
+ void neutronRouterUpdated(NeutronRouter router);
+
+ /**
+ * Services provide this interface method to indicate if the specified router can be deleted
+ *
+ * @param router
+ * instance of the Neutron Router object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteRouter(NeutronRouter router);
+
+ /**
+ * Services provide this interface method for taking action after a router has been deleted
+ *
+ * @param router
+ * instance of deleted Router Network object
+ */
+ void neutronRouterDeleted(NeutronRouter router);
+
+ /**
+ * Services provide this interface method to indicate if the
+ * specified interface can be attached to the specified router
+ *
+ * @param router
+ * instance of the base Neutron Router object
+ * @param routerInterface
+ * instance of the NeutronRouter_Interface to be attached to the router
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the attach operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface);
+
+ /**
+ * Services provide this interface method for taking action
+ * after an interface has been added to a router
+ *
+ * @param router
+ * instance of the base Neutron Router object
+ * @param routerInterface
+ * instance of the NeutronRouter_Interface being attached to the router
+ */
+ void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface);
+
+ /**
+ * Services provide this interface method to indicate if the
+ * specified interface can be detached from the specified router
+ *
+ * @param router
+ * instance of the base Neutron Router object
+ * @param routerInterface
+ * instance of the NeutronRouter_Interface to be detached to the router
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the detach operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface);
+
+ /**
+ * Services provide this interface method for taking action after an interface has been removed from a router
+ *
+ * @param router
+ * instance of the base Neutron Router object
+ * @param routerInterface
+ * instance of the NeutronRouter_Interface being detached from the router
+ */
+ void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Security Groups needs to implement
+ */
+
+public interface INeutronSecurityGroupAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified security group can be created
+ *
+ * @param securityGroup instance of proposed new Neutron Security Group object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronSecurityGroup(NeutronSecurityGroup securityGroup);
+
+ /**
+ * Services provide this interface method for taking action after a security group has been created
+ *
+ * @param securityGroup instance of new Neutron Security Group object
+ */
+ void neutronSecurityGroupCreated(NeutronSecurityGroup securityGroup);
+
+ /**
+ * Services provide this interface method to indicate if the specified security group can be changed using the specified
+ * delta
+ *
+ * @param delta updates to the security group object using patch semantics
+ * @param original instance of the Neutron Security Group object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronSecurityGroup(NeutronSecurityGroup delta, NeutronSecurityGroup original);
+
+ /**
+ * Services provide this interface method for taking action after a security group has been updated
+ *
+ * @param securityGroup instance of modified Neutron Security Group object
+ */
+ void neutronSecurityGroupUpdated(NeutronSecurityGroup securityGroup);
+
+ /**
+ * Services provide this interface method to indicate if the specified security group can be deleted
+ *
+ * @param securityGroup instance of the Neutron Security Group object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronSecurityGroup(NeutronSecurityGroup securityGroup);
+
+ /**
+ * Services provide this interface method for taking action after a security group has been deleted
+ *
+ * @param securityGroup instance of deleted Neutron Security Group object
+ */
+ void neutronSecurityGroupDeleted(NeutronSecurityGroup securityGroup);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+
+/**
+ * This interface defines the methods required to be aware of Neutron Security Rules
+ */
+
+public interface INeutronSecurityRuleAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified security rule can be created
+ *
+ * @param securityRule instance of proposed new Neutron Security Rule object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateNeutronSecurityRule(NeutronSecurityRule securityRule);
+
+ /**
+ * Services provide this interface method for taking action after a security rule has been created
+ *
+ * @param securityRule instance of new Neutron Security Rule object
+ */
+ void neutronSecurityRuleCreated(NeutronSecurityRule securityRule);
+
+ /**
+ * Services provide this interface method to indicate if the specified security rule can be changed using the specified
+ * delta
+ *
+ * @param delta updates to the security rule object using patch semantics
+ * @param original instance of the Neutron Security Rule object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateNeutronSecurityRule(NeutronSecurityRule delta, NeutronSecurityRule original);
+
+ /**
+ * Services provide this interface method for taking action after a security rule has been updated
+ *
+ * @param securityRule instance of modified Neutron Security Rule object
+ */
+ void neutronSecurityRuleUpdated(NeutronSecurityRule securityRule);
+
+ /**
+ * Services provide this interface method to indicate if the specified security rule can be deleted
+ *
+ * @param securityRule instance of the Neutron Security Rule object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteNeutronSecurityRule(NeutronSecurityRule securityRule);
+
+ /**
+ * Services provide this interface method for taking action after a security rule has been deleted
+ *
+ * @param securityRule instance of deleted Neutron Security Rule object
+ */
+ void neutronSecurityRuleDeleted(NeutronSecurityRule securityRule);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Subnets needs to implement
+ *
+ */
+
+public interface INeutronSubnetAware {
+
+ /**
+ * Services provide this interface method to indicate if the specified subnet can be created
+ *
+ * @param subnet
+ * instance of proposed new Neutron Subnet object
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the create operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canCreateSubnet(NeutronSubnet subnet);
+
+ /**
+ * Services provide this interface method for taking action after a subnet has been created
+ *
+ * @param subnet
+ * instance of new Neutron Subnet object
+ */
+ void neutronSubnetCreated(NeutronSubnet subnet);
+
+ /**
+ * Services provide this interface method to indicate if the specified subnet can be changed using the specified
+ * delta
+ *
+ * @param delta
+ * updates to the subnet object using patch semantics
+ * @param original
+ * instance of the Neutron Subnet object to be updated
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the update operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canUpdateSubnet(NeutronSubnet delta, NeutronSubnet original);
+
+ /**
+ * Services provide this interface method for taking action after a subnet has been updated
+ *
+ * @param subnet
+ * instance of modified Neutron Subnet object
+ */
+ void neutronSubnetUpdated(NeutronSubnet subnet);
+
+ /**
+ * Services provide this interface method to indicate if the specified subnet can be deleted
+ *
+ * @param subnet
+ * instance of the Subnet Router object to be deleted
+ * @return integer
+ * the return value is understood to be a HTTP status code. A return value outside of 200 through 299
+ * results in the delete operation being interrupted and the returned status value reflected in the
+ * HTTP response.
+ */
+ int canDeleteSubnet(NeutronSubnet subnet);
+
+ /**
+ * Services provide this interface method for taking action after a subnet has been deleted
+ *
+ * @param subnet
+ * instance of deleted Router Subnet object
+ */
+ void neutronSubnetDeleted(NeutronSubnet subnet);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFloatingIPAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronFloatingIPChangeListener implements DataChangeListener, AutoCloseable{
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronFloatingIPChangeListener.class);
+
+ private ListenerRegistration<DataChangeListener> registration;
+ private DataBroker db;
+
+ public NeutronFloatingIPChangeListener(DataBroker db){
+ this.db = db;
+ InstanceIdentifier<Floatingip> path = InstanceIdentifier
+ .create(Neutron.class)
+ .child(Floatingips.class)
+ .child(Floatingip.class);
+ LOG.debug("Register listener for Neutron FloatingIp model data changes");
+ registration =
+ this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+ }
+
+ @Override
+ public void onDataChanged(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+ LOG.trace("Data changes : {}",changes);
+
+ Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronFloatingIPAware.class, this);
+ createFloatingIP(changes, subscribers);
+ updateFloatingIP(changes, subscribers);
+ deleteFloatingIP(changes, subscribers);
+ }
+
+ private void createFloatingIP(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> newFloatingIP : changes.getCreatedData().entrySet()) {
+ if(newFloatingIP.getValue() instanceof Floatingip){
+ NeutronFloatingIP floatingip= fromMd((Floatingip)newFloatingIP.getValue());
+ for(Object entry: subscribers){
+ INeutronFloatingIPAware subscriber = (INeutronFloatingIPAware)entry;
+ subscriber.neutronFloatingIPCreated(floatingip);
+ }
+ }
+ }
+ }
+
+ private void updateFloatingIP(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> updateFloatingIP : changes.getUpdatedData().entrySet()) {
+ if(updateFloatingIP.getValue() instanceof Floatingip){
+ NeutronFloatingIP floatingip = fromMd((Floatingip)updateFloatingIP.getValue());
+ for(Object entry: subscribers){
+ INeutronFloatingIPAware subscriber = (INeutronFloatingIPAware)entry;
+ subscriber.neutronFloatingIPUpdated(floatingip);
+ }
+ }
+ }
+ }
+
+ private void deleteFloatingIP(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (InstanceIdentifier<?> deletedFloatingIPPath : changes.getRemovedPaths()) {
+ if(deletedFloatingIPPath.getTargetType().equals(Floatingip.class)){
+ NeutronFloatingIP floatingip = fromMd((Floatingip)changes.getOriginalData().get(deletedFloatingIPPath));
+ for(Object entry: subscribers){
+ INeutronFloatingIPAware subscriber = (INeutronFloatingIPAware)entry;
+ subscriber.neutronFloatingIPDeleted(floatingip);
+ }
+ }
+ }
+ }
+
+ /*
+ * This method is borrowed from NeutronFloatingIPInterface.java class of Neutron Northbound class.
+ * We will be utilizing similar code from other classes from the same package of neutron project.
+ */
+ private NeutronFloatingIP fromMd(Floatingip fip) {
+ NeutronFloatingIP result = new NeutronFloatingIP();
+ result.setID(String.valueOf(fip.getUuid().getValue()));
+ if (fip.getFloatingNetworkId() != null) {
+ result.setFloatingNetworkUUID(String.valueOf(fip.getFloatingNetworkId().getValue()));
+ }
+ if (fip.getPortId() != null) {
+ result.setPortUUID(String.valueOf(fip.getPortId().getValue()));
+ }
+ if (fip.getFixedIpAddress() != null ) {
+ result.setFixedIPAddress(String.valueOf(fip.getFixedIpAddress().getValue()));
+ }
+ if (fip.getFloatingIpAddress() != null) {
+ result.setFloatingIPAddress(String.valueOf(fip.getFloatingIpAddress().getValue()));
+ }
+ if (fip.getTenantId() != null) {
+ result.setTenantUUID(String.valueOf(fip.getTenantId().getValue()));
+ }
+ if (fip.getRouterId() != null) {
+ result.setRouterUUID(String.valueOf(fip.getRouterId().getValue()));
+ }
+ result.setStatus(fip.getStatus());
+ return result;
+ }
+
+ @Override
+ public void close() throws Exception {
+ registration.close();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, 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.openstack.netvirt.translator.iaware.impl;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronIAwareUtil {
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(NeutronIAwareUtil.class);
+
+ private NeutronIAwareUtil() {
+ }
+
+ public static Object[] getInstances(Class<?> clazz,Object bundle) {
+ Object instances[] = null;
+ try {
+ BundleContext bCtx = FrameworkUtil.getBundle(bundle.getClass())
+ .getBundleContext();
+
+ ServiceReference<?>[] services = null;
+ services = bCtx.getServiceReferences(clazz.getName(),
+ null);
+ if (services != null) {
+ instances = new Object[services.length];
+ for (int i = 0; i < services.length; i++) {
+ instances[i] = bCtx.getService(services[i]);
+ }
+ }
+ } catch (Exception e) {
+ LOGGER.error("Instance reference is NULL", e);
+ }
+ return instances;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2015 Red Hat, 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer_SessionPersistence;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_ID;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Pools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.Pool;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.members.Member;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronLoadBalancerPoolChangeListener implements DataChangeListener, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronLoadBalancerPoolChangeListener.class);
+
+ private static final ImmutableBiMap<Class<? extends ProtocolBase>,String> PROTOCOL_MAP
+ = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>,String>()
+ .put(ProtocolHttp.class, "HTTP")
+ .put(ProtocolHttps.class, "HTTPS")
+ .put(ProtocolIcmp.class, "ICMP")
+ .put(ProtocolTcp.class,"TCP")
+ .build();
+
+ private ListenerRegistration<DataChangeListener> registration;
+ private DataBroker db;
+
+ public NeutronLoadBalancerPoolChangeListener(DataBroker db){
+ this.db = db;
+ InstanceIdentifier<Pool> path = InstanceIdentifier
+ .create(Neutron.class)
+ .child(Pools.class)
+ .child(Pool.class);
+ LOG.debug("Register listener for Neutron Load Balancer Pool model data changes");
+ registration =
+ this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, AsyncDataBroker.DataChangeScope.ONE);
+ }
+
+ @Override
+ public void close() throws Exception {
+ registration.close();
+ }
+
+ @Override
+ public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+ LOG.trace("Data changes : {}", changes);
+
+ Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronLoadBalancerPoolAware.class, this);
+ createPool(changes, subscribers);
+ updatePool(changes, subscribers);
+ deletePool(changes, subscribers);
+ }
+
+ private void createPool(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> newPool : changes.getCreatedData().entrySet()) {
+ if(newPool.getValue() instanceof Pool){
+ NeutronLoadBalancerPool loadBalancerPool = fromMd((Pool) newPool.getValue());
+ for (Object entry : subscribers) {
+ INeutronLoadBalancerPoolAware subscriber = (INeutronLoadBalancerPoolAware) entry;
+ subscriber.neutronLoadBalancerPoolCreated(loadBalancerPool);
+ }
+ }
+ }
+ }
+ private void updatePool(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> updatePool : changes.getUpdatedData().entrySet()) {
+ if(updatePool.getValue() instanceof Pool){
+ NeutronLoadBalancerPool loadBalancerPool = fromMd((Pool)updatePool.getValue());
+ for(Object entry: subscribers){
+ INeutronLoadBalancerPoolAware subscriber = (INeutronLoadBalancerPoolAware) entry;
+ subscriber.neutronLoadBalancerPoolUpdated(loadBalancerPool);
+ }
+ }
+ }
+ }
+ private void deletePool(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (InstanceIdentifier<?> deletedPoolPath : changes.getRemovedPaths()) {
+ if(deletedPoolPath.getTargetType().equals(Pool.class)){
+ NeutronLoadBalancerPool loadBalancerPool = fromMd((Pool)changes.getOriginalData().get(deletedPoolPath));
+ for(Object entry: subscribers){
+ INeutronLoadBalancerPoolAware subscriber = (INeutronLoadBalancerPoolAware) entry;
+ subscriber.neutronLoadBalancerPoolDeleted(loadBalancerPool);
+ }
+ }
+ }
+ }
+
+ /*
+ * This method is borrowed from NeutronLoadBalancerPool.java class of Neutron Northbound class.
+ * in the original location, this method is called extractFields.
+ * We will be utilizing similar code from other classes from the same package of neutron project.
+ */
+ private NeutronLoadBalancerPool fromMd(Pool pool) {
+ NeutronLoadBalancerPool result = new NeutronLoadBalancerPool();
+
+ result.setID(pool.getUuid().getValue());
+ result.setLoadBalancerPoolTenantID(pool.getTenantId().getValue());
+ result.setLoadBalancerPoolName(pool.getName());
+ result.setLoadBalancerPoolDescription(pool.getDescr());
+ result.setLoadBalancerPoolProtocol(PROTOCOL_MAP.get(pool.getProtocol()));
+ result.setLoadBalancerPoolLbAlgorithm(pool.getLbAlgorithm());
+
+ // TODO: setNeutronLoadBalancerPoolHealthMonitorID is a list? Fill in, when its needed.
+ if (pool.getHealthmonitorId() != null) {
+ result.setNeutronLoadBalancerPoolHealthMonitorID(pool.getHealthmonitorId().getValue());
+ }
+
+ result.setLoadBalancerPoolAdminStateIsUp(pool.isAdminStateUp());
+
+ List<Neutron_ID> listeners = new ArrayList();
+ if (pool.getListeners() != null) {
+ for (Uuid listenerUuid : pool.getListeners()) {
+ listeners.add(new Neutron_ID(listenerUuid.getValue()));
+ }
+ }
+ result.setLoadBalancerPoolListeners(listeners);
+
+ if (pool.getSessionPersistence() != null) {
+ NeutronLoadBalancer_SessionPersistence sessionPersistence = new NeutronLoadBalancer_SessionPersistence();
+ sessionPersistence.setCookieName(pool.getSessionPersistence().getCookieName());
+ sessionPersistence.setType(pool.getSessionPersistence().getType());
+ result.setLoadBalancerSessionPersistence(sessionPersistence);
+ }
+
+ List<NeutronLoadBalancerPoolMember> loadBalancerPoolMembers = new ArrayList();
+ if (pool.getMembers() != null) {
+ for (Member member : pool.getMembers().getMember()) {
+ NeutronLoadBalancerPoolMember neutronMember = new NeutronLoadBalancerPoolMember();
+
+ neutronMember.setPoolID(pool.getUuid().getValue());
+ neutronMember.setPoolMemberID(member.getUuid().getValue());
+
+ // TODO: locate and populate remainder attributes, when its needed
+ // member.setPoolMemberAddress(xxx);
+ // member.setPoolMemberAdminStateIsUp(xxx);
+ // member.setPoolMemberProtoPort(xxx);
+ // member.setPoolMemberSubnetID(xxx);
+ // member.setPoolMemberTenantID(xxx);
+ // member.setPoolMemberWeight(xxx);
+
+ loadBalancerPoolMembers.add(neutronMember);
+ }
+ }
+ result.setLoadBalancerPoolMembers(loadBalancerPoolMembers);
+
+ return result;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2015 Red Hat, 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Pools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.Pool;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.PoolKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.Members;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.members.Member;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronLoadBalancerPoolMemberChangeListener implements DataChangeListener, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronLoadBalancerPoolMemberChangeListener.class);
+
+ private ListenerRegistration<DataChangeListener> registration;
+ private DataBroker db;
+
+ public NeutronLoadBalancerPoolMemberChangeListener(DataBroker db){
+ this.db = db;
+ InstanceIdentifier<Member> path = InstanceIdentifier
+ .create(Neutron.class)
+ .child(Pools.class)
+ .child(Pool.class)
+ .child(Members.class)
+ .child(Member.class);
+ LOG.debug("Register listener for Neutron Load Balancer Pool Member model data changes");
+ registration =
+ this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this,
+ AsyncDataBroker.DataChangeScope.ONE);
+ }
+
+ @Override
+ public void close() throws Exception {
+ registration.close();
+ }
+
+ @Override
+ public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+ LOG.trace("Data changes : {}", changes);
+
+ Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronLoadBalancerPoolMemberAware.class, this);
+ createPoolMember(changes, subscribers);
+ updatePoolMember(changes, subscribers);
+ deletePoolMember(changes, subscribers);
+ }
+
+ private void createPoolMember(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> newPoolMember : changes.getCreatedData().entrySet()) {
+ if(newPoolMember.getValue() instanceof Member){
+ NeutronLoadBalancerPoolMember neutronLBPoolMember = fromMd(newPoolMember.getKey(), (Member) newPoolMember.getValue());
+ for (Object entry : subscribers) {
+ INeutronLoadBalancerPoolMemberAware subscriber = (INeutronLoadBalancerPoolMemberAware) entry;
+ subscriber.neutronLoadBalancerPoolMemberCreated(neutronLBPoolMember);
+ }
+ }
+ }
+ }
+ private void updatePoolMember(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> updatePoolMember : changes.getUpdatedData().entrySet()) {
+ if(updatePoolMember.getValue() instanceof Member){
+ NeutronLoadBalancerPoolMember neutronLBPoolMember =
+ fromMd(updatePoolMember.getKey(), (Member) updatePoolMember.getValue());
+ for(Object entry: subscribers){
+ INeutronLoadBalancerPoolMemberAware subscriber = (INeutronLoadBalancerPoolMemberAware) entry;
+ subscriber.neutronLoadBalancerPoolMemberUpdated(neutronLBPoolMember);
+ }
+ }
+ }
+ }
+ private void deletePoolMember(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (InstanceIdentifier<?> deletedPoolMemberPath : changes.getRemovedPaths()) {
+ if(deletedPoolMemberPath.getTargetType().equals(Member.class)){
+ NeutronLoadBalancerPoolMember neutronLBPoolMember =
+ fromMd(deletedPoolMemberPath, (Member) changes.getOriginalData().get(deletedPoolMemberPath));
+ for(Object entry: subscribers){
+ INeutronLoadBalancerPoolMemberAware subscriber = (INeutronLoadBalancerPoolMemberAware) entry;
+ subscriber.neutronLoadBalancerPoolMemberDeleted(neutronLBPoolMember);
+ }
+ }
+ }
+ }
+
+ /*
+ * This method is borrowed from NeutronLoadBalancerPoolMember.java class of Neutron Northbound class.
+ * in the original location, this method is called extractFields.
+ * We will be utilizing similar code from other classes from the same package of neutron project.
+ */
+ private NeutronLoadBalancerPoolMember fromMd(InstanceIdentifier<?> iid, Member member) {
+ NeutronLoadBalancerPoolMember result = new NeutronLoadBalancerPoolMember();
+
+ final PoolKey poolsKey = iid.firstKeyOf(Pool.class, PoolKey.class);
+ if (poolsKey != null) {
+ result.setPoolID(poolsKey.getUuid().getValue());
+ }
+
+ result.setID(member.getUuid().getValue());
+ result.setPoolMemberAdminStateIsUp(member.isAdminStateUp());
+
+ final IpAddress memberIpAddress = member.getAddress();
+ if (memberIpAddress != null) {
+ if (memberIpAddress.getIpv4Address() != null) {
+ result.setPoolMemberAddress(memberIpAddress.getIpv4Address().getValue());
+ } else if (memberIpAddress.getIpv6Address() != null) {
+ result.setPoolMemberAddress(memberIpAddress.getIpv6Address().getValue());
+ }
+ }
+
+ result.setPoolMemberProtoPort(member.getProtocolPort());
+ result.setPoolMemberSubnetID(member.getSubnetId().getValue());
+ result.setPoolMemberTenantID(member.getTenantId().getValue());
+ result.setPoolMemberWeight(member.getWeight());
+
+ return result;
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork_Segment;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronNetworkAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3Extension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronNetworkChangeListener implements DataChangeListener, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronNetworkChangeListener.class);
+
+ private static final ImmutableBiMap<Class<? extends NetworkTypeBase>,String> NETWORK_MAP
+ = new ImmutableBiMap.Builder<Class<? extends NetworkTypeBase>,String>()
+ .put(NetworkTypeFlat.class,"flat")
+ .put(NetworkTypeGre.class,"gre")
+ .put(NetworkTypeVlan.class,"vlan")
+ .put(NetworkTypeVxlan.class,"vxlan")
+ .build();
+
+ private ListenerRegistration<DataChangeListener> registration;
+ private DataBroker db;
+
+ public NeutronNetworkChangeListener(DataBroker db){
+ this.db = db;
+ InstanceIdentifier<Network> path = InstanceIdentifier
+ .create(Neutron.class)
+ .child(Networks.class)
+ .child(Network.class);
+ LOG.debug("Register listener for Neutron Network model data changes");
+ registration =
+ this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+ }
+
+ @Override
+ public void onDataChanged(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+ LOG.trace("Data changes : {}",changes);
+
+ Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronNetworkAware.class, this);
+ createNetwork(changes, subscribers);
+ updateNetwork(changes, subscribers);
+ deleteNetwork(changes, subscribers);
+ }
+
+ private void createNetwork(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> newNetwork : changes.getCreatedData().entrySet()) {
+ if(newNetwork.getValue() instanceof Network){
+ NeutronNetwork network = fromMd((Network)newNetwork.getValue());
+ for(Object entry: subscribers){
+ INeutronNetworkAware subscriber = (INeutronNetworkAware)entry;
+ subscriber.neutronNetworkCreated(network);
+ }
+ }
+ }
+ }
+
+ private void updateNetwork(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> updateNetwork : changes.getUpdatedData().entrySet()) {
+ if(updateNetwork.getValue() instanceof Network){
+ NeutronNetwork network = fromMd((Network)updateNetwork.getValue());
+ for(Object entry: subscribers){
+ INeutronNetworkAware subscriber = (INeutronNetworkAware)entry;
+ subscriber.neutronNetworkUpdated(network);
+ }
+ }
+ }
+ }
+
+ private void deleteNetwork(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (InstanceIdentifier<?> deletedNetworkPath : changes.getRemovedPaths()) {
+ if(deletedNetworkPath.getTargetType().equals(Network.class)){
+ NeutronNetwork network = fromMd((Network)changes.getOriginalData().get(deletedNetworkPath));
+ for(Object entry: subscribers){
+ INeutronNetworkAware subscriber = (INeutronNetworkAware)entry;
+ subscriber.neutronNetworkDeleted(network);
+ }
+ }
+ }
+ }
+
+ /*
+ * This method is borrowed from NeutronNetworkInterface.java class of Neutron Northbound class.
+ * We will be utilizing similar code from other classes from the same package of neutron project.
+ */
+ private NeutronNetwork fromMd(Network network) {
+ NeutronNetwork result = new NeutronNetwork();
+ result.setAdminStateUp(network.isAdminStateUp());
+ result.setNetworkName(network.getName());
+ result.setShared(network.isShared());
+ result.setStatus(network.getStatus());
+ if (network.getSubnets() != null) {
+ List<String> neutronSubnets = new ArrayList<String>();
+ for( Uuid subnet : network.getSubnets()) {
+ neutronSubnets.add(subnet.getValue());
+ }
+ result.setSubnets(neutronSubnets);
+ }
+
+ // todo remove '-' chars as tenant id doesn't use them
+ result.setTenantID(network.getTenantId().getValue());
+ result.setID(network.getUuid().getValue());
+
+ NetworkL3Extension l3Extension = network.getAugmentation(NetworkL3Extension.class);
+ result.setRouterExternal(l3Extension.isExternal());
+
+ NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+ result.setProviderPhysicalNetwork(providerExtension.getPhysicalNetwork());
+ result.setProviderSegmentationID(providerExtension.getSegmentationId());
+ result.setProviderNetworkType(NETWORK_MAP.get(providerExtension.getNetworkType()));
+ List<NeutronNetwork_Segment> segments = new ArrayList<NeutronNetwork_Segment>();
+ if (providerExtension.getSegments() != null) {
+ for (Segments segment: providerExtension.getSegments()) {
+ NeutronNetwork_Segment neutronSegment = new NeutronNetwork_Segment();
+ neutronSegment.setProviderPhysicalNetwork(segment.getPhysicalNetwork());
+ neutronSegment.setProviderSegmentationID(segment.getSegmentationId());
+ neutronSegment.setProviderNetworkType(NETWORK_MAP.get(segment.getNetworkType()));
+ segments.add(neutronSegment);
+ }
+ }
+ result.setSegments(segments);
+ return result;
+ }
+
+ @Override
+ public void close() throws Exception {
+ registration.close();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_AllowedAddressPairs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_ExtraDHCPOption;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_VIFDetail;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronPortAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOpts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronPortChangeListener implements DataChangeListener, AutoCloseable{
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
+
+ private ListenerRegistration<DataChangeListener> registration;
+ private DataBroker db;
+
+ public NeutronPortChangeListener(DataBroker db){
+ this.db = db;
+ InstanceIdentifier<Port> path = InstanceIdentifier
+ .create(Neutron.class)
+ .child(Ports.class)
+ .child(Port.class);
+ LOG.debug("Register listener for Neutron Port model data changes");
+ registration =
+ this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+ }
+
+ @Override
+ public void onDataChanged(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+ LOG.trace("Data changes : {}",changes);
+
+ Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronPortAware.class, this);
+ createPort(changes, subscribers);
+ updatePort(changes, subscribers);
+ deletePort(changes, subscribers);
+ }
+
+ private void createPort(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> newPort : changes.getCreatedData().entrySet()) {
+ if(newPort.getValue() instanceof Port){
+ NeutronPort port = fromMd((Port)newPort.getValue());
+ for(Object entry: subscribers){
+ INeutronPortAware subscriber = (INeutronPortAware)entry;
+ subscriber.neutronPortCreated(port);
+ }
+ }
+ }
+ }
+
+ private void updatePort(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ Map<String, NeutronPort> originalPortMap = getChangedPorts(changes.getOriginalData());
+ for (Entry<InstanceIdentifier<?>, DataObject> updatePort : changes.getUpdatedData().entrySet()) {
+ if (updatePort.getValue() instanceof Port) {
+ NeutronPort port = fromMd((Port)updatePort.getValue());
+ NeutronPort originalPort = originalPortMap.get(port.getID());
+ if (originalPort != null) {
+ port.setOriginalPort(originalPort);
+ } else {
+ LOG.warn("Original Port data is missing");
+ }
+ for (Object entry: subscribers) {
+ INeutronPortAware subscriber = (INeutronPortAware)entry;
+ subscriber.neutronPortUpdated(port);
+ }
+ }
+ }
+ }
+
+ private void deletePort(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (InstanceIdentifier<?> deletedPortPath : changes.getRemovedPaths()) {
+ if(deletedPortPath.getTargetType().equals(Port.class)){
+ NeutronPort port = fromMd((Port)changes.getOriginalData().get(deletedPortPath));
+ for(Object entry: subscribers){
+ INeutronPortAware subscriber = (INeutronPortAware)entry;
+ subscriber.neutronPortDeleted(port);
+ }
+ }
+ }
+ }
+
+ /*
+ * This method is borrowed from NeutronPortInterface.java class of Neutron Northbound class.
+ * We will be utilizing similar code from other classes from the same package of neutron project.
+ */
+ private NeutronPort fromMd(Port port) {
+
+ NeutronPort result = new NeutronPort();
+ result.setAdminStateUp(port.isAdminStateUp());
+ if (port.getAllowedAddressPairs() != null) {
+ List<NeutronPort_AllowedAddressPairs> pairs = new ArrayList<NeutronPort_AllowedAddressPairs>();
+ for (AllowedAddressPairs mdPair : port.getAllowedAddressPairs()) {
+ NeutronPort_AllowedAddressPairs pair = new NeutronPort_AllowedAddressPairs();
+ pair.setIpAddress(mdPair.getIpAddress());
+ pair.setMacAddress(mdPair.getMacAddress());
+ pair.setPortID(mdPair.getPortId());
+ pairs.add(pair);
+ }
+ result.setAllowedAddressPairs(pairs);
+ }
+ result.setDeviceID(port.getDeviceId());
+ result.setDeviceOwner(port.getDeviceOwner());
+ if (port.getExtraDhcpOpts() != null) {
+ List<NeutronPort_ExtraDHCPOption> options = new ArrayList<NeutronPort_ExtraDHCPOption>();
+ for (ExtraDhcpOpts opt : port.getExtraDhcpOpts()) {
+ NeutronPort_ExtraDHCPOption arg = new NeutronPort_ExtraDHCPOption();
+ arg.setName(opt.getOptName());
+ arg.setValue(opt.getOptValue());
+ options.add(arg);
+ }
+ result.setExtraDHCPOptions(options);
+ }
+ if (port.getFixedIps() != null) {
+ List<Neutron_IPs> ips = new ArrayList<Neutron_IPs>();
+ for (FixedIps mdIP : port.getFixedIps()) {
+ Neutron_IPs ip = new Neutron_IPs();
+ ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
+ ip.setSubnetUUID(mdIP.getSubnetId().getValue());
+ ips.add(ip);
+ }
+ result.setFixedIPs(ips);
+ }
+ result.setMacAddress(port.getMacAddress());
+ result.setName(port.getName());
+ result.setNetworkUUID(String.valueOf(port.getNetworkId().getValue()));
+ if (port.getSecurityGroups() != null) {
+ Set<NeutronSecurityGroup> allGroups = new HashSet<NeutronSecurityGroup>();
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces().fetchINeutronSecurityGroupCRUD(this);
+ INeutronSecurityGroupCRUD sgIf = interfaces.getSecurityGroupInterface();
+ for (Uuid sgUuid : port.getSecurityGroups()) {
+ allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+ }
+ List<NeutronSecurityGroup> groups = new ArrayList<NeutronSecurityGroup>();
+ groups.addAll(allGroups);
+ result.setSecurityGroups(groups);
+ }
+ result.setStatus(port.getStatus());
+ if (port.getTenantId() != null) {
+ result.setTenantID(String.valueOf(port.getTenantId().getValue()).replace("-", ""));
+ }
+ result.setPortUUID(String.valueOf(port.getUuid().getValue()));
+ addExtensions(port, result);
+ return result;
+ }
+
+ protected void addExtensions(Port port, NeutronPort result) {
+ PortBindingExtension binding = port.getAugmentation(PortBindingExtension.class);
+ result.setBindinghostID(binding.getHostId());
+ if (binding.getVifDetails() != null) {
+ List<NeutronPort_VIFDetail> details = new ArrayList<NeutronPort_VIFDetail>();
+ for (VifDetails vifDetail : binding.getVifDetails()) {
+ NeutronPort_VIFDetail detail = new NeutronPort_VIFDetail();
+ detail.setPortFilter(vifDetail.isPortFilter());
+ detail.setOvsHybridPlug(vifDetail.isOvsHybridPlug());
+ details.add(detail);
+ }
+ result.setVIFDetail(details);
+ }
+ result.setBindingvifType(binding.getVifType());
+ result.setBindingvnicType(binding.getVnicType());
+ }
+
+ private Map<String,NeutronPort> getChangedPorts(Map<InstanceIdentifier<?>, DataObject> changedData) {
+ LOG.trace("getChangedPorts:" + changedData);
+ Map<String,NeutronPort> portMap = new HashMap<String,NeutronPort>();
+ for (Map.Entry<InstanceIdentifier<?>, DataObject> changed : changedData.entrySet()) {
+ if (changed.getValue() instanceof Port) {
+ NeutronPort port = fromMd((Port)changed.getValue());
+ portMap.put(port.getID(), port);
+ }
+ }
+ return portMap;
+ }
+
+ @Override
+ public void close() throws Exception {
+ registration.close();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_NetworkReference;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronRouterAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronRouterChangeListener implements DataChangeListener, AutoCloseable{
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterChangeListener.class);
+
+ private ListenerRegistration<DataChangeListener> registration;
+ private DataBroker db;
+
+ public NeutronRouterChangeListener(DataBroker db){
+ this.db = db;
+ InstanceIdentifier<Router> path = InstanceIdentifier
+ .create(Neutron.class)
+ .child(Routers.class)
+ .child(Router.class);
+ LOG.debug("Register listener for Neutron Router model data changes");
+ registration =
+ this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+ }
+
+ @Override
+ public void onDataChanged(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+ LOG.trace("Data changes : {}",changes);
+
+ Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronRouterAware.class, this);
+ createRouter(changes, subscribers);
+ updateRouter(changes, subscribers);
+ deleteRouter(changes, subscribers);
+ }
+
+ private void createRouter(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> newRouter : changes.getCreatedData().entrySet()) {
+ if(newRouter.getValue() instanceof Router){
+ NeutronRouter router = fromMd((Router)newRouter.getValue());
+ for(Object entry: subscribers){
+ INeutronRouterAware subscriber = (INeutronRouterAware)entry;
+ subscriber.neutronRouterCreated(router);
+ }
+ }
+ }
+
+ }
+
+ private void updateRouter(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> updateRouter : changes.getUpdatedData().entrySet()) {
+ if(updateRouter.getValue() instanceof Router){
+ NeutronRouter router = fromMd((Router)updateRouter.getValue());
+ for(Object entry: subscribers){
+ INeutronRouterAware subscriber = (INeutronRouterAware)entry;
+ subscriber.neutronRouterUpdated(router);
+ }
+ }
+ }
+ }
+
+ private void deleteRouter(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (InstanceIdentifier<?> deletedRouterPath : changes.getRemovedPaths()) {
+ if(deletedRouterPath.getTargetType().equals(Router.class)){
+ NeutronRouter router = fromMd((Router)changes.getOriginalData().get(deletedRouterPath));
+ for(Object entry: subscribers){
+ INeutronRouterAware subscriber = (INeutronRouterAware)entry;
+ subscriber.neutronRouterDeleted(router);
+ }
+ }
+ }
+ }
+
+ /*
+ * This method is borrowed from NeutronRouterInterface.java class of Neutron Northbound class.
+ * We will be utilizing similar code from other classes from the same package of neutron project.
+ */
+ private NeutronRouter fromMd(Router router) {
+ NeutronRouter result = new NeutronRouter();
+ result.setID(String.valueOf(router.getUuid().getValue()));
+ result.setName(router.getName());
+ result.setTenantID(String.valueOf(router.getTenantId().getValue()));
+ result.setAdminStateUp(router.isAdminStateUp());
+ result.setStatus(router.getStatus());
+ result.setDistributed(router.isDistributed());
+ if (router.getGatewayPortId() != null) {
+ result.setGatewayPortId(String.valueOf(router.getGatewayPortId().getValue()));
+ }
+ if (router.getRoutes() != null) {
+ List<String> routes = new ArrayList<String>();
+ for (String route : router.getRoutes()) {
+ routes.add(route);
+ }
+ result.setRoutes(routes);
+ }
+
+ if (router.getExternalGatewayInfo() != null) {
+ NeutronRouter_NetworkReference extGwInfo = new NeutronRouter_NetworkReference();
+ extGwInfo.setNetworkID(String.valueOf(router.getExternalGatewayInfo().getExternalNetworkId().getValue()));
+ extGwInfo.setEnableSNAT(router.getExternalGatewayInfo().isEnableSnat());
+ if (router.getExternalGatewayInfo().getExternalFixedIps() != null) {
+ List<Neutron_IPs> fixedIPs = new ArrayList<Neutron_IPs>();
+ for (ExternalFixedIps mdFixedIP : router.getExternalGatewayInfo().getExternalFixedIps()) {
+ Neutron_IPs fixedIP = new Neutron_IPs();
+ fixedIP.setSubnetUUID(String.valueOf(mdFixedIP.getSubnetId().getValue()));
+ fixedIP.setIpAddress(String.valueOf(mdFixedIP.getIpAddress().getValue()));
+ fixedIPs.add(fixedIP);
+ }
+ extGwInfo.setExternalFixedIPs(fixedIPs);
+ }
+ result.setExternalGatewayInfo(extGwInfo);
+ }
+
+ if (router.getInterfaces() != null) {
+ Map<String, NeutronRouter_Interface> interfaces = new HashMap<String, NeutronRouter_Interface>();
+ for (Interfaces mdInterface : router.getInterfaces()) {
+ NeutronRouter_Interface pojoInterface = new NeutronRouter_Interface();
+ String id = String.valueOf(mdInterface.getUuid().getValue());
+ pojoInterface.setID(id);
+ pojoInterface.setTenantID(String.valueOf(mdInterface.getTenantId().getValue()));
+ pojoInterface.setSubnetUUID(String.valueOf(mdInterface.getSubnetId().getValue()));
+ pojoInterface.setPortUUID(String.valueOf(mdInterface.getPortId().getValue()));
+ interfaces.put(id, pojoInterface);
+ }
+ result.setInterfaces(interfaces);
+ }
+ return result;
+ }
+
+ @Override
+ public void close() throws Exception {
+ registration.close();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroups;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronSecurityGroupDataChangeListener implements
+ DataChangeListener, AutoCloseable {
+ private static final Logger LOG = LoggerFactory
+ .getLogger(NeutronSecurityGroupDataChangeListener.class);
+
+ private ListenerRegistration<DataChangeListener> registration;
+ private DataBroker db;
+
+ public NeutronSecurityGroupDataChangeListener(DataBroker db) {
+ this.db = db;
+ InstanceIdentifier<SecurityGroup> path = InstanceIdentifier
+ .create(Neutron.class).child(SecurityGroups.class)
+ .child(SecurityGroup.class);
+ LOG.debug("Register listener for Neutron Secutiry group model data changes");
+ registration = this.db.registerDataChangeListener(
+ LogicalDatastoreType.CONFIGURATION, path, this,
+ DataChangeScope.ONE);
+
+ }
+
+ @Override
+ public void onDataChanged(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+ LOG.trace("Data changes : {}", changes);
+
+ Object[] subscribers = NeutronIAwareUtil.getInstances(
+ INeutronSecurityGroupAware.class, this);
+ createSecurityGroup(changes, subscribers);
+ updateSecurityGroup(changes, subscribers);
+ deleteSecurityGroup(changes, subscribers);
+ }
+
+ private void createSecurityGroup(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> newSecutiryGroup : changes
+ .getCreatedData().entrySet()) {
+ if (newSecutiryGroup.getValue() instanceof SecurityGroup) {
+ NeutronSecurityGroup secutiryGroup = fromMd((SecurityGroup) newSecutiryGroup
+ .getValue());
+ for (Object entry : subscribers) {
+ INeutronSecurityGroupAware subscriber = (INeutronSecurityGroupAware) entry;
+ subscriber.neutronSecurityGroupCreated(secutiryGroup);
+ }
+ }
+ }
+
+ }
+
+ private void updateSecurityGroup(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> updateSecurityGroup : changes
+ .getUpdatedData().entrySet()) {
+ if (updateSecurityGroup.getValue() instanceof SecurityGroup) {
+ NeutronSecurityGroup securityGroup = fromMd((SecurityGroup) updateSecurityGroup
+ .getValue());
+ for (Object entry : subscribers) {
+ INeutronSecurityGroupAware subscriber = (INeutronSecurityGroupAware) entry;
+ subscriber.neutronSecurityGroupUpdated(securityGroup);
+ }
+ }
+ }
+ }
+
+ private void deleteSecurityGroup(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (InstanceIdentifier<?> deletedSecurityGroup : changes
+ .getRemovedPaths()) {
+ if (deletedSecurityGroup.getTargetType()
+ .equals(SecurityGroup.class)) {
+ NeutronSecurityGroup securityGroup = fromMd((SecurityGroup) changes
+ .getOriginalData().get(deletedSecurityGroup));
+ for (Object entry : subscribers) {
+ INeutronSecurityGroupAware subscriber = (INeutronSecurityGroupAware) entry;
+ subscriber.neutronSecurityGroupDeleted(securityGroup);
+ }
+ }
+ }
+ }
+
+ private NeutronSecurityGroup fromMd(SecurityGroup group) {
+ NeutronSecurityGroup answer = new NeutronSecurityGroup();
+ if (group.getName() != null) {
+ answer.setSecurityGroupName(group.getName());
+ }
+ if (group.getDescription() != null) {
+ answer.setSecurityGroupDescription(group.getDescription());
+ }
+ if (group.getTenantId() != null) {
+ answer.setSecurityGroupTenantID(group.getTenantId().getValue()
+ .replace("-", ""));
+ }
+ if (group.getSecurityRules() != null) {
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+ .fetchINeutronSecurityRuleCRUD(this);
+ INeutronSecurityRuleCRUD srCrud = interfaces
+ .getSecurityRuleInterface();
+
+ List<NeutronSecurityRule> rules = new ArrayList<NeutronSecurityRule>();
+ for (Uuid uuid : group.getSecurityRules()) {
+ rules.add(srCrud.getNeutronSecurityRule(uuid.getValue()));
+ }
+ answer.setSecurityRules(rules);
+ }
+ if (group.getUuid() != null) {
+ answer.setID(group.getUuid().getValue());
+ }
+ return answer;
+ }
+
+ @Override
+ public void close() throws Exception {
+ registration.close();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronSecurityRuleDataChangeListener implements DataChangeListener, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleDataChangeListener.class);
+
+ private static final ImmutableBiMap<Class<? extends DirectionBase>, String> DIRECTION_MAP
+ = new ImmutableBiMap.Builder<Class<? extends DirectionBase>, String>()
+ .put(DirectionEgress.class, "egress")
+ .put(DirectionIngress.class, "ingress").build();
+ private static final ImmutableBiMap<Class<? extends ProtocolBase>, String> PROTOCOL_MAP
+ = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>, String>()
+ .put(ProtocolHttp.class, "HTTP")
+ .put(ProtocolHttps.class, "HTTPS")
+ .put(ProtocolIcmp.class, "ICMP")
+ .put(ProtocolTcp.class, "TCP")
+ .build();
+ private static final ImmutableBiMap<Class<? extends EthertypeBase>, String> ETHERTYPE_MAP
+ = new ImmutableBiMap.Builder<Class<? extends EthertypeBase>, String>()
+ .put(EthertypeV4.class, "v4")
+ .put(EthertypeV6.class, "v6")
+ .build();
+
+ private ListenerRegistration<DataChangeListener> registration;
+ private DataBroker db;
+
+ public NeutronSecurityRuleDataChangeListener(DataBroker db) {
+ this.db = db;
+ InstanceIdentifier<SecurityRule> path = InstanceIdentifier
+ .create(Neutron.class).child(SecurityRules.class)
+ .child(SecurityRule.class);
+ LOG.debug("Register listener for Neutron Secutiry rules model data changes");
+ registration = this.db.registerDataChangeListener(
+ LogicalDatastoreType.CONFIGURATION, path, this,
+ DataChangeScope.ONE);
+
+ }
+
+ @Override
+ public void onDataChanged(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+ LOG.trace("Data changes : {}", changes);
+
+ Object[] subscribers = NeutronIAwareUtil.getInstances(
+ INeutronSecurityRuleAware.class, this);
+ createSecurityRule(changes, subscribers);
+ updateSecurityRule(changes, subscribers);
+ deleteSecurityRule(changes, subscribers);
+ }
+
+ private void createSecurityRule(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> newSecutiryRule : changes
+ .getCreatedData().entrySet()) {
+ if (newSecutiryRule.getValue() instanceof SecurityRule) {
+ NeutronSecurityRule secutiryRule = fromMd((SecurityRule) newSecutiryRule
+ .getValue());
+ for (Object entry : subscribers) {
+ INeutronSecurityRuleAware subscriber = (INeutronSecurityRuleAware) entry;
+ subscriber.neutronSecurityRuleCreated(secutiryRule);
+ }
+ }
+ }
+
+ }
+
+ private void updateSecurityRule(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> updateSecurityRule : changes
+ .getUpdatedData().entrySet()) {
+ if (updateSecurityRule.getValue() instanceof SecurityRule) {
+ NeutronSecurityRule securityRule = fromMd((SecurityRule) updateSecurityRule
+ .getValue());
+ for (Object entry : subscribers) {
+ INeutronSecurityRuleAware subscriber = (INeutronSecurityRuleAware) entry;
+ subscriber.neutronSecurityRuleUpdated(securityRule);
+ }
+ }
+ }
+ }
+
+ private void deleteSecurityRule(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (InstanceIdentifier<?> deletedSecurityRule : changes
+ .getRemovedPaths()) {
+ if (deletedSecurityRule.getTargetType().equals(SecurityRule.class)) {
+ NeutronSecurityRule securityRule = fromMd((SecurityRule) changes
+ .getOriginalData().get(deletedSecurityRule));
+ for (Object entry : subscribers) {
+ INeutronSecurityRuleAware subscriber = (INeutronSecurityRuleAware) entry;
+ subscriber.neutronSecurityRuleDeleted(securityRule);
+ }
+ }
+ }
+ }
+
+ private NeutronSecurityRule fromMd(SecurityRule rule) {
+ NeutronSecurityRule answer = new NeutronSecurityRule();
+ if (rule.getTenantId() != null) {
+ answer.setSecurityRuleTenantID(rule.getTenantId().getValue()
+ .replace("-", ""));
+ }
+ if (rule.getDirection() != null) {
+ answer.setSecurityRuleDirection(DIRECTION_MAP.get(rule
+ .getDirection()));
+ }
+ if (rule.getSecurityGroupId() != null) {
+ answer.setSecurityRuleGroupID(rule.getSecurityGroupId().getValue());
+ }
+ if (rule.getRemoteGroupId() != null) {
+ answer.setSecurityRemoteGroupID(rule.getRemoteGroupId().getValue());
+ }
+ if (rule.getRemoteIpPrefix() != null) {
+ answer.setSecurityRuleRemoteIpPrefix(rule.getRemoteIpPrefix().getIpv4Prefix()!= null?
+ rule.getRemoteIpPrefix().getIpv4Prefix().getValue():rule.getRemoteIpPrefix().getIpv6Prefix().getValue());
+ }
+ if (rule.getProtocol() != null) {
+ answer.setSecurityRuleProtocol(PROTOCOL_MAP.get(rule.getProtocol()));
+ }
+ if (rule.getEthertype() != null) {
+ answer.setSecurityRuleEthertype(ETHERTYPE_MAP.get(rule
+ .getEthertype()));
+ }
+ if (rule.getPortRangeMin() != null) {
+ answer.setSecurityRulePortMin(Integer.valueOf(rule
+ .getPortRangeMin()));
+ }
+ if (rule.getPortRangeMax() != null) {
+ answer.setSecurityRulePortMax(Integer.valueOf(rule
+ .getPortRangeMax()));
+ }
+ if (rule.getId() != null) {
+ answer.setID(rule.getId().getValue());
+ }
+ return answer;
+ }
+
+ @Override
+ public void close() throws Exception {
+ registration.close();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, 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.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnetIPAllocationPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSubnetAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Base;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Off;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Slaac;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateful;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateless;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronSubnetChangeListener implements DataChangeListener, AutoCloseable{
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronSubnetChangeListener.class);
+
+ private static final ImmutableBiMap<Class<? extends IpVersionBase>,Integer> IPV_MAP
+ = new ImmutableBiMap.Builder<Class<? extends IpVersionBase>,Integer>()
+ .put(IpVersionV4.class,Integer.valueOf(4))
+ .put(IpVersionV6.class,Integer.valueOf(6))
+ .build();
+
+ private static final ImmutableBiMap<Class<? extends Dhcpv6Base>,String> DHCPV6_MAP
+ = new ImmutableBiMap.Builder<Class<? extends Dhcpv6Base>,String>()
+ .put(Dhcpv6Off.class,"off")
+ .put(Dhcpv6Stateful.class,"dhcpv6-stateful")
+ .put(Dhcpv6Slaac.class,"slaac")
+ .put(Dhcpv6Stateless.class,"dhcpv6-stateless")
+ .build();
+
+ private ListenerRegistration<DataChangeListener> registration;
+ private DataBroker db;
+
+ public NeutronSubnetChangeListener(DataBroker db){
+ this.db = db;
+ InstanceIdentifier<Subnet> path = InstanceIdentifier
+ .create(Neutron.class)
+ .child(Subnets.class)
+ .child(Subnet.class);
+ LOG.debug("Register listener for Neutron Subnet model data changes");
+ registration =
+ this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+ }
+
+ @Override
+ public void onDataChanged(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+ LOG.trace("Data changes : {}",changes);
+
+ Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronSubnetAware.class, this);
+ createSubnet(changes, subscribers);
+ updateSubnet(changes, subscribers);
+ deleteSubnet(changes, subscribers);
+ }
+
+ private void createSubnet(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> newSubnet : changes.getCreatedData().entrySet()) {
+ if(newSubnet.getValue() instanceof Subnet){
+ NeutronSubnet subnet = fromMd((Subnet)newSubnet.getValue());
+ for(Object entry: subscribers){
+ INeutronSubnetAware subscriber = (INeutronSubnetAware)entry;
+ subscriber.neutronSubnetCreated(subnet);
+ }
+ }
+ }
+ }
+
+ private void updateSubnet(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (Entry<InstanceIdentifier<?>, DataObject> updateSubnet : changes.getUpdatedData().entrySet()) {
+ if(updateSubnet.getValue() instanceof Subnet){
+ NeutronSubnet subnet = fromMd((Subnet)updateSubnet.getValue());
+ for(Object entry: subscribers){
+ INeutronSubnetAware subscriber = (INeutronSubnetAware)entry;
+ subscriber.neutronSubnetUpdated(subnet);
+ }
+ }
+ }
+ }
+
+ private void deleteSubnet(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+ Object[] subscribers) {
+ for (InstanceIdentifier<?> deletedSubnetPath : changes.getRemovedPaths()) {
+ if(deletedSubnetPath.getTargetType().equals(Subnet.class)){
+ NeutronSubnet subnet = fromMd((Subnet)changes.getOriginalData().get(deletedSubnetPath));
+ for(Object entry: subscribers){
+ INeutronSubnetAware subscriber = (INeutronSubnetAware)entry;
+ subscriber.neutronSubnetDeleted(subnet);
+ }
+ }
+ }
+ }
+
+ /*
+ * This method is borrowed from NeutronSubnetInterface.java class of Neutron Northbound class.
+ * We will be utilizing similar code from other classes from the same package of neutron project.
+ */
+ private NeutronSubnet fromMd(Subnet subnet) {
+ NeutronSubnet result = new NeutronSubnet();
+ result.setName(subnet.getName());
+ result.setTenantID(String.valueOf(subnet.getTenantId().getValue()).replace("-",""));
+ result.setNetworkUUID(subnet.getNetworkId().getValue());
+ result.setIpVersion(IPV_MAP.get(subnet.getIpVersion()));
+ result.setCidr(subnet.getCidr());
+ result.setGatewayIP(String.valueOf(subnet.getGatewayIp().getValue()));
+ result.setIpV6RaMode(DHCPV6_MAP.get(subnet.getIpv6RaMode()));
+ result.setIpV6AddressMode(DHCPV6_MAP.get(subnet.getIpv6AddressMode()));
+ result.setEnableDHCP(subnet.isEnableDhcp());
+ if (subnet.getAllocationPools() != null) {
+ List<NeutronSubnetIPAllocationPool> allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
+ for (AllocationPools allocationPool : subnet.getAllocationPools()) {
+ NeutronSubnetIPAllocationPool pool = new NeutronSubnetIPAllocationPool();
+ pool.setPoolStart(allocationPool.getStart());
+ pool.setPoolEnd(allocationPool.getEnd());
+ allocationPools.add(pool);
+ }
+ result.setAllocationPools(allocationPools);
+ }
+ if (subnet.getDnsNameservers() != null) {
+ List<String> dnsNameServers = new ArrayList<String>();
+ for (IpAddress dnsNameServer : subnet.getDnsNameservers()) {
+ dnsNameServers.add(String.valueOf(dnsNameServer.getValue()));
+ }
+ result.setDnsNameservers(dnsNameServers);
+ }
+ result.setID(subnet.getUuid().getValue());
+
+ // read through the ports and put the ones in this subnet into the internal
+ // myPorts object.
+ Set<NeutronPort> allPorts = new HashSet<NeutronPort>();
+ NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+ .fetchINeutronPortCRUD(this);
+ INeutronPortCRUD portIf = interfaces.getPortInterface();
+ for (NeutronPort port : portIf.getAllPorts()) {
+ if (port.getFixedIPs() != null) {
+ for (Neutron_IPs ip : port.getFixedIPs()) {
+ if (ip.getSubnetUUID().equals(result.getID())) {
+ allPorts.add(port);
+ }
+ }
+ }
+ }
+ List<NeutronPort> ports = new ArrayList<NeutronPort>();
+ ports.addAll(allPorts);
+ result.setPorts(ports);
+ return result;
+ }
+
+ @Override
+ public void close() throws Exception {
+ registration.close();
+ }
+
+}
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronFirewall;
-import org.opendaylight.neutron.spi.NeutronFirewallPolicy;
-import org.opendaylight.neutron.spi.NeutronFirewallRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
import org.osgi.framework.ServiceReference;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
import org.powermock.modules.junit4.PowerMockRunner;
/**
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
import org.osgi.framework.ServiceReference;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
import org.opendaylight.ovsdb.openstack.netvirt.SouthboundEvent.Type;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbTables;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
import org.opendaylight.ovsdb.openstack.netvirt.api.VlanConfigurationCache;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
/*
-* Copyright (C) 2014 Red Hat, Inc.
+* Copyright (C) 2014 Red Hat, 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,
<url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
</scm>
<dependencies>
- <dependency>
- <groupId>org.opendaylight.dlux</groupId>
- <artifactId>loader</artifactId>
- <version>${dlux.loader.version}</version>
+ <dependency>
+ <groupId>org.opendaylight.dlux</groupId>
+ <artifactId>loader</artifactId>
+ <version>${dlux.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.ovsdb</groupId>
<property name="angularJs" value="app.ovsdb"/>
<property name="cssDependencies">
<list>
- <value>src/app/ovsdb/ovsdb.css</value>
+ <value>src/app/ovsdb/css/select2.min.css</value>
+ <value>src/app/ovsdb/css/toggle-switch.css</value>
+ <value>src/app/ovsdb/css/ovsdb.css</value>
</list>
</property>
</bean>
--- /dev/null
+define(['app/ovsdb/lib/d3.min', 'app/ovsdb/OvsCore', 'app/ovsdb/matrix', 'underscore'], function(d3, OvsCore, Geom, _) {
+ 'use strict';
+
+ var root = null,
+ forceLayout = null,
+ baseBB = null,
+ nodes = null,
+ links = null,
+ nodeData = [],
+ linkData = [],
+ drag = null,
+ nodePosCache = null;
+
+ function Graph(id, width, height) {
+ var x = d3.scale.linear()
+ .domain([0, width])
+ .range([0, width]);
+
+ var y = d3.scale.linear()
+ .domain([0, height])
+ .range([height, 0]);
+
+ var tmp = d3.select(id).append("svg")
+ .attr('width', width)
+ .attr('height', height)
+ .append("svg:g")
+ .attr('class', 'layer_0');
+
+ tmp.append('svg:rect')
+ .attr('width', width)
+ .attr('height', height)
+ .attr('fill', 'white');
+
+ root = tmp.call(d3.behavior.zoom().x(x).y(y).scaleExtent([1, 6]).on("zoom", zoom))
+ .append("g");
+
+ this.matrix = new Geom.Matrix();
+
+ // this._bg = tmp.insert('svg:polygon', ':first-child');
+ // this._bg.attr('id', 'ttt').attr('fill', 'rgb(250, 220, 220)').attr('stroke', 'rgb(250,0,0)');
+
+ drag = d3.behavior.drag()
+ .origin(function(d) {
+ return d;
+ })
+ .on("dragstart", dragstarted.bind(this))
+ .on("drag", dragmove.bind(this))
+ .on("dragend", dragend.bind(this));
+
+ // a layout for the bridge and his link
+ forceLayout = new d3.layout.force()
+ .gravity(0.05)
+ .charge(-400)
+ .linkDistance(80)
+ .size([width, height])
+ .on('tick', this.update.bind(this));
+
+ addDefs();
+ }
+
+ function zoom() {
+ root.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
+ }
+
+ function dragstarted(d) {
+ d3.event.sourceEvent.stopPropagation();
+ forceLayout.stop();
+ }
+
+ function dragmove(d) {
+ d.x += d3.event.dx;
+ d.y += d3.event.dy;
+ d.px += d3.event.dx;
+ d.py += d3.event.dy;
+ this.update();
+ }
+
+ function dragend(d) {
+ d.fixed = true;
+ this.update();
+ forceLayout.resume();
+ baseBB = null;
+ }
+
+ // Define reusable svg item like box-shadow
+ function addDefs() {
+ // box-shadow
+ var defs = d3.select('svg').insert('svg:defs', ':first-child');
+ var filter = defs.append('svg:filter').attr('id', 'selectNode').attr('x', '-20%').attr('y', '-20%').attr('width', '140%').attr('height', '140%');
+ filter.append('feGaussianBlur').attr('stdDeviation', '2').attr('result', 'coloredBlur');
+ var femerge = filter.append('feMerge');
+ femerge.append('feMergeNode').attr('in', 'coloredBlur');
+ femerge.append('feMergeNode').attr('in', 'SourceGraphic');
+ }
+
+ function sortLink(links) {
+ links.sort(function(a,b) {
+ if (a.source > b.source) {
+ return 1;
+ } else if (a.source < b.source) {
+ return -1;
+ }
+ else {
+ if (a.target > b.target) {
+ return 1;
+ }
+ if (a.target < b.target) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ });
+ }
+
+ function setLinkIndexAndNum(links) {
+ _.each(links, function(link, i) {
+ if (i != 0 && links[i].source == links[i-1].source &&
+ links[i].target == links[i-1].target) {
+ links[i].linkindex = links[i-1].linkindex + 1;
+ } else {
+ links[i].linkindex = 1;
+ }
+ });
+ }
+
+ // Properties to quick access and set nodes and links
+ Object.defineProperties(Graph.prototype, {
+ links: {
+ get: function() {
+ return links;
+ },
+ set: function(value) {
+ sortLink(value);
+ setLinkIndexAndNum(value);
+
+ forceLayout.links(value);
+ links = root.selectAll('links')
+ .data(value)
+ .enter().append('svg:path')
+ .attr('class', function(d) {
+ return d.linkType;
+ })
+ .attr('fill', 'none')
+ .attr('stroke-dasharray', function(d) {
+ return d.dashArray;
+ })
+ .attr('stroke-width', function(d) {
+ return d.width;
+ })
+ .attr('stroke', function(d) {
+ return d.color;
+ });
+ }
+ },
+ nodes: {
+ get: function() {
+ return nodes;
+ },
+ set: function(value) {
+ var _this = this; // context change in callback function and we need both
+
+ forceLayout.nodes(value);
+ nodes = root.selectAll('.nodes')
+ .data(value)
+ .enter().append('svg:g')
+ .call(drag)
+ .attr('class', function(d) {
+ return (d.node instanceof OvsCore.BridgeNode) ? 'bridge' : 'switch';
+ })
+ .on('click', function(d) {
+ if (d3.event.defaultPrevented) return;
+ _this.onNodeClick(d, nodes, links, this);
+ })
+ .on("mouseover", function(d) {
+ _this.onNodeOver(d, nodes, links, this);
+ })
+ .on("mouseout", function(d) {
+ _this.onNodeOut(d, nodes, links, this);
+ });
+
+ nodes.append('text')
+ .attr('x', 0)
+ .attr('y', 30)
+ .attr('fill', 'black')
+ .attr('text-anchor', 'middle')
+ .text(function(d) {
+ if (d.node instanceof OvsCore.BridgeNode)
+ return d.node.flowInfo.ip;
+ else
+ return d.node.otherLocalIp;
+ });
+
+ //svg node
+ var layer = d3.selectAll('g.switch').append('svg:g').attr('class', 'switch').attr('transform', 'translate(-16 -16)');
+ layer.append('svg:rect').style('fill-rule', 'evenodd').attr('ry', '3.6808').attr('height', '28.901')
+ .attr('width', '28.784').style('stroke', '#002b69').attr('y', '0').attr('x', '0').style('stroke-width', "3px").style('fill', '#2a7fff');
+ layer.append('svg:path').attr('d', 'm27.043 6.2-5.0754 3.3764-.01018-2.1082-5.9209-.022.01773-2.6018 5.9031-.037.08118-2.1164z').style('fill', "#002b69");
+ layer.append('svg:path').attr('d', "m26.866 19.4-5.0754 3.3764-.01018-2.1082-5.9209-.022.01773-2.6018 5.9031-.037.08118-2.1164z").style('fill', "#002b69");
+ layer.append('svg:path').attr('d', "m3.0872 11.6 5.0754 3.3764.01018-2.1082 5.9209-.022-.01773-2.6018-5.9031-.037-.08118-2.1164z").style('fill', "#002b69");
+ layer.append('svg:path').attr('d', "m3.2639 24.8 5.0754 3.3764.01018-2.1082 5.9209-.022-.01773-2.6018-5.9031-.037-.08118-2.1164z").style('fill', "#002b69");
+
+ //svg bridge
+ var layer = d3.selectAll('g.bridge').append('svg:g').attr('transform', 'translate(-16 -16)');
+ layer.append('svg:path').style('fill', '#d40000').style('stroke', '#ff0000').style('stroke-width', '0.10413094')
+ .style('stroke-linecap', 'round') //stroke-linejoin:round
+ .attr('d', 'm 2.9656662,3.4868 c 4.8978761,7.5117 16.2156478,6.1742 21.9929178,2.0807 l 2.154019,-1.5814 -0.08265,18.1941 -2.055088,2.0313 -24.17161713,0.055 -0.0255688,-18.6893 z');
+ layer.append('svg:path').style('fill', '#ff5555').style('stroke', '#ff0000').style('stroke-width', '0.10413094')
+ .style('stroke-linecap', 'round') //stroke-linejoin:round
+ .attr('d', 'm 0.83642587,5.5637 c 4.89787603,7.5117 18.41115613,4.1109 24.18842613,0.018 l -0.06627,18.6546 -24.12215693,0 z');
+ }
+ }
+ });
+
+ // Update the node and link position on the canvas
+ Graph.prototype.update = function(e) {
+ var k = 1 , //.1 * e.alpha
+ isDragging = (e !== null)
+/*
+ if (!isDragging) {
+ k = .1 * e.alpha;
+ }
+
+ if (!isDragging) {
+ forceLayout.nodes().forEach(function(o) {
+ var i = (o.node instanceof OvsCore.OvsNode) ? 1 : 0;
+ o.y += (layerAnchor[i].y - o.y) * k;
+ o.x += (layerAnchor[i].x - o.x) * k;
+ });
+ }*/
+
+ if (links) {
+ links.attr('d', (function(d) {
+ var srcT = this.matrix.transformPoint(d.source.x, d.source.y),
+ targetT = this.matrix.transformPoint(d.target.x, d.target.y),
+ src = {x:srcT.elements[0],y:srcT.elements[1]},
+ tgt = {x:targetT.elements[0],y:targetT.elements[1]},
+ anchor1 = {}, anchor2 = {};
+
+ if (d.linkType === 'tunnel') {
+ // curve the line and arc it on a direction of a 90 degree vector
+ var perp = { x : -tgt.y, y: tgt.x};
+ var srcNorm = Math.sqrt(src.x * src.x + src.y * src.y);
+ var perpNorm = Math.sqrt(perp.x * perp.x + perp.y * perp.y);
+ var dy = (perp.y/perpNorm - src.y/srcNorm);
+ var dx = (perp.x/perpNorm - src.x/srcNorm);
+
+ anchor1 = {x: src.x - dx * 30, y: src.y - dy * 30 };
+ anchor2 = {x: tgt.x - dx * 30, y: tgt.y - dy * 30 };
+ } else {
+ // default strait line
+ anchor1 = src;
+ anchor2 = tgt;
+ }
+
+ return OvsCore.Util.String.Format('M{0},{1} C{2},{3} {4},{5} {6},{7}',
+ srcT.elements[0], srcT.elements[1],
+ anchor1.x, anchor1.y,
+ anchor2.x, anchor2.y,
+ targetT.elements[0], targetT.elements[1]
+ );
+ }).bind(this));
+ }
+
+ nodes.attr("transform", (function(d) {
+ var a = new Geom.Matrix.fromString(root.attr('transform'));
+ var tmp = Geom.Matrix.combine(a, this.matrix);
+
+ var transV = this.matrix.transformPoint(d.x, d.y);
+ var v = tmp.transformPoint(d.x, d.y);
+ d.pos = {
+ x: v.elements[0],
+ y: v.elements[1]
+ };
+ nodePosCache[d.node.nodeId] = { pos: d.pos, fixed: d.fixed};
+ return "translate(" + transV.elements[0] + ',' + transV.elements[1] + ')';
+ }).bind(this));
+ };
+
+ Graph.prototype.setPosCache = function(cache) {
+ nodePosCache = cache;
+ };
+
+ // Apply few matrix transform to fake a perspective effet
+ Graph.prototype.applyPerspective = function(value) {
+ if (!baseBB)
+ baseBB = root.node().getBBox();
+
+ var padding = 50;
+ var persMatrix = new Geom.Matrix()
+ .translate(-(baseBB.x + baseBB.width / 2), -(baseBB.y + baseBB.height / 2))
+ .skew(-25, 0)
+ .scale(1, 0.6)
+ .translate(baseBB.x + baseBB.width / 2, baseBB.y + baseBB.height / 2);
+
+ this.matrix.transform = value ? this.matrix.transform.x(persMatrix.transform) : this.matrix.transform.x(persMatrix.transform.inverse());
+
+ var p1 = this.matrix.transformPoint(baseBB.x - padding, baseBB.y - padding);
+ var p2 = this.matrix.transformPoint(baseBB.x - padding, baseBB.y + baseBB.height + padding);
+ var p3 = this.matrix.transformPoint(baseBB.x + baseBB.width + padding, baseBB.y + baseBB.height + padding);
+ var p4 = this.matrix.transformPoint(baseBB.x + baseBB.width + padding, baseBB.y - padding);
+
+ this._bg.attr('points', OvsCore.Util.String.Format("{0},{1} {2},{3} {4},{5} {6},{7}",
+ p1.elements[0],
+ p1.elements[1],
+ //--
+ p2.elements[0],
+ p2.elements[1],
+ //--
+ p3.elements[0],
+ p3.elements[1],
+ //--
+ p4.elements[0],
+ p4.elements[1])).style('display', (value) ? 'block' : 'none');
+
+ this.update();
+ };
+
+ function positionateBaseOnCache() {
+ forceLayout.stop();
+ forceLayout.nodes().forEach(function(d) {
+ var nodeCached = nodePosCache[d.node.nodeId];
+ d.px = d.x = nodeCached.pos.x;
+ d.py = d.y = nodeCached.pos.y;
+ d.fixed = nodeCached.fixed;
+ });
+ forceLayout.resume();
+ }
+
+ // start the force layout
+ Graph.prototype.start = function() {
+ forceLayout.linkStrength(function(link) {
+ if (link.linkType === 'bridgeOvsLink') {
+ return 0;
+ }
+ return 1;
+ });
+ forceLayout.start();
+ if (_.size(nodePosCache) > 0) {
+ positionateBaseOnCache();
+ }
+ };
+
+ Graph.prototype.freeDOM = function() {
+ nodes.remove();
+ links.remove();
+ forceLayout.nodes([]);
+ forceLayout.links([]);
+ };
+
+ // Enable to manipulate attributes of the graph group node
+ Graph.prototype.attr = function(name, value) {
+ return root.attr(name, value);
+ };
+
+ // Enable the monipulate the css of the graph group node
+ Graph.prototype.style = function(name, value) {
+ return root.style(name, value);
+ };
+
+ Graph.prototype.selectAll = function(a) {
+ return root.selectAll(a);
+ };
+
+ // callback function
+ Graph.prototype.onNodeOver = _.noop;
+ Graph.prototype.onNodeOut = _.noop;
+ Graph.prototype.onNodeClick = _.noop;
+
+ return Graph;
+});
--- /dev/null
+define(['app/ovsdb/lib/d3.min', 'app/ovsdb/OvsCore', 'underscore'], function(d3, OvsCore, _) {
+ 'use strict';
+
+ var root = null,
+ canvasWidth = -1,
+ canvasHeight = -1,
+ bbox = { x:0, y:15, width: 0, height: 0},
+ // config
+ nodeWidth = 15,
+ nodeHeight = -1,
+ defaultRouterWidth = 66,
+ defaultRouterHeight = 66,
+ networkMargin = { width: 120, height: 15},
+ routerMargin = { width: 120, height: 40},
+ vmMargin = { width: 90, height: 30},
+ defaultVmsWidth = 48,
+ defaultVmsHeight = 48,
+ ipNetworkTextMaxLength = 60,
+ networkOffset = 15,
+ linkHeight = 5,
+ // datas
+ networkData = [],
+ routerData = [],
+ vmData = [],
+ linkData = [],
+ tmpNetHolder = {},
+ // d3 layer over datas
+ d3Node = null,
+ d3Link = null,
+ d3Vm = null,
+ d3Router = null,
+ randomize = OvsCore.Util.Math.Random(42);
+
+ function LogicalGraph(id, width , height) {
+ canvasWidth = width;
+ canvasHeight = height;
+
+ nodeHeight = height - 15;
+
+ var tmp = d3.select(id).append("svg")
+ .attr('width', width)
+ .attr('height', height)
+ .append("svg:g")
+ .attr('class', 'layer_0');
+
+ tmp.append('svg:rect')
+ .attr('width', width)
+ .attr('height', height)
+ .attr('fill', 'white');
+
+ root = tmp.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
+ .append("g");
+ tmp.on("dblclick.zoom", null);
+ addDefs();
+ }
+
+ // Define reusable svg item like box-shadow
+ function addDefs() {
+ // box-shadow
+ var defs = d3.select('svg').insert('svg:defs', ':first-child');
+ var filter = defs.append('svg:filter').attr('id', 'boxShadow').attr('x', '0').attr('y', '0').attr('width', '200%').attr('height', '200%');
+ filter.append('feOffset').attr('in', 'SourceAlpha').attr('result', 'offOut').attr('dx', 0).attr('dy', 0);
+ filter.append('feGaussianBlur').attr('stdDeviation', '5').attr('in','offOut').attr('result', 'blurOut');
+ filter.append('feOffset').attr('in', 'SourceGraphic').attr('in2', 'blurOut').attr('mode', 'normal');
+ }
+
+ function zoom() {
+ root.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
+ }
+
+ Object.defineProperties(LogicalGraph.prototype, {
+ networks: {
+ set: function(value) {
+ networkData = value;
+ value.forEach(function(net) {
+ routerData = routerData.concat(net.routers);
+ });
+ value.forEach(function(net) {
+ vmData = vmData.concat(net.instances);
+ });
+ }
+ }
+ });
+
+ LogicalGraph.prototype.start = function() {
+ setTopologyPosition.call(this, networkData);
+ addLinksToDom.call(this, linkData);
+ addNetWorkRouterVmsToDom.call(this, networkData, routerData, vmData);
+ update.call(this);
+ };
+
+ LogicalGraph.prototype.freeDOM = function() {
+ d3Node.remove();
+ d3Link.remove();
+ d3Vm.remove();
+ d3Router.remove();
+
+ networkData = [];
+ routerData = [];
+ vmData = [];
+ linkData = [];
+ bbox = { x:0, y:15, width: 0, height: 0};
+ };
+
+ function addLinksToDom(linksData) {
+ d3Link = root.selectAll('.llink')
+ .data(linksData).enter().append('svg:g');
+
+ d3Link.append('rect')
+ .attr('width', function(d) {
+ return d.target.x - d.source.x;
+ })
+ .attr('height', linkHeight)
+ .style('fill', function(d) {
+ return d.color;
+ });
+
+ d3Link.append('text')
+ .attr('x', 40)
+ .attr('y', -3)
+ .text(function(d) {return d.text;});
+ }
+
+ function addNetWorkRouterVmsToDom(networks, routers, vms) {
+ var ctx = this,
+ timer = null;
+
+ function getAbsPos() {
+ var elem = d3.select(this)[0][0],
+ elemAbsBBox = elem.getBoundingClientRect(),
+ parentAbsBox = d3.select('#l_graph').node().getBoundingClientRect(),
+ left = elemAbsBBox.left - parentAbsBox.left + (elemAbsBBox.right - elemAbsBBox.left),
+ top = elemAbsBBox.top - parentAbsBox.top;
+
+ if (top < 0 ) {
+ top = 10;
+ }
+ var event = {
+ left : left,
+ top : top
+ };
+ return event;
+ }
+ d3Node = root.selectAll('.network')
+ .data(networks).enter()
+ .append('svg:g');
+ d3Router = root.selectAll('.routers')
+ .data(routers).enter()
+ .append('svg:g');
+ d3Vm = root.selectAll('.vm')
+ .data(vms).enter()
+ .append('svg:g');
+
+ // append coresponding form
+ d3Node.append('svg:rect')
+ .attr('width', nodeWidth)
+ .attr('height', nodeHeight)
+ .attr('rx', 10)
+ .attr('ry', 10)
+ .style('fill', function(d) {
+ return d.color;
+ }).on('click', function(d) {
+ if (d3.event.defaultPrevented) return;
+ timer = setTimeout(function() {
+ var e = getAbsPos.call(this);
+ ctx.onClick(e, d);
+ }.bind(this), 150);
+ }).on('dblclick', function(d) {
+ clearTimeout(timer);
+ ctx.dblClick(d);
+ });
+
+ // append the network name text
+ d3Node.append('text')
+ .attr('x', nodeWidth / 2 )
+ .attr('y', nodeHeight /2 )
+ .style('text-anchor', 'middle')
+ .style('writing-mode', 'tb')
+ .style('font-size', '12px')
+ .style('glyph-orientation-vertical', '0')
+ .text(function(d) { return d.name; });
+
+ // text info for the network ip
+ d3Node.append('text')
+ .attr('x', nodeWidth + 10)
+ .attr('y', nodeHeight - 15)
+ .attr('transform',
+ OvsCore.Util.String.Format('translate({0} {1}) rotate(-90) translate(-{0} -{1})', nodeWidth + 10, nodeHeight - 15))
+ .attr('class', 'linfolabel')
+ .text(function(d) {return d.ip;});
+
+ // vm
+ d3Vm.append('svg:image')
+ .attr('width', defaultVmsWidth)
+ .attr('height', defaultVmsHeight)
+ .attr('filter', 'url(#boxShadow)')
+ .attr('xlink:href', function(d) {
+ return d.type === 'network:dhcp' ?
+ 'src/app/ovsdb/assets/dhcp.png' : 'src/app/ovsdb/assets/vm.png';
+ })
+ .on('click', function(d) {
+ if (d3.event.defaultPrevented) return;
+ timer = setTimeout(function() {
+ var e = getAbsPos.call(this);
+ ctx.onClick(e, d);
+ }.bind(this), 150);
+ }).on('dblclick', function(d) {
+ clearTimeout(timer);
+ ctx.dblClick(d);
+ });
+
+ // router
+ d3Router.append('svg:image')
+ .attr('width', defaultRouterWidth)
+ .attr('height', defaultRouterHeight)
+ .attr('xlink:href', 'src/app/ovsdb/assets/router.png')
+ .on('click', function(d) {
+ if (d3.event.defaultPrevented) return;
+ timer = setTimeout(function() {
+ var e = getAbsPos.call(this);
+ ctx.onClick(e, d);
+ }.bind(this), 150);
+ }).on('dblclick', function(d) {
+ clearTimeout(timer);
+ ctx.dblClick(d);
+ });
+
+ // router name label
+ d3Router.append('text')
+ .attr('x', defaultRouterWidth * 0.5)
+ .attr('y', defaultRouterHeight + 15)
+ .attr('text-anchor', 'middle')
+ .attr('class', 'linfolabel')
+ .text(function(d) { return d.name; });
+
+ // vm name label
+ d3Vm.append('text')
+ .attr('x', defaultVmsWidth * 0.5)
+ .attr('y', defaultVmsHeight + 15)
+ .attr('text-anchor', 'middle')
+ .attr('class', 'linfolabel')
+ .text(function(d) { return d.name; });
+
+ // vm floating ip label
+ d3Vm.append('text')
+ .attr('x', -35)
+ .attr('y', 40)
+ .attr('text-anchor', 'middle')
+ .text(function(d) {
+ return (d.floatingIp) ? d.floatingIp.ip : '';
+ });
+
+ }
+
+ function findNetworkWithRouter(router) {
+ var result = [];
+ _.each(router.interfaces, function(inter) {
+ if (inter.type === 'router_interface') {
+ var net = tmpNetHolder[inter.networkId] || null;
+
+ if (net) {
+ result.push({network: net, interface: inter});
+ }
+ }
+ });
+
+ return result;
+ }
+
+ function positionateNetwork(network, x, y, margin) {
+ network.x = x;
+ network.y = y;
+ margin = margin || 0;
+ network.color = d3.hsl(randomize.next() * 360, 1, 0.6).toString();
+
+ // look is the network is the highest
+ bbox.height = network.y > bbox.height ? network.y : bbox.height ;
+ bbox.width = network.x > bbox.width ? network.x : bbox.width;
+
+ // get the number of "childs" (router, vm)
+ var nbRouter = network.routers.length;
+ var nbVm = network.instances.length;
+
+ if (!network.external) {
+ _.each(network.subnets, function(subnet, i) {
+ network.ip += subnet.cidr;
+ if (i < network.subnets.length -1) {
+ network.ip += ', ';
+ }
+ });
+ }
+
+ // if needed, ajust the height of the network
+ // to be able to display all children
+ ajustHeighBaseOnChilds(nbRouter, nbVm);
+
+ var py = positionateRouter(network, x + routerMargin.width, y + margin);
+
+ positionateVm(network, x + vmMargin.width, py + 35 + margin);
+ delete tmpNetHolder[network.id];
+ }
+
+ function positionateRouter(network, x, y) {
+ var px = x,
+ py = y ;
+
+ // loop over all routers
+ _.each(network.routers, function(router, i) {
+ router.x = getRouterCentroid(x, py).x ;
+ router.y = py;
+ py += getRouterMarginHeight();
+
+ if (network.external) {
+ // find network ip with the gateway ip
+ var gateway = router.externalGateway.external_fixed_ips[0].ip_address;
+ var netIp = gateway.slice(0, gateway.lastIndexOf('.')) + '.0';
+ network.ip = netIp;
+ }
+
+ // look is the router is the highest
+ bbox.height = router.y > bbox.height ? router.y : bbox.height ;
+ bbox.width = router.x > bbox.width ? router.x : bbox.width;
+
+ linkData.push({
+ source: {x: network.x + (nodeWidth * 0.5), y: router.y + (defaultRouterHeight * 0.5)},
+ target: {x: router.x + (defaultRouterWidth * 0.5), y: router.y + (nodeWidth * 0.5)},
+ color: network.color,
+ text: router.externalGateway.external_fixed_ips[0].ip_address
+ });
+
+ // go to the next layer
+ var nets = findNetworkWithRouter(router),
+ step = defaultRouterHeight / (nets.length + 1);
+
+ _.forEach(nets, function(net, i) {
+ var netPos = getNetworkLayerPosition(bbox.width + defaultRouterWidth);
+
+ positionateNetwork(net.network, netPos.x, netPos.y);
+ linkData.push({
+ source: {x: router.x + (2 * nodeWidth), y: router.y + step * (i + 1) },
+ target: {x: net.network.x + (nodeWidth * 0.5), y: router.y + (nodeWidth * 0.5 )},
+ color: net.network.color,
+ text: net.interface.ip.ip_address
+ });
+ });
+ });
+ return py;
+ }
+
+ function positionateVm(network, x, y) {
+
+ // I do vm before router because router
+ // will step to another BUS
+ _.each(network.instances, function(vm) {
+ vm.x = x;
+ vm.y = y;
+
+ // look is the network is the highest
+ bbox.height = vm.y > bbox.height ? vm.y : bbox.height ;
+ bbox.width = vm.x > bbox.width ? vm.x : bbox.width;
+
+ y += getVmMarginHeight();
+ linkData.push({
+ source: {x: network.x + (nodeWidth * 0.5), y: vm.y + (defaultVmsHeight * 0.5 )},
+ target: {x: vm.x + (defaultVmsWidth * 0.5), y: vm.y + (nodeWidth * 0.5)},
+ color: network.color,
+ text: vm.ip
+ });
+ });
+ }
+
+ /*
+ * Scan the whole "BUS" to display it properly
+ * ------------------------------------------------
+ * I build it in a virtual space, if it need to be
+ * resize it at the end when the overal bounding
+ * box is known
+ */
+ function setTopologyPosition(networks) {
+ _.each(networks, function(net) {
+ tmpNetHolder[net.id] = net;
+ });
+
+ var i = 0;
+ for(var key in tmpNetHolder) {
+ var margin = (i === 0) ? 5 : networkMargin.width,
+ net = tmpNetHolder[key];
+ if (net.routers.length > 0) {
+ positionateNetwork(net, bbox.x + bbox.width + margin, bbox.y);
+ ++i;
+ }
+ }
+
+ for(var key in tmpNetHolder) {
+ var margin = networkMargin.width,
+ net = tmpNetHolder[key];
+ positionateNetwork(net, bbox.x + bbox.width + margin, bbox.y);
+ }
+ }
+
+ /*
+ * Check and ajust the height for a network.
+ */
+ function ajustHeighBaseOnChilds(nbRouter, nbVm) {
+ // calculate the height for the number of childs
+ var childHeight = nbRouter * (getRouterMarginHeight()) +
+ nbVm * (getVmMarginHeight()) + ipNetworkTextMaxLength;
+
+ // if heigh bigger than the default network height resize it
+ if (childHeight > nodeHeight) {
+ nodeHeight = childHeight + networkOffset;
+ }
+ }
+
+ /*
+ * Set the view to the modal position
+ */
+ function update() {
+
+ d3Node.attr('transform', function(d) {
+ return OvsCore.Util.String.Format("translate({0}, {1})",
+ d.x, d.y
+ );
+ });
+
+ d3Router.attr('transform', function(d, i) {
+ return OvsCore.Util.String.Format("translate({0}, {1})",
+ d.x, d.y
+ );
+ });
+
+ d3Vm.attr('transform', function(d) {
+ return OvsCore.Util.String.Format("translate({0}, {1})",
+ d.x, d.y
+ );
+ });
+
+ d3Link.attr('transform', function(d) {
+ return OvsCore.Util.String.Format("translate({0}, {1})",
+ d.source.x, d.source.y
+ );
+ });
+
+ // resize the graph if bigger than the canvas
+ var bbox = root.node().getBBox();
+ if (bbox.width > canvasWidth || bbox.height > canvasHeight) {
+ var sx = (canvasWidth - 30) / bbox.width,
+ sy = (canvasHeight - 30) / bbox.height,
+ s = sx < sy ? sx : sy;
+ d3.select('.layer_0').attr('transform', 'scale(' + s + ')');
+ console.log(root.node().getBBox());
+ }
+ }
+
+ function getRouterCentroid(x, y) {
+ return {
+ x : x + defaultRouterWidth * 0.5,
+ y : y + defaultRouterHeight * 0.5
+ };
+ }
+
+ function getRouterMarginHeight() {
+ return (defaultRouterHeight + routerMargin.height);
+ }
+
+ function getVmMarginHeight() {
+ return (defaultVmsHeight + vmMargin.height);
+ }
+
+ function getNetworkLayerPosition(x) {
+ return {
+ x : x + networkMargin.width,
+ y : networkMargin.height
+ };
+ }
+
+ function getVmLayerPosition(nbRouter, x) {
+ var t = {
+ x : x + vmMargin.width * 2,
+ y : getRoutersDim(nbRouter).height + getVmMarginHeight()
+ };
+ return t;
+ }
+
+ LogicalGraph.prototype.onClick = _.noop;
+ LogicalGraph.prototype.dblClick = _.noop;
+
+ return LogicalGraph;
+});
--- /dev/null
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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
+ */
+
+define(['underscore'], function (_) {
+
+ var Topology = (function () {
+
+ function Topology(topoId) {
+ this.topoId = topoId || '';
+ this._bridgeNodes = {};
+ this._ovsdbNodes = {};
+ this._links = {};
+ }
+
+ Object.defineProperties(Topology.prototype, {
+ bridgeNodes: {
+ get: function () {
+ return this._bridgeNodes;
+ }
+ },
+ nodes: {
+ get: function() {
+ return _.extend({}, this._bridgeNodes, this._ovsdbNodes);
+ }
+ },
+ ovsdbNodes: {
+ get: function () {
+ return this._ovsdbNodes;
+ }
+ },
+ links: {
+ get: function () {
+ return this._links;
+ }
+ }
+ });
+
+ Topology.prototype.registerBridgeNode = function (bridgeNode) {
+ this._bridgeNodes[bridgeNode.nodeId] = bridgeNode;
+ };
+
+ Topology.prototype.registerOvsdbNode = function (ovsdbNode) {
+ this._ovsdbNodes[ovsdbNode.nodeId] = ovsdbNode;
+ };
+
+ Topology.prototype.registerLink = function (link) {
+ if (this._links[link.linkId]) {
+ console.warn('Two links have the same id (' + link.linkId + '), the first one will be overrided');
+ }
+ this._links[link.linkId] = link;
+ };
+
+ Topology.prototype.updateLink = function () {
+ _.each(this._links, (function (link, key) {
+ if (link instanceof Link) {
+ srcNode = _.filter(this._bridgeNodes, function(node) {
+ return node.getFLowName() === link.srcNodeId;
+ });
+ destNode = _.filter(this._bridgeNodes, function(node) {
+ return node.getFLowName() === link.destNodeId;
+ });
+ link.srcNodeId = srcNode[0].nodeId;
+ link.destNodeId = destNode[0].nodeId;
+ }
+ link.source = Object.keys(this.nodes).indexOf(link.srcNodeId);
+ link.target = Object.keys(this.nodes).indexOf(link.destNodeId);
+
+ }).bind(this));
+ };
+
+ return Topology;
+ })();
+
+ var OvsNode = (function () {
+ function OvsNode(nodeId, inetMgr, inetNode, otherLocalIp, ovsVersion) {
+ this.nodeId = nodeId;
+ this.inetMgr = inetMgr;
+ this.inetNode = inetNode;
+ this.otherLocalIp = otherLocalIp;
+ this.ovsVersion = ovsVersion;
+ }
+
+ OvsNode.prototype.showIpAdress = function() {
+ return this.otherLocalIp;
+ };
+
+ OvsNode.prototype.pretty = function() {
+ return {
+ 'tabs' : ['Info'],
+ 'containts' : [ {
+ 'hasHeader' : false,
+ 'headers' : [],
+ 'datas' : [
+ { key: 'ID', value: this.nodeId},
+ { key: 'InetMgr', value: this.inetMgr},
+ { key: 'InetNode', value: this.inetNode},
+ { key: 'Local IP', value: this.otherLocalIp},
+ { key: 'OVS Version', value: this.ovsVersion}
+ ]
+ }]
+ };
+ };
+
+ return OvsNode;
+ })();
+
+ var BridgeNode = (function () {
+
+ function BridgeNode(nodeId, dpIp, name, controllerTarget, controllerConnected) {
+ this.nodeId = nodeId;
+ this.dpIp = dpIp;
+ this.name = name;
+ this.controllerTarget = controllerTarget;
+ this.controllerConnected = controllerConnected;
+ this._tpList = [];
+ this.flowInfo = {};
+ this.flowTable = [];
+ }
+
+ Object.defineProperties(BridgeNode.prototype, {
+ tPs: {
+ get: function () {
+ return this._tpList;
+ }
+ },
+ });
+
+ var dpToFlow = function (dpId) {
+ return 'openflow:' + parseInt(dpId.replace(/:/g, ''), 16);
+ };
+
+ BridgeNode.prototype.getFLowName = function () {
+ return (!this.dpIp) ? this.nodeId : dpToFlow(this.dpIp);
+ };
+
+ BridgeNode.prototype.addTerminationPoint = function (tp) {
+ this._tpList.push(tp);
+ this._tpList.sort(function(tp1, tp2) {
+ return tp1.ofPort - tp2.ofPort;
+ });
+ };
+
+ BridgeNode.prototype.addFlowTableInfo = function(flowTable) {
+ this.flowTable.push(flowTable);
+ this.flowTable.sort(function(ft1, ft2) {
+ return ft1.key - ft2.key;
+ });
+ };
+
+ BridgeNode.prototype.pretty = function() {
+ return {
+ 'tabs' : [
+ 'Basic Info',
+ 'Ports',
+ 'Flow Info',
+ 'Flow Tables'
+ ],
+ 'containts' : [
+ {
+ 'hasHeader' : false,
+ 'headers' : [],
+ 'datas' : [
+ { key: 'ID', value: this.nodeId},
+ { key: 'Name', value: this.name},
+ { key: 'OpenFlow Name', value: this.getFLowName()},
+ { key: 'Controller Target', value: this.controllerTarget},
+ { key: 'Controller Connected', value: this.controllerConnected}
+ ]
+ },
+ {
+ 'hasHeader' : true,
+ 'header' : ['Of Port', 'Name', 'Mac', 'IFace Id',],
+ 'datas' : this._tpList.map(function(s) {
+ return [s.ofPort, s.name, s.mac, s.ifaceId];
+ })
+ },
+ {
+ 'hasHeader' : false,
+ 'headers' : [],
+ 'datas': [
+ {key : 'Manufacturer', value: this.flowInfo.manufacturer},
+ {key : 'Hardware', value: this.flowInfo.hardware},
+ {key : 'Software', value: this.flowInfo.software},
+ {key : 'Feature', value: this.flowInfo.features},
+ {key : 'Ip', value: this.flowInfo.ip}
+ ]
+ },
+ {
+ 'hasHeader' : true,
+ 'headers' : ['Table Id', 'Value'],
+ 'datas' :this.flowTable.map(function(t) {
+ return [t.key, t.value];
+ })
+ }
+ ]
+ };
+ };
+
+ return BridgeNode;
+ })();
+
+ var TerminationPoint = (function () {
+ function TerminationPoint(name, ofPort, tpType, mac, ifaceId) {
+ this.name = name;
+ this.ofPort = ofPort;
+ this.tpType = tpType;
+ this.mac = mac || '';
+ this.ifaceId = ifaceId || '';
+ }
+ return TerminationPoint;
+ })();
+
+ var BaseLink = (function() {
+ function BaseLink(linkId, srcNodeId, destNodeId, linkType, styles) {
+ this.linkId = linkId;
+ this.srcNodeId = srcNodeId;
+ this.destNodeId = destNodeId;
+ this.linkType = linkType;
+
+ // styling
+ styles = _.extend({}, styles);
+ this.color = styles.color;
+ this.width = styles.width || 1;
+ this.dashArray = styles.dashArray || 'None';
+
+ // d3js needed values
+ this.source = -1;
+ this.target = -1;
+ }
+ return BaseLink;
+ })();
+
+ var Link = (function () {
+ function Link(linkId, srcNodeId, destNodeId) {
+ var opt = {
+ color: 'black'
+ };
+
+ BaseLink.call(this, linkId, srcNodeId, destNodeId, 'link', opt);
+ }
+
+ Link.prototype = Object.create(BaseLink.prototype);
+ Link.prototype.constructor = Link;
+
+ return Link;
+ })();
+
+ var TunnelLink = (function() {
+ function TunnelLink(linkId, srcNodeId, destNodeId, linkType, color) {
+ var opt = {
+ color: 'green',
+ width: 2,
+ dashArray: '5,5'
+ };
+ BaseLink.call(this, linkId, srcNodeId, destNodeId, 'tunnel', opt);
+ }
+
+ TunnelLink.prototype = Object.create(BaseLink.prototype);
+ TunnelLink.prototype.constructor = TunnelLink;
+
+ return TunnelLink;
+ })();
+
+ var BridgeOvsLink = (function() {
+ function BridgeOvsLink(linkId, srcNodeId, destNodeId, linkType, color) {
+ var opt = {
+ color: 'gray',
+ dashArray: '10,10'
+ };
+ BaseLink.call(this, linkId, srcNodeId, destNodeId, 'bridgeOvsLink', opt);
+ }
+
+ BridgeOvsLink.prototype = Object.create(BaseLink.prototype);
+ BridgeOvsLink.prototype.constructor = BridgeOvsLink;
+
+ return BridgeOvsLink;
+ })();
+
+ var Util = (function() {
+ var Maths = (function() {
+ function Maths() {
+
+ }
+ // random function in javascript use timespan only
+ Maths.Random = function(nseed) {
+ var constant = Math.pow(2, 13)+1,
+ prime = 1987,
+ maximum = 1000;
+
+ if (nseed) {
+ seed = nseed;
+ }
+
+ return {
+ next : function(min, max) {
+ seed *= constant;
+ seed += prime;
+
+ return min && max ? min+seed%maximum/maximum*(max-min) : seed%maximum/maximum;
+ }
+ };
+ };
+ return Maths;
+ })();
+
+ var String = (function() {
+
+ function String() {
+
+ }
+ String.Format = function() {
+ var s = arguments[0];
+ for (var i = 0; i < arguments.length - 1; i++) {
+ var reg = new RegExp("\\{" + i + "\\}", "gm");
+ s = s.replace(reg, arguments[i + 1]);
+ }
+ return s;
+ };
+
+ return String;
+
+ })();
+ return {
+ Math: Maths,
+ String: String
+ };
+ })();
+
+ var Neutron = (function() {
+
+ var SubNet = (function() {
+ function SubNet(id, networkId, name, ipVersion, cidr, gatewayIp, tenantId) {
+ this.id = id;
+ this.networkId = networkId;
+ this.name = name;
+ this.ipVersion = ipVersion;
+ this.cidr = cidr;
+ this.gatewayIp = gatewayIp;
+ this.tenantId = tenantId;
+ }
+ return SubNet;
+ })();
+
+ var Network = (function() {
+ function Network(id, name, shared, status, external, tenantId) {
+ this.id = id;
+ this.ip = '';
+ this.name = name;
+ this.shared = shared;
+ this.status = status;
+ this.external = external;
+ this.tenantId = tenantId;
+ this.subnets = [];
+ this.instances = [];
+ this.routers = [];
+ }
+
+ Network.prototype.addSubNets = function(subnets) {
+ if(subnets) {
+ if (_.isArray(subnets)) {
+ var i = 0;
+ for (; i < subnets.length; ++i) {
+ this.subnets.push(subnets[i]);
+ }
+ }
+ else {
+ this.subnets.push(subnet);
+ }
+ }
+ };
+
+ Network.prototype.asSubnet = function(subnet) {
+ return _.every(subnet, function(sub) {
+ return _.some(this.subnets, function(s) {
+ return s.id === sub;
+ });
+ }.bind(this));
+ };
+
+ Network.prototype.pretty = function() {
+ return {
+ 'tabs' : [
+ 'Info',
+ 'Subnets'
+ ],
+ 'containts' : [
+ {
+ 'hasHeader' : false,
+ 'headers': [],
+ 'datas' : [
+ {key : 'ID', value: this.id},
+ {key : 'Ip', value: this.ip},
+ {key : 'Name', value: this.name},
+ {key : 'Shared', value: this.shared},
+ {key : 'Status', value: this.status},
+ {key : 'External', value: this.external},
+ {key : 'Tenant Id', value: this.tenantId}
+ ]
+ },
+ {
+ 'hasHeader' : true,
+ 'header' : ['ID', 'Name', 'Ip Version', 'Ip', 'Gateway Ip'],
+ 'datas' : this.subnets.map(function(s) {
+ return [s.id, s.name, s.ipVersion, s.cidr, s.gatewayIp];
+ })
+ }
+ ]
+ };
+ };
+
+ return Network;
+ })();
+
+ var Port = (function() {
+ function Port(id, networkId, name, tenantId, deviceId, deviceOwner, fixed_ips, mac) {
+ this.id = id;
+ this.networkId = networkId;
+ this.name = name;
+ this.tenantId = '' + tenantId || '';
+ this.deviceId = deviceId;
+ this.deviceOwner = deviceOwner;
+ this.fixed_ips = fixed_ips;
+ this.mac = mac;
+ }
+
+ Port.prototype.pretty = function() {
+ return [
+ { key: 'ID', value : this.id },
+ { key: 'Name', value: name },
+ { key: 'Tenant Id', value : this.tenantId },
+ { key: 'Device Id', value : this.deviceId },
+ { key: 'Device Owner', value : this.deviceOwner },
+ { key: 'MAC', value : this.mac }
+ ];
+ };
+
+ return Port;
+ })();
+
+ var Router = (function() {
+ function Router(id, name, status, tenantId, externalGateway) {
+ this.id = id;
+ this.name = name;
+ this.status = status;
+ this.tenantId = tenantId;
+ this.interfaces = [];
+ this.externalGateway = externalGateway;
+ }
+
+ Router.prototype.pretty = function() {
+ return {
+ 'tabs' : [
+ 'Info',
+ 'Interfaces'
+ ],
+ 'containts' : [
+ {
+ 'hasHeader' : false,
+ 'headers': [],
+ 'datas' : [
+ { key: 'ID', value: this.id},
+ { key: 'Name', value: this.name},
+ { key: 'status', value: this.status},
+ { key: 'Tenant ID', value: this.tenantId}
+ ]
+ },
+ {
+ 'hasHeader' : true,
+ 'header' : ['ID', 'Type', 'Mac Address', 'Ip', 'Tenant Id'],
+ 'datas' : this.interfaces.map(function(s) {
+ return [s.id, s.type, s.mac, s.ip.ip_address, s.tenantId];
+ })
+ }
+ ]
+ };
+ };
+
+ return Router;
+ })();
+
+ var Instance = (function() {
+ function Instance(id, networkId, name, ip, mac, deviceOwner, tenantId, topoInfo) {
+ this.id = id;
+ this.networkId = networkId;
+ this.name = name;
+ this.ip = ip;
+ this.mac = '' + mac;
+ this.type = deviceOwner;
+ this.tenantId = tenantId;
+ this.topoInfo = topoInfo || [];
+ this.floatingIp = {};
+ }
+
+ Instance.prototype.extractFloatingIps = function(floatingIps) {
+ var ctx = this;
+ this.floatingIp = _.find(floatingIps, function(fIp) {
+ return fIp.tenantId === ctx.tenantId &&
+ fIp.fixedIp === ctx.ip;
+ });
+ };
+
+ Instance.prototype.pretty = function() {
+ return {
+ 'tabs' : [
+ 'Info',
+ 'Ports'
+ ],
+ 'containts' : [
+ {
+ 'hasHeader' : false,
+ 'headers': [],
+ 'datas' : [
+ { key: 'ID', value: this.id},
+ { key: "Network Id", value : this.networkId},
+ { key: 'Name', value: this.name},
+ { key: 'Ip', value: this.ip},
+ { key: 'Floating Ip', value: (this.floatingIp) ? this.floatingIp.ip : 'Not found' },
+ { key: 'MAC', value: this.mac},
+ { key: 'Type', value: this.type},
+ { key: 'Tenant ID', value: this.tenantId}
+ ]
+ },
+ {
+ 'hasHeader' : true,
+ 'header' : ['Name', 'Of Port', 'Mac', 'Flow', 'Ovsdb Node', 'Ovsdb Node IP'],
+ 'datas' : this.topoInfo.map(function(s) {
+ return [s.name, s.ofPort, s.mac, s.bridge.getFLowName(), s.ovsNode.nodeId, s.ovsNode.showIpAdress()];
+ })
+ }
+ ]
+ };
+ };
+
+ return Instance;
+ })();
+
+ var FloatingIp =(function() {
+ function FloatingIp(id, networkId, portId, fixedIp, floatingIp, tentantId, status) {
+ this.id = id;
+ this.networkId = networkId;
+ this.portId = portId;
+ this.fixedIp = fixedIp;
+ this.ip = floatingIp;
+ this.tenantId = tentantId;
+ this.status = status;
+ }
+
+ return FloatingIp;
+ })();
+
+ return {
+ Network: Network,
+ Port: Port,
+ Instance: Instance,
+ FloatingIp: FloatingIp,
+ Router: Router,
+ SubNet: SubNet
+ };
+ })();
+
+ return {
+ OvsNode: OvsNode,
+ BridgeNode: BridgeNode,
+ TerminationPoint: TerminationPoint,
+ Topology: Topology,
+ BaseLink: BaseLink,
+ Link: Link,
+ TunnelLink: TunnelLink,
+ BridgeOvsLink:BridgeOvsLink,
+ Util:Util,
+ Neutron: Neutron
+ };
+});
--- /dev/null
+/*\r
+ * Copyright (c) 2015 Inocybe Technologies and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+*/\r
+\r
+#errorMessage {\r
+ display: none;\r
+}\r
+.switch-light {\r
+ width: 140px;\r
+}\r
+.switch-light span > span {\r
+ color: black;\r
+}\r
+.link {\r
+ stroke: #999;\r
+ stroke-opacity: 0.8;\r
+}\r
+.form-inline > span,\r
+label {\r
+ padding-right: 15px;\r
+}\r
+#list_container {\r
+ border: 1px solid white;\r
+ background-color: #414042;\r
+ height: 600px;\r
+}\r
+#list_container label {\r
+ color: white;\r
+}\r
+svg,\r
+#list_container {\r
+ width: 100%;\r
+}\r
+svg {\r
+ border: none;\r
+ border-radius: 0;\r
+ background-image: none;\r
+ background-color: white;\r
+ height: 580px;\r
+}\r
+#list_container > .row {\r
+ margin-left: 15px;\r
+ margin-right: 15px;\r
+}\r
+.container {\r
+ padding-top: 15px;\r
+ width: 1200px;\r
+}\r
+.row {\r
+ padding-bottom: 15px;\r
+}\r
+.select2-selection__choice {\r
+ background-color: orange !important;\r
+ border-color: black !important;\r
+ color: black !important;\r
+}\r
+.select2-selection__choice > span {\r
+ color: black !important;\r
+}\r
+.select2-results {\r
+ color: black !important;\r
+}\r
+.table.table-bordered {\r
+ background-color: white;\r
+ color: black;\r
+}\r
+#graph_header {\r
+ width: 100%;\r
+ height: 20px;\r
+ background-color: white;\r
+ border-bottom: 1px solid #ccc;\r
+}\r
+.icon-fullscreen,\r
+.icon-resize-small {\r
+ margin-right: 5px;\r
+ margin-top: 2px;\r
+}\r
+.bg_rect {\r
+ fill: #FFA6A6;\r
+ opacity: .4;\r
+ stroke: #ff0000;\r
+}\r
+kbd {\r
+ color: #333;\r
+ border-radius: 3px;\r
+ padding: 2px 4px;\r
+ font-size: 90%;\r
+ background-color: #DDD;\r
+ box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.25);\r
+}\r
+.network_info {\r
+ text-align: center;\r
+ width: 170px;\r
+ height: 80px;\r
+ padding: 5px;\r
+ border-radius: 5px;\r
+ border: 1px solid black;\r
+}\r
+#network_summary {\r
+ width: auto;\r
+ height: auto;\r
+ left: 15px;\r
+ padding: 5px;\r
+}\r
+.graph_window {\r
+ position: absolute !important;\r
+ background-color: rgba(255, 255, 255, 0.7);\r
+ -webkit-box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.75);\r
+ -moz-box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.75);\r
+ box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.75);\r
+ padding: 5px;\r
+ z-index: 2;\r
+ border-radius: 5px;\r
+ top: 25px;\r
+ min-height: 35px;\r
+ min-width: 100px;\r
+ overflow: hidden;\r
+}\r
+#graph_summary {\r
+ width: 160px;\r
+ height: 100px;\r
+ right: 10px;\r
+}\r
+\r
+div.window_body {\r
+ height: 80%;\r
+ font-size:12px;\r
+ color:#ccc;\r
+}\r
+div.window_content {\r
+ position:relative;\r
+ max-height:350px;\r
+ height:100%;\r
+ overflow-y: auto;\r
+}\r
+div.window_header > hr {\r
+ margin-top: 0;\r
+ margin-bottom: 10px;\r
+}\r
+div.window_header > span {\r
+ width: 100%;\r
+ display: inline;\r
+}\r
+#network_table_window,\r
+#node_table_window {\r
+ width: 355px;\r
+ height: 215px;\r
+}\r
+#node_table_window {\r
+ top: 300px;\r
+ left: 25px;\r
+}\r
+#network_table_window {\r
+ top: 300px;\r
+ right: 25px;\r
+}\r
+.window-icon {\r
+ color: black;\r
+ float: right;\r
+ margin-right: 5px;\r
+}\r
+.window-icon:hover {\r
+ background-color: #ddd;\r
+ cursor: pointer;\r
+}\r
+\r
+.linfolabel {\r
+ font-size : 12px;\r
+ letter-spacing: 1px;\r
+}\r
+#tabs > ul > li > a {\r
+ color:white !important;\r
+}\r
+#tabs > ul > li.ui-state-active {\r
+ border: 1px solid white;\r
+}\r
+\r
+#tabs > ul > li.ui-state-hover > a{\r
+ color:black !important;\r
+}\r
+\r
+#tabs > ul > li > a:focus {\r
+ background-color:inherit !important;\r
+}\r
+\r
+#lDialog, #pDialog {\r
+ position:absolute;\r
+ font-size: 11px;\r
+ width: auto;\r
+ min-width: 450px;\r
+ display:none;\r
+ background-color: rgb(255, 255, 255);\r
+ border: 1px solid black;\r
+ border-radius: 10px;\r
+ height: auto;\r
+ padding: 10px;\r
+}\r
+\r
+.window_content > ul > li.ui-state-active {\r
+ border-top: 1px solid #dddddd;\r
+ border-left: 1px solid #dddddd;\r
+ border-right: 1px solid #dddddd;\r
+}\r
+\r
+.arrow-left {\r
+ width: 0;\r
+ height: 0;\r
+ border-top: 10px solid transparent;\r
+ border-bottom: 10px solid transparent;\r
+\r
+ border-right:10px solid blue;\r
+}\r
+\r
+span.selection {\r
+ font-size: 10px;\r
+}\r
--- /dev/null
+.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle;}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none;}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px;}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none;}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap;}.select2-container .select2-search--inline{float:left;}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none;}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051;}.select2-results{display:block;}.select2-results__options{list-style:none;margin:0;padding:0;}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none;}.select2-results__option[aria-selected]{cursor:pointer;}.select2-container--open .select2-dropdown{left:0;}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0;}.select2-search--dropdown{display:block;padding:4px;}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box;}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none;}.select2-search--dropdown.select2-search--hide{display:none;}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0);}.select2-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px;}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px;}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999;}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px;}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0;}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left;}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto;}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default;}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none;}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px;}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%;}.select2-container--default .select2-selection--multiple .select2-selection__placeholder{color:#999;margin-top:5px;float:left;}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px;}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px;}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333;}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder{float:right;}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto;}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto;}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0;}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default;}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none;}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0;}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0;}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa;}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto;}.select2-container--default .select2-results__option[role=group]{padding:0;}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999;}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd;}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em;}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white;}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px;}.select2-container--classic .select2-selection--single{background-color:#f6f6f6;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #ffffff 50%, #eeeeee 100%);background-image:-o-linear-gradient(top, #ffffff 50%, #eeeeee 100%);background-image:linear-gradient(to bottom, #ffffff 50%, #eeeeee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb;}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px;}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px;}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999;}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#cccccc', GradientType=0);}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0;}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left;}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto;}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb;}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none;}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px;}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #ffffff 0%, #eeeeee 50%);background-image:-o-linear-gradient(top, #ffffff 0%, #eeeeee 50%);background-image:linear-gradient(to bottom, #ffffff 0%, #eeeeee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eeeeee 50%, #ffffff 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, #ffffff 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, #ffffff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0;}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb;}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px;}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none;}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px;}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px;}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555;}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto;}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto;}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb;}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0;}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0;}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;}.select2-container--classic .select2-dropdown{background-color:white;border:1px solid transparent;}.select2-container--classic .select2-dropdown--above{border-bottom:none;}.select2-container--classic .select2-dropdown--below{border-top:none;}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto;}.select2-container--classic .select2-results__option[role=group]{padding:0;}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey;}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:white;}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px;}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb;}
\ No newline at end of file
--- /dev/null
+/*
+* CSS TOGGLE SWITCHES
+* Unlicense
+*
+* Ionuț Colceriu - ghinda.net
+* https://github.com/ghinda/css-toggle-switch
+*
+*/
+/* Supported values are px, rem-calc, em-calc */
+/* Functions */
+/* Toggle Switches */
+/* Shared */
+/* Checkbox
+*/
+/* Radio Switch
+*/
+/* Hide by default
+*/
+.switch-toggle a, .switch-light span span {
+ display: none; }
+
+/* We can't test for a specific feature,
+* so we only target browsers with support for media queries.
+*/
+@media only screen {
+ /* Checkbox switch
+ */
+ .switch-light {
+ display: block;
+ min-height: 1.875em;
+ /* Outline the toggles when the inputs are focused
+ */
+ position: relative;
+ overflow: visible;
+ padding: 0;
+ margin-left: 6.25em;
+ /* Position the label over all the elements, except the slide-button (<a>)
+ * Clicking anywhere on the label will change the switch-state
+ */
+ /* Don't hide the input from screen-readers and keyboard access
+ */ }
+ .switch-light * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box; }
+ .switch-light a {
+ display: block;
+ -webkit-transition: all 0.2s ease-out;
+ -moz-transition: all 0.2s ease-out;
+ transition: all 0.2s ease-out; }
+ .switch-light label, .switch-light > span {
+ line-height: 1.875em;
+ vertical-align: middle; }
+ .switch-light input:focus ~ a, .switch-light input:focus + label {
+ outline: 1px dotted #888; }
+ .switch-light label {
+ position: relative;
+ z-index: 3;
+ display: block;
+ width: 100%; }
+ .switch-light input {
+ position: absolute;
+ opacity: 0;
+ z-index: 5; }
+ .switch-light input:checked ~ a {
+ right: 0%; }
+ .switch-light > span {
+ position: absolute;
+ left: -6.25em;
+ width: 100%;
+ margin: 0;
+ padding-right: 6.25em;
+ text-align: left; }
+ .switch-light > span span {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 5;
+ display: block;
+ width: 50%;
+ margin-left: 6.25em;
+ text-align: center; }
+ .switch-light > span span:last-child {
+ left: 50%; }
+ .switch-light a {
+ position: absolute;
+ right: 50%;
+ top: 0;
+ z-index: 4;
+ display: block;
+ width: 50%;
+ height: 100%;
+ padding: 0; }
+
+ /* Radio switch
+ */
+ .switch-toggle {
+ display: block;
+ min-height: 1.875em;
+ /* Outline the toggles when the inputs are focused
+ */
+ position: relative;
+ display: table;
+ table-layout: fixed;
+ /* For callout panels in foundation
+ */
+ padding: 0 !important;
+ /* Generate styles for the multiple states */ }
+ .switch-toggle * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box; }
+ .switch-toggle a {
+ display: block;
+ -webkit-transition: all 0.2s ease-out;
+ -moz-transition: all 0.2s ease-out;
+ transition: all 0.2s ease-out; }
+ .switch-toggle label, .switch-toggle > span {
+ line-height: 1.875em;
+ vertical-align: middle; }
+ .switch-toggle input:focus ~ a, .switch-toggle input:focus + label {
+ outline: 1px dotted #888; }
+ .switch-toggle * {
+ font-size: 1em; }
+ .switch-toggle input {
+ position: absolute;
+ opacity: 0; }
+ .switch-toggle input + label {
+ position: relative;
+ z-index: 2;
+ display: table-cell;
+ width: 50%;
+ padding: 0 0.5em;
+ margin: 0;
+ text-align: center; }
+ .switch-toggle a {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 0;
+ z-index: 1;
+ width: 50%;
+ height: 100%; }
+ .switch-toggle input:last-of-type:checked ~ a {
+ left: 50%; }
+ .switch-toggle.switch-3 label, .switch-toggle.switch-3 a {
+ width: 33.3333333333%; }
+ .switch-toggle.switch-3 input:checked:nth-of-type(2) ~ a {
+ left: 33.3333333333%; }
+ .switch-toggle.switch-3 input:checked:last-of-type ~ a {
+ left: 66.6666666667%; }
+ .switch-toggle.switch-4 label, .switch-toggle.switch-4 a {
+ width: 25%; }
+ .switch-toggle.switch-4 input:checked:nth-of-type(2) ~ a {
+ left: 25%; }
+ .switch-toggle.switch-4 input:checked:nth-of-type(3) ~ a {
+ left: 50%; }
+ .switch-toggle.switch-4 input:checked:last-of-type ~ a {
+ left: 75%; }
+ .switch-toggle.switch-5 label, .switch-toggle.switch-5 a {
+ width: 20%; }
+ .switch-toggle.switch-5 input:checked:nth-of-type(2) ~ a {
+ left: 20%; }
+ .switch-toggle.switch-5 input:checked:nth-of-type(3) ~ a {
+ left: 40%; }
+ .switch-toggle.switch-5 input:checked:nth-of-type(4) ~ a {
+ left: 60%; }
+ .switch-toggle.switch-5 input:checked:last-of-type ~ a {
+ left: 80%; }
+
+ /* Standalone Themes */
+ /* Candy Theme
+ * Based on the "Sort Switches / Toggles (PSD)" by Ormal Clarck
+ * http://www.premiumpixels.com/freebies/sort-switches-toggles-psd/
+ */
+ .switch-candy {
+ background-color: #2d3035;
+ border-radius: 3px;
+ color: #fff;
+ font-weight: bold;
+ text-align: center;
+ text-shadow: 1px 1px 1px #191b1e;
+ box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.2); }
+ .switch-candy label {
+ color: #fff;
+ -webkit-transition: color 0.2s ease-out;
+ -moz-transition: color 0.2s ease-out;
+ transition: color 0.2s ease-out; }
+ .switch-candy input:checked + label {
+ color: #333;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); }
+ .switch-candy a {
+ border: 1px solid #333;
+ background-color: #70c66b;
+ border-radius: 3px;
+ background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+ background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.45); }
+ .switch-candy > span {
+ color: #333;
+ text-shadow: none; }
+ .switch-candy span {
+ color: #fff; }
+ .switch-candy.switch-candy-blue a {
+ background-color: #38a3d4; }
+ .switch-candy.switch-candy-yellow a {
+ background-color: #f5e560; }
+
+ /* Android Theme
+ */
+ .switch-android {
+ background-color: #464747;
+ border-radius: 1px;
+ box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0;
+ color: #fff;
+ /* Selected ON switch-light
+ */ }
+ .switch-android label {
+ color: #fff; }
+ .switch-android > span span {
+ opacity: 0;
+ margin-left: 7.1875em;
+ -webkit-transition: all 0.1s;
+ -moz-transition: all 0.1s;
+ transition: all 0.1s; }
+ .switch-android > span span:first-of-type {
+ opacity: 1; }
+ .switch-android > span span, .switch-android input + label {
+ font-size: 85%;
+ line-height: 2.15625em; }
+ .switch-android a {
+ background-color: #666;
+ border-radius: 1px;
+ box-shadow: inset rgba(255, 255, 255, 0.2) 0 1px 0, inset rgba(0, 0, 0, 0.3) 0 -1px 0; }
+ .switch-android.switch-light input:checked ~ a {
+ background-color: #0E88B1; }
+ .switch-android.switch-light input:checked ~ span span:first-of-type {
+ opacity: 0; }
+ .switch-android.switch-light input:checked ~ span span:last-of-type {
+ opacity: 1; }
+ .switch-android.switch-toggle, .switch-android > span span {
+ text-transform: uppercase; }
+
+ /* iOS Theme
+ */
+ .switch-ios.switch-light {
+ color: #868686; }
+ .switch-ios.switch-light a {
+ left: 0;
+ width: 1.875em;
+ background-color: #fff;
+ border: 1px solid #d3d3d3;
+ border-radius: 100%;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out;
+ box-shadow: inset 0 -3px 3px rgba(0, 0, 0, 0.025), 0 1px 4px rgba(0, 0, 0, 0.15), 0 4px 4px rgba(0, 0, 0, 0.1); }
+ .switch-ios.switch-light > span span {
+ width: 100%;
+ left: 0;
+ opacity: 0; }
+ .switch-ios.switch-light > span span:first-of-type {
+ opacity: 1;
+ padding-left: 1.875em; }
+ .switch-ios.switch-light > span span:last-of-type {
+ padding-right: 1.875em; }
+ .switch-ios.switch-light > span:before {
+ content: '';
+ display: block;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 6.25em;
+ top: 0;
+ background-color: #fafafa;
+ border: 1px solid #d3d3d3;
+ border-radius: 30px;
+ -webkit-transition: all 0.5s ease-out;
+ -moz-transition: all 0.5s ease-out;
+ transition: all 0.5s ease-out;
+ box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+ .switch-ios.switch-light input:checked ~ a {
+ left: 100%;
+ margin-left: -1.875em; }
+ .switch-ios.switch-light input:checked ~ span:before {
+ border-color: #53d76a;
+ box-shadow: inset 0 0 0 30px #53d76a; }
+ .switch-ios.switch-light input:checked ~ span span:first-of-type {
+ opacity: 0; }
+ .switch-ios.switch-light input:checked ~ span span:last-of-type {
+ opacity: 1;
+ color: #fff; }
+ .switch-ios.switch-toggle {
+ background-color: #fafafa;
+ border: 1px solid #d3d3d3;
+ border-radius: 30px;
+ box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+ .switch-ios.switch-toggle a {
+ background-color: #53d76a;
+ border-radius: 25px;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out; }
+ .switch-ios.switch-toggle label {
+ color: #868686; }
+ .switch-ios input:checked + label {
+ color: #3a3a3a; }
+ }
+
+/* Bugfix for older Webkit, including mobile Webkit. Adapted from
+* http://css-tricks.com/webkit-sibling-bug/
+*/
+@media only screen and (-webkit-max-device-pixel-ratio: 2) and (max-device-width: 80em) {
+ .switch-light, .switch-toggle {
+ -webkit-animation: webkitSiblingBugfix infinite 1s; } }
+
+@-webkit-keyframes webkitSiblingBugfix {
+ from {
+ -webkit-transform: translate3d(0, 0, 0); }
+
+ to {
+ -webkit-transform: translate3d(0, 0, 0); } }
+++ /dev/null
-<!--\r
- * Copyright (c) 2015 Inocybe Technologies and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
--->\r
-\r
-<div class="form-group">\r
- <span>In progress</span>\r
- <div id="errorMessage" class="alert alert-danger" role="alert">\r
- {{err.message}}\r
- </div>\r
-</div>\r
--- /dev/null
+!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function r(n){return null===n?0/0:+n}function u(n){return!isNaN(n)}function i(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function c(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function l(){this._=Object.create(null)}function s(n){return(n+="")===pa||n[0]===va?va+n:n}function f(n){return(n+="")[0]===va?n.slice(1):n}function h(n){return s(n)in this._}function g(n){return(n=s(n))in this._&&delete this._[n]}function p(){var n=[];for(var t in this._)n.push(f(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function m(){this._=Object.create(null)}function y(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=da.length;r>e;++e){var u=da[e]+t;if(u in n)return u}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new l;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function S(){ta.event.preventDefault()}function k(){for(var n,t=ta.event;n=t.sourceEvent;)t=n;return t}function E(n){for(var t=new _,e=0,r=arguments.length;++e<r;)t[arguments[e]]=w(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=ta.event;u.target=n,ta.event=u,t[u.type].apply(e,r)}finally{ta.event=i}}},t}function A(n){return ya(n,_a),n}function N(n){return"function"==typeof n?n:function(){return Ma(n,this)}}function C(n){return"function"==typeof n?n:function(){return xa(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=ta.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function q(n){return n.trim().replace(/\s+/g," ")}function L(n){return new RegExp("(?:^|\\s+)"+ta.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=T(n).map(D);var u=n.length;return"function"==typeof t?r:e}function D(n){var t=L(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",q(u+" "+n))):e.setAttribute("class",q(u.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?i:u}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e?t.createElementNS(e,n):t.createElement(n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ta.ns.qualify(n)).local?e:t}function F(){var n=this.parentNode;n&&n.removeChild(this)}function H(n){return{__data__:n}}function O(n){return function(){return ba(this,n)}}function I(n){return arguments.length||(n=e),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function Y(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function Z(n){return ya(n,Sa),n}function V(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,ra(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+ta.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=$;a>0&&(n=n.slice(0,a));var l=ka.get(n);return l&&(n=l,c=B),a?t?u:r:t?b:i}function $(n,t){return function(e){var r=ta.event;ta.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ta.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Aa,u="click"+r,i=ta.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ea&&(Ea="onselectstart"in e?!1:x(e.style,"userSelect")),Ea){var o=n(e).style,a=o[Ea];o[Ea]="none"}return function(n){if(i.on(r,null),Ea&&(o[Ea]=a),n){var t=function(){i.on(u,null)};i.on(u,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var u=r.createSVGPoint();if(0>Na){var i=t(n);if(i.scrollX||i.scrollY){r=ta.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Na=!(o.f||o.e),r.remove()}}return Na?(u.x=e.pageX,u.y=e.pageY):(u.x=e.clientX,u.y=e.clientY),u=u.matrixTransform(n.getScreenCTM().inverse()),[u.x,u.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ta.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nt(n){return n>1?0:-1>n?qa:Math.acos(n)}function tt(n){return n>1?Ra:-1>n?-Ra:Math.asin(n)}function et(n){return((n=Math.exp(n))-1/n)/2}function rt(n){return((n=Math.exp(n))+1/n)/2}function ut(n){return((n=Math.exp(2*n))-1)/(n+1)}function it(n){return(n=Math.sin(n/2))*n}function ot(){}function at(n,t,e){return this instanceof at?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof at?new at(n.h,n.s,n.l):bt(""+n,_t,at):new at(n,t,e)}function ct(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new mt(u(n+120),u(n),u(n-120))}function lt(n,t,e){return this instanceof lt?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof lt?new lt(n.h,n.c,n.l):n instanceof ft?gt(n.l,n.a,n.b):gt((n=wt((n=ta.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new lt(n,t,e)}function st(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new ft(e,Math.cos(n*=Da)*t,Math.sin(n)*t)}function ft(n,t,e){return this instanceof ft?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof ft?new ft(n.l,n.a,n.b):n instanceof lt?st(n.h,n.c,n.l):wt((n=mt(n)).r,n.g,n.b):new ft(n,t,e)}function ht(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=pt(u)*Xa,r=pt(r)*$a,i=pt(i)*Ba,new mt(dt(3.2404542*u-1.5371385*r-.4985314*i),dt(-.969266*u+1.8760108*r+.041556*i),dt(.0556434*u-.2040259*r+1.0572252*i))}function gt(n,t,e){return n>0?new lt(Math.atan2(e,t)*Pa,Math.sqrt(t*t+e*e),n):new lt(0/0,0/0,n)}function pt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function vt(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function dt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mt(n,t,e){return this instanceof mt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mt?new mt(n.r,n.g,n.b):bt(""+n,mt,ct):new mt(n,t,e)}function yt(n){return new mt(n>>16,n>>8&255,255&n)}function Mt(n){return yt(n)+""}function xt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function bt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(kt(u[0]),kt(u[1]),kt(u[2]))}return(i=Ga.get(n.toLowerCase()))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function _t(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new at(r,u,c)}function wt(n,t,e){n=St(n),t=St(t),e=St(e);var r=vt((.4124564*n+.3575761*t+.1804375*e)/Xa),u=vt((.2126729*n+.7151522*t+.072175*e)/$a),i=vt((.0193339*n+.119192*t+.9503041*e)/Ba);return ft(116*u-16,500*(r-u),200*(u-i))}function St(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function kt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function Et(n){return"function"==typeof n?n:function(){return n}}function At(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Nt(t,e,n,r)}}function Nt(n,t,e,r){function u(){var n,t=c.status;if(!t&&zt(c)||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return void o.error.call(i,r)}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=ta.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!this.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=ta.event;ta.event=n;try{o.progress.call(i,c)}finally{ta.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(l=n,i):l},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(ra(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var s in a)c.setRequestHeader(s,a[s]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},ta.rebind(i,o,"on"),null==r?i:i.get(Ct(r))}function Ct(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function zt(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qt(){var n=Lt(),t=Tt()-n;t>24?(isFinite(t)&&(clearTimeout(tc),tc=setTimeout(qt,t)),nc=0):(nc=1,rc(qt))}function Lt(){var n=Date.now();for(ec=Ka;ec;)n>=ec.t&&(ec.f=ec.c(n-ec.t)),ec=ec.n;return n}function Tt(){for(var n,t=Ka,e=1/0;t;)t.f?t=n?n.n=t.n:Ka=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Qa=n,e}function Rt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Dt(n,t){var e=Math.pow(10,3*ga(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Pt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r&&e?function(n,t){for(var u=n.length,i=[],o=0,a=r[0],c=0;u>0&&a>0&&(c+a+1>t&&(a=Math.max(1,t-c)),i.push(n.substring(u-=a,u+a)),!((c+=a+1)>t));)a=r[o=(o+1)%r.length];return i.reverse().join(e)}:y;return function(n){var e=ic.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",c=e[4]||"",l=e[5],s=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1,y=!0;switch(h&&(h=+h.substring(1)),(l||"0"===r&&"="===o)&&(l=r="0",o="="),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":y=!1;case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=oc.get(g)||Ut;var M=l&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>p){var c=ta.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=y?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!l&&f&&(x=i(x,1/0));var S=v.length+x.length+b.length+(M?0:u.length),k=s>S?new Array(S=s-S+1).join(r):"";return M&&(x=i(k+x,k.length?s-b.length:1/0)),u+=v,n=x+b,("<"===o?u+n+k:">"===o?k+u+n:"^"===o?k.substring(0,S>>=1)+u+n+k.substring(S):u+(M?n:k+n))+e}}}function Ut(n){return n+""}function jt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Ft(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new cc(e-1)),1),e}function i(n,e){return t(n=new cc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{cc=jt;var r=new jt;return r._=n,o(r,t,e)}finally{cc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Ht(n);return c.floor=c,c.round=Ht(r),c.ceil=Ht(u),c.offset=Ht(i),c.range=a,n}function Ht(n){return function(t,e){try{cc=jt;var r=new jt;return r._=t,n(r,e)._}finally{cc=Date}}}function Ot(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(c,a)),null!=(u=sc[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=N[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.slice(c,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&cc!==jt,o=new(i?jt:cc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,l=e.length;c>a;){if(r>=l)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=C[o in sc?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.slice(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,N.c.toString(),t,r)}function c(n,t,r){return e(n,N.x.toString(),t,r)}function l(n,t,r){return e(n,N.X.toString(),t,r)}function s(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{cc=jt;var t=new cc;return t._=n,r(t)}finally{cc=Date}}var r=t(n);return e.parse=function(n){try{cc=jt;var t=r.parse(n);return t&&t._}finally{cc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ae;var M=ta.map(),x=Yt(v),b=Zt(v),_=Yt(d),w=Zt(d),S=Yt(m),k=Zt(m),E=Yt(y),A=Zt(y);p.forEach(function(n,t){M.set(n.toLowerCase(),t)});var N={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return It(n.getDate(),t,2)},e:function(n,t){return It(n.getDate(),t,2)},H:function(n,t){return It(n.getHours(),t,2)},I:function(n,t){return It(n.getHours()%12||12,t,2)},j:function(n,t){return It(1+ac.dayOfYear(n),t,3)},L:function(n,t){return It(n.getMilliseconds(),t,3)},m:function(n,t){return It(n.getMonth()+1,t,2)},M:function(n,t){return It(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return It(n.getSeconds(),t,2)},U:function(n,t){return It(ac.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return It(ac.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return It(n.getFullYear()%100,t,2)},Y:function(n,t){return It(n.getFullYear()%1e4,t,4)},Z:ie,"%":function(){return"%"}},C={a:r,A:u,b:i,B:o,c:a,d:Qt,e:Qt,H:te,I:te,j:ne,L:ue,m:Kt,M:ee,p:s,S:re,U:Xt,w:Vt,W:$t,x:c,X:l,y:Wt,Y:Bt,Z:Jt,"%":oe};return t}function It(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Yt(n){return new RegExp("^(?:"+n.map(ta.requote).join("|")+")","i")}function Zt(n){for(var t=new l,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Vt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Xt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function $t(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Bt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Wt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.y=Gt(+r[0]),e+r[0].length):-1}function Jt(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Gt(n){return n+(n>68?1900:2e3)}function Kt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Qt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function ne(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function te(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ee(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function re(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ue(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ie(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=ga(t)/60|0,u=ga(t)%60;return e+It(r,"0",2)+It(u,"0",2)}function oe(n,t,e){hc.lastIndex=0;var r=hc.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ae(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ce(){}function le(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function se(n,t){n&&dc.hasOwnProperty(n.type)&&dc[n.type](n,t)}function fe(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function he(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)fe(n[e],t,1);t.polygonEnd()}function ge(){function n(n,t){n*=Da,t=t*Da/2+qa/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),l=Math.sin(t),s=i*l,f=u*c+s*Math.cos(a),h=s*o*Math.sin(a);yc.add(Math.atan2(h,f)),r=n,u=c,i=l}var t,e,r,u,i;Mc.point=function(o,a){Mc.point=n,r=(t=o)*Da,u=Math.cos(a=(e=a)*Da/2+qa/4),i=Math.sin(a)},Mc.lineEnd=function(){n(t,e)}}function pe(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function ve(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function de(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function me(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function ye(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Me(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function xe(n){return[Math.atan2(n[1],n[0]),tt(n[2])]}function be(n,t){return ga(n[0]-t[0])<Ca&&ga(n[1]-t[1])<Ca}function _e(n,t){n*=Da;var e=Math.cos(t*=Da);we(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function we(n,t,e){++xc,_c+=(n-_c)/xc,wc+=(t-wc)/xc,Sc+=(e-Sc)/xc}function Se(){function n(n,u){n*=Da;var i=Math.cos(u*=Da),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),l=Math.atan2(Math.sqrt((l=e*c-r*a)*l+(l=r*o-t*c)*l+(l=t*a-e*o)*l),t*o+e*a+r*c);bc+=l,kc+=l*(t+(t=o)),Ec+=l*(e+(e=a)),Ac+=l*(r+(r=c)),we(t,e,r)}var t,e,r;qc.point=function(u,i){u*=Da;var o=Math.cos(i*=Da);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),qc.point=n,we(t,e,r)}}function ke(){qc.point=_e}function Ee(){function n(n,t){n*=Da;var e=Math.cos(t*=Da),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),l=u*c-i*a,s=i*o-r*c,f=r*a-u*o,h=Math.sqrt(l*l+s*s+f*f),g=r*o+u*a+i*c,p=h&&-nt(g)/h,v=Math.atan2(h,g);Nc+=p*l,Cc+=p*s,zc+=p*f,bc+=v,kc+=v*(r+(r=o)),Ec+=v*(u+(u=a)),Ac+=v*(i+(i=c)),we(r,u,i)}var t,e,r,u,i;qc.point=function(o,a){t=o,e=a,qc.point=n,o*=Da;var c=Math.cos(a*=Da);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),we(r,u,i)},qc.lineEnd=function(){n(t,e),qc.lineEnd=ke,qc.point=_e}}function Ae(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function Ne(){return!0}function Ce(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(be(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return void u.lineEnd()}var c=new qe(e,n,null,!0),l=new qe(e,null,c,!1);c.o=l,i.push(c),o.push(l),c=new qe(r,n,null,!1),l=new qe(r,null,c,!0),c.o=l,i.push(c),o.push(l)}}),o.sort(t),ze(i),ze(o),i.length){for(var a=0,c=e,l=o.length;l>a;++a)o[a].e=c=!c;for(var s,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;s=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,l=s.length;l>a;++a)u.point((f=s[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){s=g.p.z;for(var a=s.length-1;a>=0;--a)u.point((f=s[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,s=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ze(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function qe(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Le(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function l(){y.point=o,d.lineEnd()}function s(n,t){v.push([n,t]);var e=u(n,t);x.point(e[0],e[1])}function f(){x.lineStart(),v=[]}function h(){s(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(b||(i.polygonStart(),b=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Te))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:l,polygonStart:function(){y.point=s,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=l,g=ta.merge(g);var n=Fe(m,p);g.length?(b||(i.polygonStart(),b=!0),Ce(g,De,n,e,i)):n&&(b||(i.polygonStart(),b=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),b&&(i.polygonEnd(),b=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},M=Re(),x=t(M),b=!1;return y}}function Te(n){return n.length>1}function Re(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function De(n,t){return((n=n.x)[0]<0?n[1]-Ra-Ca:Ra-n[1])-((t=t.x)[0]<0?t[1]-Ra-Ca:Ra-t[1])}function Pe(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?qa:-qa,c=ga(i-e);ga(c-qa)<Ca?(n.point(e,r=(r+o)/2>0?Ra:-Ra),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=qa&&(ga(e-u)<Ca&&(e-=u*Ca),ga(i-a)<Ca&&(i-=a*Ca),r=Ue(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function Ue(n,t,e,r){var u,i,o=Math.sin(n-e);return ga(o)>Ca?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function je(n,t,e,r){var u;if(null==n)u=e*Ra,r.point(-qa,u),r.point(0,u),r.point(qa,u),r.point(qa,0),r.point(qa,-u),r.point(0,-u),r.point(-qa,-u),r.point(-qa,0),r.point(-qa,u);else if(ga(n[0]-t[0])>Ca){var i=n[0]<t[0]?qa:-qa;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function Fe(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;yc.reset();for(var a=0,c=t.length;c>a;++a){var l=t[a],s=l.length;if(s)for(var f=l[0],h=f[0],g=f[1]/2+qa/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===s&&(d=0),n=l[d];var m=n[0],y=n[1]/2+qa/4,M=Math.sin(y),x=Math.cos(y),b=m-h,_=b>=0?1:-1,w=_*b,S=w>qa,k=p*M;if(yc.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),i+=S?b+_*La:b,S^h>=e^m>=e){var E=de(pe(f),pe(n));Me(E);var A=de(u,E);Me(A);var N=(S^b>=0?-1:1)*tt(A[2]);(r>N||r===N&&(E[0]||E[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=m,p=M,v=x,f=n}}return(-Ca>i||Ca>i&&0>yc)^1&o}function He(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,l,s;return{lineStart:function(){l=c=!1,s=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?qa:-qa),h):0;if(!e&&(l=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(be(e,g)||be(p,g))&&(p[0]+=Ca,p[1]+=Ca,v=t(p[0],p[1]))),v!==c)s=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(s=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&be(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return s|(l&&c)<<1}}}function r(n,t,e){var r=pe(n),u=pe(t),o=[1,0,0],a=de(r,u),c=ve(a,a),l=a[0],s=c-l*l;if(!s)return!e&&n;var f=i*c/s,h=-i*l/s,g=de(o,a),p=ye(o,f),v=ye(a,h);me(p,v);var d=g,m=ve(p,d),y=ve(d,d),M=m*m-y*(ve(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=ye(d,(-m-x)/y);if(me(b,p),b=xe(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(_=w,w=S,S=_);var A=S-w,N=ga(A-qa)<Ca,C=N||Ca>A;if(!N&&k>E&&(_=k,k=E,E=_),C?N?k+E>0^b[1]<(ga(b[0]-w)<Ca?k:E):k<=b[1]&&b[1]<=E:A>qa^(w<=b[0]&&b[0]<=S)){var z=ye(d,(-m+x)/y);return me(z,p),[b,xe(z)]}}}function u(t,e){var r=o?n:qa-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ga(i)>Ca,c=gr(n,6*Da);return Le(t,e,c,o?[0,-n]:[-qa,n-qa])}function Oe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,l=o.y,s=a.x,f=a.y,h=0,g=1,p=s-c,v=f-l;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-l,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-l,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:l+h*v}),1>g&&(u.b={x:c+g*p,y:l+g*v}),u}}}}}}function Ie(n,t,e,r){function u(r,u){return ga(r[0]-n)<Ca?u>0?0:3:ga(r[0]-e)<Ca?u>0?2:1:ga(r[1]-t)<Ca?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&Q(l,i,n)>0&&++t:i[1]<=r&&Q(l,i,n)<0&&--t,l=i;return 0!==t}function l(i,a,c,l){var s=0,f=0;if(null==i||(s=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(a[0],a[1])}function s(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){s(n,t)&&a.point(n,t)}function h(){C.point=p,d&&d.push(m=[]),S=!0,w=!1,b=_=0/0}function g(){v&&(p(y,M),x&&w&&A.rejoin(),v.push(A.buffer())),C.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-Tc,Math.min(Tc,n)),t=Math.max(-Tc,Math.min(Tc,t));var e=s(n,t);if(d&&m.push([n,t]),S)y=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};N(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,m,y,M,x,b,_,w,S,k,E=a,A=Re(),N=Oe(n,t,e,r),C={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=ta.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),u&&Ce(v,i,t,l,a),a.polygonEnd()),v=d=m=null}};return C}}function Ye(n){var t=0,e=qa/3,r=ir(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*qa/180,e=n[1]*qa/180):[t/qa*180,e/qa*180]},u}function Ze(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,tt((i-(n*n+e*e)*u*u)/(2*u))]},e}function Ve(){function n(n,t){Dc+=u*n-r*t,r=n,u=t}var t,e,r,u;Hc.point=function(i,o){Hc.point=n,t=r=i,e=u=o},Hc.lineEnd=function(){n(t,e)}}function Xe(n,t){Pc>n&&(Pc=n),n>jc&&(jc=n),Uc>t&&(Uc=t),t>Fc&&(Fc=t)}function $e(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Be(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Be(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Be(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function We(n,t){_c+=n,wc+=t,++Sc}function Je(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);kc+=o*(t+n)/2,Ec+=o*(e+r)/2,Ac+=o,We(t=n,e=r)}var t,e;Ic.point=function(r,u){Ic.point=n,We(t=r,e=u)}}function Ge(){Ic.point=We}function Ke(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);kc+=o*(r+n)/2,Ec+=o*(u+t)/2,Ac+=o,o=u*n-r*t,Nc+=o*(r+n),Cc+=o*(u+t),zc+=3*o,We(r=n,u=t)}var t,e,r,u;Ic.point=function(i,o){Ic.point=n,We(t=r=i,e=u=o)},Ic.lineEnd=function(){n(t,e)}}function Qe(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,La)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function nr(n){function t(n){return(a?r:e)(n)}function e(t){return rr(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=0/0,S.point=i,t.lineStart()}function i(e,r){var i=pe([e,r]),o=n(e,r);u(M,x,y,b,_,w,M=o[0],x=o[1],y=e,b=i[0],_=i[1],w=i[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=l,S.lineEnd=s}function l(n,t){i(f=n,h=t),g=M,p=x,v=b,d=_,m=w,S.point=i}function s(){u(M,x,y,b,_,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c
+},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,l,s,f,h,g,p,v,d,m){var y=s-t,M=f-e,x=y*y+M*M;if(x>4*i&&d--){var b=a+g,_=c+p,w=l+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),E=ga(ga(w)-1)<Ca||ga(r-h)<Ca?(r+h)/2:Math.atan2(_,b),A=n(E,k),N=A[0],C=A[1],z=N-t,q=C-e,L=M*z-y*q;(L*L/x>i||ga((y*z+M*q)/x-.5)>.3||o>a*g+c*p+l*v)&&(u(t,e,r,a,c,l,N,C,E,b/=S,_/=S,w,d,m),m.point(N,C),u(N,C,E,b,_,w,s,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Da),a=16;return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function tr(n){var t=nr(function(t,e){return n([t*Pa,e*Pa])});return function(n){return or(t(n))}}function er(n){this.stream=n}function rr(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function ur(n){return ir(function(){return n})()}function ir(n){function t(n){return n=a(n[0]*Da,n[1]*Da),[n[0]*h+c,l-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Pa,n[1]*Pa]}function r(){a=Ae(o=lr(m,M,x),i);var n=i(v,d);return c=g-n[0]*h,l=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,o,a,c,l,s,f=nr(function(n,t){return n=i(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,M=0,x=0,b=Lc,_=y,w=null,S=null;return t.stream=function(n){return s&&(s.valid=!1),s=or(b(o,f(_(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Lc):He((w=+n)*Da),u()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Ie(n[0][0],n[0][1],n[1][0],n[1][1]):y,u()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Da,d=n[1]%360*Da,r()):[v*Pa,d*Pa]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Da,M=n[1]%360*Da,x=n.length>2?n[2]%360*Da:0,r()):[m*Pa,M*Pa,x*Pa]},ta.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function or(n){return rr(n,function(t,e){n.point(t*Da,e*Da)})}function ar(n,t){return[n,t]}function cr(n,t){return[n>qa?n-La:-qa>n?n+La:n,t]}function lr(n,t,e){return n?t||e?Ae(fr(n),hr(t,e)):fr(n):t||e?hr(t,e):cr}function sr(n){return function(t,e){return t+=n,[t>qa?t-La:-qa>t?t+La:t,e]}}function fr(n){var t=sr(n);return t.invert=sr(-n),t}function hr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+a*u;return[Math.atan2(c*i-s*o,a*r-l*u),tt(s*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*i-c*o;return[Math.atan2(c*i+l*o,a*r+s*u),tt(s*r-a*u)]},e}function gr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=pr(e,u),i=pr(e,i),(o>0?i>u:u>i)&&(u+=o*La)):(u=n+o*La,i=n-.5*c);for(var l,s=u;o>0?s>i:i>s;s-=c)a.point((l=xe([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],l[1])}}function pr(n,t){var e=pe(t);e[0]-=n,Me(e);var r=nt(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Ca)%(2*Math.PI)}function vr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function dr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function mr(n){return n.source}function yr(n){return n.target}function Mr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),l=u*Math.sin(n),s=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(it(r-t)+u*o*it(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,u=e*l+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Pa,Math.atan2(o,Math.sqrt(r*r+u*u))*Pa]}:function(){return[n*Pa,t*Pa]};return p.distance=h,p}function xr(){function n(n,u){var i=Math.sin(u*=Da),o=Math.cos(u),a=ga((n*=Da)-t),c=Math.cos(a);Yc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Zc.point=function(u,i){t=u*Da,e=Math.sin(i*=Da),r=Math.cos(i),Zc.point=n},Zc.lineEnd=function(){Zc.point=Zc.lineEnd=b}}function br(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function _r(n,t){function e(n,t){o>0?-Ra+Ca>t&&(t=-Ra+Ca):t>Ra-Ca&&(t=Ra-Ca);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(qa/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=K(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Ra]},e):Sr}function wr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ga(u)<Ca?ar:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-K(u)*Math.sqrt(n*n+e*e)]},e)}function Sr(n,t){return[n,Math.log(Math.tan(qa/4+t/2))]}function kr(n){var t,e=ur(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=qa*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Er(n,t){return[Math.log(Math.tan(qa/4+t/2)),-n]}function Ar(n){return n[0]}function Nr(n){return n[1]}function Cr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function zr(n,t){return n[0]-t[0]||n[1]-t[1]}function qr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Lr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(a*(c-l)-f*(u-i))/(f*o-a*s);return[u+h*o,c+h*s]}function Tr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Rr(){tu(this),this.edge=this.site=this.circle=null}function Dr(n){var t=el.pop()||new Rr;return t.site=n,t}function Pr(n){Xr(n),Qc.remove(n),el.push(n),tu(n)}function Ur(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Pr(n);for(var c=i;c.circle&&ga(e-c.circle.x)<Ca&&ga(r-c.circle.cy)<Ca;)i=c.P,a.unshift(c),Pr(c),c=i;a.unshift(c),Xr(c);for(var l=o;l.circle&&ga(e-l.circle.x)<Ca&&ga(r-l.circle.cy)<Ca;)o=l.N,a.push(l),Pr(l),l=o;a.push(l),Xr(l);var s,f=a.length;for(s=1;f>s;++s)l=a[s],c=a[s-1],Kr(l.edge,c.site,l.site,u);c=a[0],l=a[f-1],l.edge=Jr(c.site,l.site,null,u),Vr(c),Vr(l)}function jr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Qc._;a;)if(r=Fr(a,o)-i,r>Ca)a=a.L;else{if(u=i-Hr(a,o),!(u>Ca)){r>-Ca?(t=a.P,e=a):u>-Ca?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Dr(n);if(Qc.insert(t,c),t||e){if(t===e)return Xr(t),e=Dr(t.site),Qc.insert(c,e),c.edge=e.edge=Jr(t.site,c.site),Vr(t),void Vr(e);if(!e)return void(c.edge=Jr(t.site,c.site));Xr(t),Xr(e);var l=t.site,s=l.x,f=l.y,h=n.x-s,g=n.y-f,p=e.site,v=p.x-s,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,M=v*v+d*d,x={x:(d*y-g*M)/m+s,y:(h*M-v*y)/m+f};Kr(e.edge,l,p,x),c.edge=Jr(l,n,null,x),e.edge=Jr(n,p,null,x),Vr(t),Vr(e)}}function Fr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,l=c-t;if(!l)return a;var s=a-r,f=1/i-1/l,h=s/l;return f?(-h+Math.sqrt(h*h-2*f*(s*s/(-2*l)-c+l/2+u-i/2)))/f+r:(r+a)/2}function Hr(n,t){var e=n.N;if(e)return Fr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Or(n){this.site=n,this.edges=[]}function Ir(n){for(var t,e,r,u,i,o,a,c,l,s,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Kc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)s=a[o].end(),r=s.x,u=s.y,l=a[++o%c].start(),t=l.x,e=l.y,(ga(r-t)>Ca||ga(u-e)>Ca)&&(a.splice(o,0,new Qr(Gr(i.site,s,ga(r-f)<Ca&&p-u>Ca?{x:f,y:ga(t-f)<Ca?e:p}:ga(u-p)<Ca&&h-r>Ca?{x:ga(e-p)<Ca?t:h,y:p}:ga(r-h)<Ca&&u-g>Ca?{x:h,y:ga(t-h)<Ca?e:g}:ga(u-g)<Ca&&r-f>Ca?{x:ga(e-g)<Ca?t:f,y:g}:null),i.site,null)),++c)}function Yr(n,t){return t.angle-n.angle}function Zr(){tu(this),this.x=this.y=this.arc=this.site=this.cy=null}function Vr(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,l=r.y-a,s=i.x-o,f=i.y-a,h=2*(c*f-l*s);if(!(h>=-za)){var g=c*c+l*l,p=s*s+f*f,v=(f*g-l*p)/h,d=(c*p-s*g)/h,f=d+a,m=rl.pop()||new Zr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,M=tl._;M;)if(m.y<M.y||m.y===M.y&&m.x<=M.x){if(!M.L){y=M.P;break}M=M.L}else{if(!M.R){y=M;break}M=M.R}tl.insert(y,m),y||(nl=m)}}}}function Xr(n){var t=n.circle;t&&(t.P||(nl=t.N),tl.remove(t),rl.push(t),tu(t),n.circle=null)}function $r(n){for(var t,e=Gc,r=Oe(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Br(t,n)||!r(t)||ga(t.a.x-t.b.x)<Ca&&ga(t.a.y-t.b.y)<Ca)&&(t.a=t.b=null,e.splice(u,1))}function Br(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],l=t[1][1],s=n.l,f=n.r,h=s.x,g=s.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=l)return}else i={x:d,y:c};e={x:d,y:l}}else{if(i){if(i.y<c)return}else i={x:d,y:l};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=l)return}else i={x:(c-u)/r,y:c};e={x:(l-u)/r,y:l}}else{if(i){if(i.y<c)return}else i={x:(l-u)/r,y:l};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Wr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Jr(n,t,e,r){var u=new Wr(n,t);return Gc.push(u),e&&Kr(u,n,t,e),r&&Kr(u,t,n,r),Kc[n.i].edges.push(new Qr(u,n,t)),Kc[t.i].edges.push(new Qr(u,t,n)),u}function Gr(n,t,e){var r=new Wr(n,null);return r.a=t,r.b=e,Gc.push(r),r}function Kr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function Qr(n,t,e){var r=n.a,u=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function nu(){this._=null}function tu(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function eu(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ru(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function uu(n){for(;n.L;)n=n.L;return n}function iu(n,t){var e,r,u,i=n.sort(ou).pop();for(Gc=[],Kc=new Array(n.length),Qc=new nu,tl=new nu;;)if(u=nl,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Kc[i.i]=new Or(i),jr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;Ur(u.arc)}t&&($r(t),Ir(t));var o={cells:Kc,edges:Gc};return Qc=tl=Gc=Kc=null,o}function ou(n,t){return t.y-n.y||t.x-n.x}function au(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function cu(n){return n.x}function lu(n){return n.y}function su(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function fu(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&fu(n,c[0],e,r,o,a),c[1]&&fu(n,c[1],o,r,u,a),c[2]&&fu(n,c[2],e,a,o,i),c[3]&&fu(n,c[3],o,a,u,i)}}function hu(n,t,e,r,u,i,o){var a,c=1/0;return function l(n,s,f,h,g){if(!(s>i||f>o||r>h||u>g)){if(p=n.point){var p,v=t-n.x,d=e-n.y,m=v*v+d*d;if(c>m){var y=Math.sqrt(c=m);r=t-y,u=e-y,i=t+y,o=e+y,a=p}}for(var M=n.nodes,x=.5*(s+h),b=.5*(f+g),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:l(n,s,f,x,b);break;case 1:l(n,x,f,h,b);break;case 2:l(n,s,b,x,g);break;case 3:l(n,x,b,h,g)}}}(n,r,u,i,o),a}function gu(n,t){n=ta.rgb(n),t=ta.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+xt(Math.round(e+i*n))+xt(Math.round(r+o*n))+xt(Math.round(u+a*n))}}function pu(n,t){var e,r={},u={};for(e in n)e in t?r[e]=mu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function vu(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function du(n,t){var e,r,u,i=il.lastIndex=ol.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=il.exec(n))&&(r=ol.exec(t));)(u=r.index)>i&&(u=t.slice(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:vu(e,r)})),i=ol.lastIndex;return i<t.length&&(u=t.slice(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function mu(n,t){for(var e,r=ta.interpolators.length;--r>=0&&!(e=ta.interpolators[r](n,t)););return e}function yu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(mu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function Mu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function xu(n){return function(t){return 1-n(1-t)}}function bu(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function _u(n){return n*n}function wu(n){return n*n*n}function Su(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function ku(n){return function(t){return Math.pow(t,n)}}function Eu(n){return 1-Math.cos(n*Ra)}function Au(n){return Math.pow(2,10*(n-1))}function Nu(n){return 1-Math.sqrt(1-n*n)}function Cu(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/La*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*La/t)}}function zu(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function qu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Lu(n,t){n=ta.hcl(n),t=ta.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return st(e+i*n,r+o*n,u+a*n)+""}}function Tu(n,t){n=ta.hsl(n),t=ta.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function Ru(n,t){n=ta.lab(n),t=ta.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ht(e+i*n,r+o*n,u+a*n)+""}}function Du(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Pu(n){var t=[n.a,n.b],e=[n.c,n.d],r=ju(t),u=Uu(t,e),i=ju(Fu(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Pa,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Pa:0}function Uu(n,t){return n[0]*t[0]+n[1]*t[1]}function ju(n){var t=Math.sqrt(Uu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Fu(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Hu(n,t){var e,r=[],u=[],i=ta.transform(n),o=ta.transform(t),a=i.translate,c=o.translate,l=i.rotate,s=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:vu(a[0],c[0])},{i:3,x:vu(a[1],c[1])})):r.push(c[0]||c[1]?"translate("+c+")":""),l!=s?(l-s>180?s+=360:s-l>180&&(l+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:vu(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:vu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:vu(g[0],p[0])},{i:e-2,x:vu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Ou(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Iu(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Yu(n){for(var t=n.source,e=n.target,r=Vu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Zu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Vu(n,t){if(n===t)return n;for(var e=Zu(n),r=Zu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Xu(n){n.fixed|=2}function $u(n){n.fixed&=-7}function Bu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Wu(n){n.fixed&=-5}function Ju(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Ju(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var l=t*e[n.point.index];n.charge+=n.pointCharge=l,r+=l*n.point.x,u+=l*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Gu(n,t){return ta.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=ri,n}function Ku(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Qu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function ni(n){return n.children}function ti(n){return n.value}function ei(n,t){return t.value-n.value}function ri(n){return ta.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function ui(n){return n.x}function ii(n){return n.y}function oi(n,t,e){n.y0=t,n.y=e}function ai(n){return ta.range(n.length)}function ci(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function li(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function si(n){return n.reduce(fi,0)}function fi(n,t){return n+t[1]}function hi(n,t){return gi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function gi(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function pi(n){return[ta.min(n),ta.max(n)]}function vi(n,t){return n.value-t.value}function di(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function mi(n,t){n._pack_next=t,t._pack_prev=n}function yi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function Mi(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,u,i,o,a,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(xi),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(u=e[1],u.x=u.r,u.y=0,t(u),l>2))for(i=e[2],wi(r,u,i),t(i),di(r,i),r._pack_prev=i,di(i,u),u=r._pack_next,o=3;l>o;o++){wi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(yi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!yi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?mi(r,u=a):mi(r=c,u),o--):(di(r,i),u=i,t(i))}var m=(s+f)/2,y=(h+g)/2,M=0;for(o=0;l>o;o++)i=e[o],i.x-=m,i.y-=y,M=Math.max(M,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=M,e.forEach(bi)}}function xi(n){n._pack_next=n._pack_prev=n}function bi(n){delete n._pack_next,delete n._pack_prev}function _i(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)_i(u[i],t,e,r)}function wi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),l=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+l*i,e.y=n.y+c*i-l*u}else e.x=n.x+r,e.y=n.y}function Si(n,t){return n.parent==t.parent?1:2}function ki(n){var t=n.children;return t.length?t[0]:n.t}function Ei(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ai(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Ni(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Ci(n,t,e){return n.a.parent===t.parent?n.a:e}function zi(n){return 1+ta.max(n,function(n){return n.y})}function qi(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Li(n){var t=n.children;return t&&t.length?Li(t[0]):n}function Ti(n){var t,e=n.children;return e&&(t=e.length)?Ti(e[t-1]):n}function Ri(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Di(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Pi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ui(n){return n.rangeExtent?n.rangeExtent():Pi(n.range())}function ji(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Fi(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Hi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ml}function Oi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=ta.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Ii(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Oi:ji,c=r?Iu:Ou;return o=u(n,t,c,e),a=u(t,n,c,mu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Du)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Xi(n,t)},i.tickFormat=function(t,e){return $i(n,t,e)},i.nice=function(t){return Zi(n,t),u()},i.copy=function(){return Ii(n,t,e,r)},u()}function Yi(n,t){return ta.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Zi(n,t){return Fi(n,Hi(Vi(n,t)[2]))}function Vi(n,t){null==t&&(t=10);var e=Pi(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Xi(n,t){return ta.range.apply(ta,Vi(n,t))}function $i(n,t,e){var r=Vi(n,t);if(e){var u=ic.exec(e);if(u.shift(),"s"===u[8]){var i=ta.formatPrefix(Math.max(ga(r[0]),ga(r[1])));return u[7]||(u[7]="."+Bi(i.scale(r[2]))),u[8]="f",e=ta.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Wi(u[8],r)),e=u.join("")}else e=",."+Bi(r[2])+"f";return ta.format(e)}function Bi(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Wi(n,t){var e=Bi(t[2]);return n in yl?Math.abs(e-Bi(Math.max(ga(t[0]),ga(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Ji(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Fi(r.map(u),e?Math:xl);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Pi(r),o=[],a=n[0],c=n[1],l=Math.floor(u(a)),s=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)o.push(i(l)*h);o.push(i(l))}else for(o.push(i(l));l++<s;)for(var h=f-1;h>0;h--)o.push(i(l)*h);for(l=0;o[l]<a;l++);for(s=o.length;o[s-1]>c;s--);o=o.slice(l,s)}return o},o.tickFormat=function(n,t){if(!arguments.length)return Ml;arguments.length<2?t=Ml:"function"!=typeof t&&(t=ta.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Ji(n.copy(),t,e,r)},Yi(o,n)}function Gi(n,t,e){function r(t){return n(u(t))}var u=Ki(t),i=Ki(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Xi(e,n)},r.tickFormat=function(n,t){return $i(e,n,t)},r.nice=function(n){return r.domain(Zi(e,n))},r.exponent=function(o){return arguments.length?(u=Ki(t=o),i=Ki(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Gi(n.copy(),t,e)},Yi(r,n)}function Ki(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Qi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return ta.range(n.length).map(function(n){return t+e*n})}var u,i,o;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new l;for(var i,o=-1,a=r.length;++o<a;)u.has(i=r[o])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,o=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=(c+l)/2,0):(l-c)/(n.length-1+a);return i=r(c+s*a/2,s),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=l=Math.round((c+l)/2),0):(l-c)/(n.length-1+a)|0;return i=r(c+Math.round(s*a/2+(l-c-(n.length-1+a)*s)/2),s),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=(f-s)/(n.length-a+2*c);return i=r(s+h*c,h),l&&i.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=Math.floor((f-s)/(n.length-a+2*c));return i=r(s+Math.round((f-s-(n.length-a)*h)/2),h),l&&i.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Pi(t.a[0])},e.copy=function(){return Qi(n,t)},e.domain(n)}function no(n,t){function i(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ta.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ta.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(u).sort(e),i()):n},o.range=function(n){return arguments.length?(t=n,i()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[0/0,0/0]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return no(n,t)},i()}function to(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return to(n,t,e)},u()}function eo(n,t){function e(e){return e>=e?t[ta.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return eo(n,t)},e}function ro(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Xi(n,t)},t.tickFormat=function(t,e){return $i(n,t,e)},t.copy=function(){return ro(n)},t}function uo(){return 0}function io(n){return n.innerRadius}function oo(n){return n.outerRadius}function ao(n){return n.startAngle}function co(n){return n.endAngle}function lo(n){return n&&n.padAngle}function so(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function fo(n,t,e,r,u){var i=n[0]-t[0],o=n[1]-t[1],a=(u?r:-r)/Math.sqrt(i*i+o*o),c=a*o,l=-a*i,s=n[0]+c,f=n[1]+l,h=t[0]+c,g=t[1]+l,p=(s+h)/2,v=(f+g)/2,d=h-s,m=g-f,y=d*d+m*m,M=e-r,x=s*g-h*f,b=(0>m?-1:1)*Math.sqrt(M*M*y-x*x),_=(x*m-d*b)/y,w=(-x*d-m*b)/y,S=(x*m+d*b)/y,k=(-x*d+m*b)/y,E=_-p,A=w-v,N=S-p,C=k-v;return E*E+A*A>N*N+C*C&&(_=S,w=k),[[_-c,w-l],[_*e/M,w*e/M]]}function ho(n){function t(t){function o(){l.push("M",i(n(s),a))}for(var c,l=[],s=[],f=-1,h=t.length,g=Et(e),p=Et(r);++f<h;)u.call(this,c=t[f],f)?s.push([+g.call(this,c,f),+p.call(this,c,f)]):s.length&&(o(),s=[]);return s.length&&o(),l.length?l.join(""):null}var e=Ar,r=Nr,u=Ne,i=go,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=El.get(n)||go).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function go(n){return n.join("L")}function po(n){return go(n)+"Z"}function vo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function mo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function yo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function Mo(n,t){return n.length<4?go(n):n[1]+_o(n.slice(1,-1),wo(n,t))}function xo(n,t){return n.length<3?go(n):n[0]+_o((n.push(n[0]),n),wo([n[n.length-2]].concat(n,[n[1]]),t))}function bo(n,t){return n.length<3?go(n):n[0]+_o(n,wo(n,t))}function _o(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return go(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var l=2;l<t.length;l++,c++)i=n[c],a=t[l],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var s=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+s[0]+","+s[1]}return r}function wo(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function So(n){if(n.length<3)return go(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",No(Cl,o),",",No(Cl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Co(c,o,a);return n.pop(),c.push("L",r),c.join("")}function ko(n){if(n.length<4)return go(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(No(Cl,i)+","+No(Cl,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Co(e,i,o);return e.join("")}function Eo(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[No(Cl,o),",",No(Cl,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Co(t,o,a);return t.join("")}function Ao(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,l=-1;++l<=e;)r=n[l],u=l/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return So(n)}function No(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Co(n,t,e){n.push("C",No(Al,t),",",No(Al,e),",",No(Nl,t),",",No(Nl,e),",",No(Cl,t),",",No(Cl,e))}function zo(n,t){return(t[1]-n[1])/(t[0]-n[0])}function qo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=zo(u,i);++t<e;)r[t]=(o+(o=zo(u=i,i=n[t+1])))/2;return r[t]=o,r}function Lo(n){for(var t,e,r,u,i=[],o=qo(n),a=-1,c=n.length-1;++a<c;)t=zo(n[a],n[a+1]),ga(t)<Ca?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function To(n){return n.length<3?go(n):n[0]+_o(n,Lo(n))}function Ro(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]-Ra,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Do(n){function t(t){function c(){v.push("M",a(n(m),f),s,l(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,M=t.length,x=Et(e),b=Et(u),_=e===r?function(){return g}:Et(r),w=u===i?function(){return p}:Et(i);++y<M;)o.call(this,h=t[y],y)?(d.push([g=+x.call(this,h,y),p=+b.call(this,h,y)]),m.push([+_.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=Ar,r=Ar,u=0,i=Nr,o=Ne,a=go,c=a.key,l=a,s="L",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r
+},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=El.get(n)||go).key,l=a.reverse||a,s=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Po(n){return n.radius}function Uo(n){return[n.x,n.y]}function jo(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Ra;return[e*Math.cos(r),e*Math.sin(r)]}}function Fo(){return 64}function Ho(){return"circle"}function Oo(n){var t=Math.sqrt(n/qa);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Io(n){return function(){var t,e;(t=this[n])&&(e=t[t.active])&&(--t.count?delete t[t.active]:delete this[n],t.active+=.5,e.event&&e.event.interrupt.call(this,this.__data__,e.index))}}function Yo(n,t,e){return ya(n,Pl),n.namespace=t,n.id=e,n}function Zo(n,t,e,r){var u=n.id,i=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[i][u].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[i][u].tween.set(t,e)}))}function Vo(n){return null==n&&(n=""),function(){this.textContent=n}}function Xo(n){return null==n?"__transition__":"__transition_"+n+"__"}function $o(n,t,e,r,u){var i=n[e]||(n[e]={active:0,count:0}),o=i[r];if(!o){var a=u.time;o=i[r]={tween:new l,time:a,delay:u.delay,duration:u.duration,ease:u.ease,index:t},u=null,++i.count,ta.timer(function(u){function c(e){if(i.active>r)return s();var u=i[i.active];u&&(--i.count,delete i[i.active],u.event&&u.event.interrupt.call(n,n.__data__,u.index)),i.active=r,o.event&&o.event.start.call(n,n.__data__,t),o.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&v.push(r)}),h=o.ease,f=o.duration,ta.timer(function(){return p.c=l(e||1)?Ne:l,1},0,a)}function l(e){if(i.active!==r)return 1;for(var u=e/f,a=h(u),c=v.length;c>0;)v[--c].call(n,a);return u>=1?(o.event&&o.event.end.call(n,n.__data__,t),s()):void 0}function s(){return--i.count?delete i[r]:delete n[e],1}var f,h,g=o.delay,p=ec,v=[];return p.t=g+a,u>=g?c(u-g):void(p.c=c)},0,a)}}function Bo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function Wo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function Jo(n){return n.toISOString()}function Go(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=ta.bisect(Vl,u);return i==Vl.length?[t.year,Vi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Vl[i-1]<Vl[i]/u?i-1:i]:[Bl,Vi(n,e)[2]]}return r.invert=function(t){return Ko(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Ko)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Ko(+e+1),t).length}var i=r.domain(),o=Pi(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Fi(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Ko(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Ko(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Pi(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Ko(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Go(n.copy(),t,e)},Yi(r,n)}function Ko(n){return new Date(n)}function Qo(n){return JSON.parse(n.responseText)}function na(n){var t=ua.createRange();return t.selectNode(ua.body),t.createContextualFragment(n.responseText)}var ta={version:"3.5.5"},ea=[].slice,ra=function(n){return ea.call(n)},ua=this.document;if(ua)try{ra(ua.documentElement.childNodes)[0].nodeType}catch(ia){ra=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),ua)try{ua.createElement("DIV").style.setProperty("opacity",0,"")}catch(oa){var aa=this.Element.prototype,ca=aa.setAttribute,la=aa.setAttributeNS,sa=this.CSSStyleDeclaration.prototype,fa=sa.setProperty;aa.setAttribute=function(n,t){ca.call(this,n,t+"")},aa.setAttributeNS=function(n,t,e){la.call(this,n,t,e+"")},sa.setProperty=function(n,t,e){fa.call(this,n,t+"",e)}}ta.ascending=e,ta.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},ta.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},ta.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},ta.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o;)if(null!=(r=n[i])&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},ta.sum=function(n,t){var e,r=0,i=n.length,o=-1;if(1===arguments.length)for(;++o<i;)u(e=+n[o])&&(r+=e);else for(;++o<i;)u(e=+t.call(n,n[o],o))&&(r+=e);return r},ta.mean=function(n,t){var e,i=0,o=n.length,a=-1,c=o;if(1===arguments.length)for(;++a<o;)u(e=r(n[a]))?i+=e:--c;else for(;++a<o;)u(e=r(t.call(n,n[a],a)))?i+=e:--c;return c?i/c:void 0},ta.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},ta.median=function(n,t){var i,o=[],a=n.length,c=-1;if(1===arguments.length)for(;++c<a;)u(i=r(n[c]))&&o.push(i);else for(;++c<a;)u(i=r(t.call(n,n[c],c)))&&o.push(i);return o.length?ta.quantile(o.sort(e),.5):void 0},ta.variance=function(n,t){var e,i,o=n.length,a=0,c=0,l=-1,s=0;if(1===arguments.length)for(;++l<o;)u(e=r(n[l]))&&(i=e-a,a+=i/++s,c+=i*(e-a));else for(;++l<o;)u(e=r(t.call(n,n[l],l)))&&(i=e-a,a+=i/++s,c+=i*(e-a));return s>1?c/(s-1):void 0},ta.deviation=function(){var n=ta.variance.apply(this,arguments);return n?Math.sqrt(n):n};var ha=i(e);ta.bisectLeft=ha.left,ta.bisect=ta.bisectRight=ha.right,ta.bisector=function(n){return i(1===n.length?function(t,r){return e(n(t),r)}:n)},ta.shuffle=function(n,t,e){(i=arguments.length)<3&&(e=n.length,2>i&&(t=0));for(var r,u,i=e-t;i;)u=Math.random()*i--|0,r=n[i+t],n[i+t]=n[u+t],n[u+t]=r;return n},ta.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ta.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},ta.zip=function(){if(!(r=arguments.length))return[];for(var n=-1,t=ta.min(arguments,o),e=new Array(t);++n<t;)for(var r,u=-1,i=e[n]=new Array(r);++u<r;)i[u]=arguments[u][n];return e},ta.transpose=function(n){return ta.zip.apply(ta,n)},ta.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ta.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ta.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ta.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ga=Math.abs;ta.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,u=[],i=a(ga(e)),o=-1;if(n*=i,t*=i,e*=i,0>e)for(;(r=n+e*++o)>t;)u.push(r/i);else for(;(r=n+e*++o)<t;)u.push(r/i);return u},ta.map=function(n,t){var e=new l;if(n instanceof l)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,u=-1,i=n.length;if(1===arguments.length)for(;++u<i;)e.set(u,n[u]);else for(;++u<i;)e.set(t.call(n,r=n[u],u),r)}else for(var o in n)e.set(o,n[o]);return e};var pa="__proto__",va="\x00";c(l,{has:h,get:function(n){return this._[s(n)]},set:function(n,t){return this._[s(n)]=t},remove:g,keys:p,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:f(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t),this._[t])}}),ta.nest=function(){function n(t,o,a){if(a>=i.length)return r?r.call(u,o):e?o.sort(e):o;for(var c,s,f,h,g=-1,p=o.length,v=i[a++],d=new l;++g<p;)(h=d.get(c=v(s=o[g])))?h.push(s):d.set(c,[s]);return t?(s=t(),f=function(e,r){s.set(e,n(t,r,a))}):(s={},f=function(e,r){s[e]=n(t,r,a)}),d.forEach(f),s}function t(n,e){if(e>=i.length)return n;var r=[],u=o[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],o=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(ta.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return o[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},ta.set=function(n){var t=new m;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},c(m,{has:h,add:function(n){return this._[s(n+="")]=!0,n},remove:g,values:p,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t))}}),ta.behavior={},ta.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=M(n,t,t[e]);return n};var da=["webkit","ms","moz","Moz","o","O"];ta.dispatch=function(){for(var n=new _,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=w(n);return n},_.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ta.event=null,ta.requote=function(n){return n.replace(ma,"\\$&")};var ma=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ya={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},Ma=function(n,t){return t.querySelector(n)},xa=function(n,t){return t.querySelectorAll(n)},ba=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(ba=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(Ma=function(n,t){return Sizzle(n,t)[0]||null},xa=Sizzle,ba=Sizzle.matchesSelector),ta.selection=function(){return ta.select(ua.documentElement)};var _a=ta.selection.prototype=[];_a.select=function(n){var t,e,r,u,i=[];n=N(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,l=r.length;++c<l;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return A(i)},_a.selectAll=function(n){var t,e,r=[];n=C(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=ra(n.call(e,e.__data__,a,u))),t.parentNode=e);return A(r)};var wa={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ta.ns={prefix:wa,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.slice(0,t),n=n.slice(t+1)),wa.hasOwnProperty(e)?{space:wa[e],local:n}:n}},_a.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ta.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},_a.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!L(n[u]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},_a.style=function(n,e,r){var u=arguments.length;if(3>u){if("string"!=typeof n){2>u&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>u){var i=this.node();return t(i).getComputedStyle(i,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},_a.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},_a.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},_a.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},_a.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},_a.insert=function(n,t){return n=j(n),t=N(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},_a.remove=function(){return this.each(F)},_a.data=function(n,t){function e(n,e){var r,u,i,o=n.length,f=e.length,h=Math.min(o,f),g=new Array(f),p=new Array(f),v=new Array(o);if(t){var d,m=new l,y=new Array(o);for(r=-1;++r<o;)m.has(d=t.call(u=n[r],u.__data__,r))?v[r]=u:m.set(d,u),y[r]=d;for(r=-1;++r<f;)(u=m.get(d=t.call(e,i=e[r],r)))?u!==!0&&(g[r]=u,u.__data__=i):p[r]=H(i),m.set(d,!0);for(r=-1;++r<o;)m.get(y[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=H(i);for(;f>r;++r)p[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,a.push(p),c.push(g),s.push(v)}var r,u,i=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++i<o;)(u=r[i])&&(n[i]=u.__data__);return n}var a=Z([]),c=A([]),s=A([]);if("function"==typeof n)for(;++i<o;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<o;)e(r=this[i],n);return c.enter=function(){return a},c.exit=function(){return s},c},_a.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},_a.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return A(u)},_a.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},_a.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},_a.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},_a.call=function(n){var t=ra(arguments);return n.apply(t[0]=this,t),this},_a.empty=function(){return!this.node()},_a.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},_a.size=function(){var n=0;return Y(this,function(){++n}),n};var Sa=[];ta.selection.enter=Z,ta.selection.enter.prototype=Sa,Sa.append=_a.append,Sa.empty=_a.empty,Sa.node=_a.node,Sa.call=_a.call,Sa.size=_a.size,Sa.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var l=-1,s=u.length;++l<s;)(i=u[l])?(t.push(r[l]=e=n.call(u.parentNode,i.__data__,l,a)),e.__data__=i.__data__):t.push(null)}return A(o)},Sa.insert=function(n,t){return arguments.length<2&&(t=V(this)),_a.insert.call(this,n,t)},ta.select=function(t){var e;return"string"==typeof t?(e=[Ma(t,ua)],e.parentNode=ua.documentElement):(e=[t],e.parentNode=n(t)),A([e])},ta.selectAll=function(n){var t;return"string"==typeof n?(t=ra(xa(n,ua)),t.parentNode=ua.documentElement):(t=n,t.parentNode=null),A([t])},_a.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var ka=ta.map({mouseenter:"mouseover",mouseleave:"mouseout"});ua&&ka.forEach(function(n){"on"+n in ua&&ka.remove(n)});var Ea,Aa=0;ta.mouse=function(n){return J(n,k())};var Na=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ta.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return J(n,r)},ta.behavior.drag=function(){function n(){this.on("mousedown.drag",i).on("touchstart.drag",o)}function e(n,t,e,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],p|=n|e,M=r,g({type:"drag",x:r[0]+l[0],y:r[1]+l[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&ta.event.target===f),g({type:"dragend"}))}var l,s=this,f=ta.event.target,h=s.parentNode,g=r.of(s,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=ta.select(e(f)).on(i+d,a).on(o+d,c),y=W(f),M=t(h,v);u?(l=u.apply(s,arguments),l=[l.x-M[0],l.y-M[1]]):l=[0,0],g({type:"dragstart"})}}var r=E(n,"drag","dragstart","dragend"),u=null,i=e(b,ta.mouse,t,"mousemove","mouseup"),o=e(G,ta.touch,y,"touchmove","touchend");return n.origin=function(t){return arguments.length?(u=t,n):u},ta.rebind(n,r,"on")},ta.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?ra(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Ca=1e-6,za=Ca*Ca,qa=Math.PI,La=2*qa,Ta=La-Ca,Ra=qa/2,Da=qa/180,Pa=180/qa,Ua=Math.SQRT2,ja=2,Fa=4;ta.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=rt(v),o=i/(ja*h)*(e*ut(Ua*t+v)-et(v));return[r+o*l,u+o*s,i*e/rt(Ua*t+v)]}return[r+n*l,u+n*s,i*Math.exp(Ua*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],l=o-r,s=a-u,f=l*l+s*s,h=Math.sqrt(f),g=(c*c-i*i+Fa*f)/(2*i*ja*h),p=(c*c-i*i-Fa*f)/(2*c*ja*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Ua;return e.duration=1e3*y,e},ta.behavior.zoom=function(){function n(n){n.on(q,f).on(Oa+".zoom",g).on("dblclick.zoom",p).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function u(n){k.k=Math.max(N[0],Math.min(N[1],n))}function i(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},u(Math.pow(2,o)),i(d=e,r),t=ta.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function c(n){z++||n({type:"zoomstart"})}function l(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function s(n){--z||n({type:"zoomend"}),d=null}function f(){function n(){f=1,i(ta.mouse(u),g),l(a)}function r(){h.on(L,null).on(T,null),p(f&&ta.event.target===o),s(a)}var u=this,o=ta.event.target,a=D.of(u,arguments),f=0,h=ta.select(t(u)).on(L,n).on(T,r),g=e(ta.mouse(u)),p=W(u);Dl.call(u),c(a)}function h(){function n(){var n=ta.touches(p);return g=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ta.event.target;ta.select(t).on(x,r).on(b,a),_.push(t);for(var e=ta.event.changedTouches,u=0,i=e.length;i>u;++u)d[e[u].identifier]=null;var c=n(),l=Date.now();if(1===c.length){if(500>l-M){var s=c[0];o(p,s,d[s.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=l}else if(c.length>1){var s=c[0],f=c[1],h=s[0]-f[0],g=s[1]-f[1];m=h*h+g*g}}function r(){var n,t,e,r,o=ta.touches(p);Dl.call(p);for(var a=0,c=o.length;c>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=m&&Math.sqrt(s/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],u(f*g)}M=null,i(n,t),l(v)}function a(){if(ta.event.touches.length){for(var t=ta.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var u in d)return void n()}ta.selectAll(_).on(y,null),w.on(q,f).on(R,h),E(),s(v)}var g,p=this,v=D.of(p,arguments),d={},m=0,y=".zoom-"+ta.event.changedTouches[0].identifier,x="touchmove"+y,b="touchend"+y,_=[],w=ta.select(p),E=W(p);t(),c(v),w.on(q,null).on(R,t)}function g(){var n=D.of(this,arguments);y?clearTimeout(y):(v=e(d=m||ta.mouse(this)),Dl.call(this),c(n)),y=setTimeout(function(){y=null,s(n)},50),S(),u(Math.pow(2,.002*Ha())*k.k),i(d,v),l(n)}function p(){var n=ta.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ta.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,m,y,M,x,b,_,w,k={x:0,y:0,k:1},A=[960,500],N=Ia,C=250,z=0,q="mousedown.zoom",L="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=E(n,"zoomstart","zoom","zoomend");return Oa||(Oa="onwheel"in ua?(Ha=function(){return-ta.event.deltaY*(ta.event.deltaMode?120:1)},"wheel"):"onmousewheel"in ua?(Ha=function(){return ta.event.wheelDelta},"mousewheel"):(Ha=function(){return-ta.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Tl?ta.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},c(n)}).tween("zoom:zoom",function(){var e=A[0],r=A[1],u=d?d[0]:e/2,i=d?d[1]:r/2,o=ta.interpolateZoom([(u-k.x)/k.k,(i-k.y)/k.k,e/k.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:u-r[0]*a,y:i-r[1]*a,k:a},l(n)}}).each("interrupt.zoom",function(){s(n)}).each("end.zoom",function(){s(n)}):(this.__chart__=k,c(n),l(n),s(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:+t},a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(N=null==t?Ia:[+t[0],+t[1]],n):N},n.center=function(t){return arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return arguments.length?(A=t&&[+t[0],+t[1]],n):A},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ta.rebind(n,D,"on")};var Ha,Oa,Ia=[0,1/0];ta.color=ot,ot.prototype.toString=function(){return this.rgb()+""},ta.hsl=at;var Ya=at.prototype=new ot;Ya.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,this.l/n)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,n*this.l)},Ya.rgb=function(){return ct(this.h,this.s,this.l)},ta.hcl=lt;var Za=lt.prototype=new ot;Za.brighter=function(n){return new lt(this.h,this.c,Math.min(100,this.l+Va*(arguments.length?n:1)))},Za.darker=function(n){return new lt(this.h,this.c,Math.max(0,this.l-Va*(arguments.length?n:1)))},Za.rgb=function(){return st(this.h,this.c,this.l).rgb()},ta.lab=ft;var Va=18,Xa=.95047,$a=1,Ba=1.08883,Wa=ft.prototype=new ot;Wa.brighter=function(n){return new ft(Math.min(100,this.l+Va*(arguments.length?n:1)),this.a,this.b)},Wa.darker=function(n){return new ft(Math.max(0,this.l-Va*(arguments.length?n:1)),this.a,this.b)},Wa.rgb=function(){return ht(this.l,this.a,this.b)},ta.rgb=mt;var Ja=mt.prototype=new ot;Ja.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new mt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mt(u,u,u)},Ja.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mt(n*this.r,n*this.g,n*this.b)},Ja.hsl=function(){return _t(this.r,this.g,this.b)},Ja.toString=function(){return"#"+xt(this.r)+xt(this.g)+xt(this.b)};var Ga=ta.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Ga.forEach(function(n,t){Ga.set(n,yt(t))}),ta.functor=Et,ta.xhr=At(y),ta.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=Nt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=l)return o;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++<l;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}s=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++s):10===r&&(u=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;l>s;){var r=n.charCodeAt(s++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++a);else if(r!==c)continue;return n.slice(t,s-a)}return n.slice(t)}for(var r,u,i={},o={},a=[],l=n.length,s=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,f++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new m,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},ta.csv=ta.dsv(",","text/csv"),ta.tsv=ta.dsv(" ","text/tab-separated-values");var Ka,Qa,nc,tc,ec,rc=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ta.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Qa?Qa.n=i:Ka=i,Qa=i,nc||(tc=clearTimeout(tc),nc=1,rc(qt))},ta.timer.flush=function(){Lt(),Tt()},ta.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var uc=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Dt);ta.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=ta.round(n,Rt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),uc[8+e/3]};var ic=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,oc=ta.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ta.round(n,Rt(n,t))).toFixed(Math.max(0,Math.min(20,Rt(n*(1+1e-15),t))))}}),ac=ta.time={},cc=Date;jt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){lc.setUTCDate.apply(this._,arguments)},setDay:function(){lc.setUTCDay.apply(this._,arguments)},setFullYear:function(){lc.setUTCFullYear.apply(this._,arguments)},setHours:function(){lc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){lc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){lc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){lc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){lc.setUTCSeconds.apply(this._,arguments)},setTime:function(){lc.setTime.apply(this._,arguments)}};var lc=Date.prototype;ac.year=Ft(function(n){return n=ac.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ac.years=ac.year.range,ac.years.utc=ac.year.utc.range,ac.day=Ft(function(n){var t=new cc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ac.days=ac.day.range,ac.days.utc=ac.day.utc.range,ac.dayOfYear=function(n){var t=ac.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ac[n]=Ft(function(n){return(n=ac.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ac[n+"s"]=e.range,ac[n+"s"].utc=e.utc.range,ac[n+"OfYear"]=function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)}}),ac.week=ac.sunday,ac.weeks=ac.sunday.range,ac.weeks.utc=ac.sunday.utc.range,ac.weekOfYear=ac.sundayOfYear;var sc={"-":"",_:" ",0:"0"},fc=/^\s*\d+/,hc=/^%/;ta.locale=function(n){return{numberFormat:Pt(n),timeFormat:Ot(n)}};var gc=ta.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ta.format=gc.numberFormat,ta.geo={},ce.prototype={s:0,t:0,add:function(n){le(n,this.t,pc),le(pc.s,this.s,this),this.s?this.t+=pc.t:this.s=pc.t
+},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var pc=new ce;ta.geo.stream=function(n,t){n&&vc.hasOwnProperty(n.type)?vc[n.type](n,t):se(n,t)};var vc={Feature:function(n,t){se(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)se(e[r].geometry,t)}},dc={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){fe(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)fe(e[r],t,0)},Polygon:function(n,t){he(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)he(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)se(e[r],t)}};ta.geo.area=function(n){return mc=0,ta.geo.stream(n,Mc),mc};var mc,yc=new ce,Mc={sphere:function(){mc+=4*qa},point:b,lineStart:b,lineEnd:b,polygonStart:function(){yc.reset(),Mc.lineStart=ge},polygonEnd:function(){var n=2*yc;mc+=0>n?4*qa+n:n,Mc.lineStart=Mc.lineEnd=Mc.point=b}};ta.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=pe([t*Da,e*Da]);if(m){var u=de(m,r),i=[u[1],-u[0],0],o=de(i,u);Me(o),o=xe(o);var c=t-p,l=c>0?1:-1,v=o[0]*Pa*l,d=ga(c)>180;if(d^(v>l*p&&l*t>v)){var y=o[1]*Pa;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>l*p&&l*t>v)){var y=-o[1]*Pa;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ga(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Mc.point(n,e),t(n,e)}function i(){Mc.lineStart()}function o(){u(v,d),Mc.lineEnd(),ga(y)>Ca&&(s=-(h=180)),x[0]=s,x[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var s,f,h,g,p,v,d,m,y,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=u,b.lineStart=i,b.lineEnd=o,y=0,Mc.polygonStart()},polygonEnd:function(){Mc.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>yc?(s=-(h=180),f=-(g=90)):y>Ca?g=90:-Ca>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],ta.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var e,r=1,u=M[0],i=[u];t>r;++r)e=M[r],l(e[0],u)||l(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,s=e[0],h=u[1])}return M=x=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),ta.geo.centroid=function(n){xc=bc=_c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,qc);var t=Nc,e=Cc,r=zc,u=t*t+e*e+r*r;return za>u&&(t=kc,e=Ec,r=Ac,Ca>bc&&(t=_c,e=wc,r=Sc),u=t*t+e*e+r*r,za>u)?[0/0,0/0]:[Math.atan2(e,t)*Pa,tt(r/Math.sqrt(u))*Pa]};var xc,bc,_c,wc,Sc,kc,Ec,Ac,Nc,Cc,zc,qc={sphere:b,point:_e,lineStart:Se,lineEnd:ke,polygonStart:function(){qc.lineStart=Ee},polygonEnd:function(){qc.lineStart=Se}},Lc=Le(Ne,Pe,je,[-qa,-qa/2]),Tc=1e9;ta.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ie(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ta.geo.conicEqualArea=function(){return Ye(Ze)}).raw=Ze,ta.geo.albers=function(){return ta.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ta.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=ta.geo.albers(),o=ta.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ta.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var l=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=o.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Ca,f+.12*l+Ca],[s-.214*l-Ca,f+.234*l-Ca]]).stream(c).point,u=a.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Ca,f+.166*l+Ca],[s-.115*l-Ca,f+.234*l-Ca]]).stream(c).point,n},n.scale(1070)};var Rc,Dc,Pc,Uc,jc,Fc,Hc={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Dc=0,Hc.lineStart=Ve},polygonEnd:function(){Hc.lineStart=Hc.lineEnd=Hc.point=b,Rc+=ga(Dc/2)}},Oc={point:Xe,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Ic={point:We,lineStart:Je,lineEnd:Ge,polygonStart:function(){Ic.lineStart=Ke},polygonEnd:function(){Ic.point=We,Ic.lineStart=Je,Ic.lineEnd=Ge}};ta.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),ta.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Rc=0,ta.geo.stream(n,u(Hc)),Rc},n.centroid=function(n){return _c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,u(Ic)),zc?[Nc/zc,Cc/zc]:Ac?[kc/Ac,Ec/Ac]:Sc?[_c/Sc,wc/Sc]:[0/0,0/0]},n.bounds=function(n){return jc=Fc=-(Pc=Uc=1/0),ta.geo.stream(n,u(Oc)),[[Pc,Uc],[jc,Fc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||tr(n):y,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new $e:new Qe(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(ta.geo.albersUsa()).context(null)},ta.geo.transform=function(n){return{stream:function(t){var e=new er(t);for(var r in n)e[r]=n[r];return e}}},er.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ta.geo.projection=ur,ta.geo.projectionMutator=ir,(ta.geo.equirectangular=function(){return ur(ar)}).raw=ar.invert=ar,ta.geo.rotation=function(n){function t(t){return t=n(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t}return n=lr(n[0]%360*Da,n[1]*Da,n.length>2?n[2]*Da:0),t.invert=function(t){return t=n.invert(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t},t},cr.invert=ar,ta.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=lr(-n[0]*Da,-n[1]*Da,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Pa,n[1]*=Pa}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=gr((t=+r)*Da,u*Da),n):t},n.precision=function(r){return arguments.length?(e=gr(t*Da,(u=+r)*Da),n):u},n.angle(90)},ta.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Da,u=n[1]*Da,i=t[1]*Da,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),l=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=l*s-c*f*a)*e),c*s+l*f*a)},ta.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ta.range(Math.ceil(i/d)*d,u,d).map(h).concat(ta.range(Math.ceil(l/m)*m,c,m).map(g)).concat(ta.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ga(n%d)>Ca}).map(s)).concat(ta.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ga(n%m)>Ca}).map(f))}var e,r,u,i,o,a,c,l,s,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],l=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[i,l],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,s=vr(a,o,90),f=dr(r,e,y),h=vr(l,c,90),g=dr(i,u,y),n):y},n.majorExtent([[-180,-90+Ca],[180,90-Ca]]).minorExtent([[-180,-80-Ca],[180,80+Ca]])},ta.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=mr,u=yr;return n.distance=function(){return ta.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},ta.geo.interpolate=function(n,t){return Mr(n[0]*Da,n[1]*Da,t[0]*Da,t[1]*Da)},ta.geo.length=function(n){return Yc=0,ta.geo.stream(n,Zc),Yc};var Yc,Zc={sphere:b,point:b,lineStart:xr,lineEnd:b,polygonStart:b,polygonEnd:b},Vc=br(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ta.geo.azimuthalEqualArea=function(){return ur(Vc)}).raw=Vc;var Xc=br(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},y);(ta.geo.azimuthalEquidistant=function(){return ur(Xc)}).raw=Xc,(ta.geo.conicConformal=function(){return Ye(_r)}).raw=_r,(ta.geo.conicEquidistant=function(){return Ye(wr)}).raw=wr;var $c=br(function(n){return 1/n},Math.atan);(ta.geo.gnomonic=function(){return ur($c)}).raw=$c,Sr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ra]},(ta.geo.mercator=function(){return kr(Sr)}).raw=Sr;var Bc=br(function(){return 1},Math.asin);(ta.geo.orthographic=function(){return ur(Bc)}).raw=Bc;var Wc=br(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ta.geo.stereographic=function(){return ur(Wc)}).raw=Wc,Er.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ra]},(ta.geo.transverseMercator=function(){var n=kr(Er),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Er,ta.geom={},ta.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=Et(e),i=Et(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(zr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var l=Cr(a),s=Cr(c),f=s[0]===l[0],h=s[s.length-1]===l[l.length-1],g=[];for(t=l.length-1;t>=0;--t)g.push(n[a[l[t]][2]]);for(t=+f;t<s.length-h;++t)g.push(n[a[s[t]][2]]);return g}var e=Ar,r=Nr;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},ta.geom.polygon=function(n){return ya(n,Jc),n};var Jc=ta.geom.polygon.prototype=[];Jc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Jc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Jc.clip=function(n){for(var t,e,r,u,i,o,a=Tr(n),c=-1,l=this.length-Tr(this),s=this[l-1];++c<l;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],qr(o,s,u)?(qr(i,s,u)||n.push(Lr(i,o,s,u)),n.push(o)):qr(i,s,u)&&n.push(Lr(i,o,s,u)),i=o;a&&n.push(n[0]),s=u}return n};var Gc,Kc,Qc,nl,tl,el=[],rl=[];Or.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Yr),t.length},Qr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},nu.prototype={insert:function(n,t){var e,r,u;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=uu(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(eu(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ru(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(ru(this,e),n=e,e=n.U),e.C=!1,r.C=!0,eu(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,u=n.U,i=n.L,o=n.R;if(e=i?o?uu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,eu(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ru(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,eu(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,ru(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,eu(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,ru(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},ta.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return iu(e(n),a).cells.forEach(function(e,a){var c=e.edges,l=e.site,s=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):l.x>=r&&l.x<=i&&l.y>=u&&l.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];s.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/Ca)*Ca,y:Math.round(o(n,t)/Ca)*Ca,i:t}})}var r=Ar,u=Nr,i=r,o=u,a=ul;return n?t(n):(t.links=function(n){return iu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return iu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Yr),c=-1,l=a.length,s=a[l-1].edge,f=s.l===o?s.r:s.l;++c<l;)u=s,i=f,s=a[c].edge,f=s.l===o?s.r:s.l,r<i.i&&r<f.i&&au(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=Et(r=n),t):r},t.y=function(n){return arguments.length?(o=Et(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?ul:n,t):a===ul?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===ul?null:a&&a[1]},t)};var ul=[[-1e6,-1e6],[1e6,1e6]];ta.geom.delaunay=function(n){return ta.geom.voronoi().triangles(n)},ta.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,s=n.y;if(null!=c)if(ga(c-e)+ga(s-r)<.01)l(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,l(n,f,c,s,u,i,o,a),l(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else l(n,t,e,r,u,i,o,a)}function l(n,t,e,r,u,o,a,c){var l=.5*(u+a),s=.5*(o+c),f=e>=l,h=r>=s,g=h<<1|f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=su()),f?u=l:a=l,h?o=s:c=s,i(n,t,e,r,u,o,a,c)}var s,f,h,g,p,v,d,m,y,M=Et(a),x=Et(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)s=n[g],s.x<v&&(v=s.x),s.y<d&&(d=s.y),s.x>m&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);v>b&&(v=b),d>_&&(d=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=su();if(k.add=function(n){i(k,n,+M(n,++g),+x(n,g),v,d,m,y)},k.visit=function(n){fu(n,k,v,d,m,y)},k.find=function(n){return hu(k,n[0],n[1],v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=s=null,k}var o,a=Ar,c=Nr;return(o=arguments.length)?(a=cu,c=lu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},ta.interpolateRgb=gu,ta.interpolateObject=pu,ta.interpolateNumber=vu,ta.interpolateString=du;var il=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ol=new RegExp(il.source,"g");ta.interpolate=mu,ta.interpolators=[function(n,t){var e=typeof t;return("string"===e?Ga.has(t)||/^(#|rgb\(|hsl\()/.test(t)?gu:du:t instanceof ot?gu:Array.isArray(t)?yu:"object"===e&&isNaN(t)?pu:vu)(n,t)}],ta.interpolateArray=yu;var al=function(){return y},cl=ta.map({linear:al,poly:ku,quad:function(){return _u},cubic:function(){return wu},sin:function(){return Eu},exp:function(){return Au},circle:function(){return Nu},elastic:Cu,back:zu,bounce:function(){return qu}}),ll=ta.map({"in":y,out:xu,"in-out":bu,"out-in":function(n){return bu(xu(n))}});ta.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=cl.get(e)||al,r=ll.get(r)||y,Mu(r(e.apply(null,ea.call(arguments,1))))},ta.interpolateHcl=Lu,ta.interpolateHsl=Tu,ta.interpolateLab=Ru,ta.interpolateRound=Du,ta.transform=function(n){var t=ua.createElementNS(ta.ns.prefix.svg,"g");return(ta.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Pu(e?e.matrix:sl)})(n)},Pu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var sl={a:1,b:0,c:0,d:1,e:0,f:0};ta.interpolateTransform=Hu,ta.layout={},ta.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Yu(n[e]));return t}},ta.layout.chord=function(){function n(){var n,l,f,h,g,p={},v=[],d=ta.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(l=0,g=-1;++g<i;)l+=u[h][g];v.push(l),m.push(ta.range(i)),n+=l}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(La-s*i)/n,l=0,h=-1;++h<i;){for(f=l,g=-1;++g<i;){var y=d[h],M=m[y][g],x=u[y][M],b=l,_=l+=x*n;p[y+"-"+M]={index:y,subindex:M,startAngle:b,endAngle:_,value:x}}r[y]={index:y,startAngle:f,endAngle:l,value:(l-f)/n},l+=s}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,l={},s=0;return l.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,l):u},l.padding=function(n){return arguments.length?(s=n,e=r=null,l):s},l.sortGroups=function(n){return arguments.length?(o=n,e=r=null,l):o},l.sortSubgroups=function(n){return arguments.length?(a=n,e=null,l):a},l.sortChords=function(n){return arguments.length?(c=n,e&&t(),l):c},l.chords=function(){return e||n(),e},l.groups=function(){return r||n(),r},l},ta.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var l=t.charge/c;n.px-=i*l,n.py-=o*l}return!0}if(t.point&&c&&p>c){var l=t.pointCharge/c;n.px-=i*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=ta.event.x,n.py=ta.event.y,a.resume()}var e,r,u,i,o,a={},c=ta.dispatch("start","tick","end"),l=[1,1],s=.9,f=fl,h=hl,g=-30,p=gl,v=.1,d=.64,m=[],M=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,y,x,b=m.length,_=M.length;for(e=0;_>e;++e)a=M[e],f=a.source,h=a.target,y=h.x-f.x,x=h.y-f.y,(p=y*y+x*x)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,y*=p,x*=p,h.x-=y*(d=f.weight/(h.weight+f.weight)),h.y-=x*d,f.x+=y*(d=1-d),f.y+=x*d);if((d=r*v)&&(y=l[0]/2,x=l[1]/2,e=-1,d))for(;++e<b;)a=m[e],a.x+=(y-a.x)*d,a.y+=(x-a.y)*d;if(g)for(Ju(t=ta.geom.quadtree(m),r,o),e=-1;++e<b;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<b;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*s,a.y-=(a.py-(a.py=a.y))*s);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(M=n,a):M},a.size=function(n){return arguments.length?(l=n,a):l},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(s=+n,a):s},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),ta.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=M[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,l=o.length;++a<l;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,s=M.length,p=l[0],v=l[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;s>t;++t)r=M[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;s>t;++t)u[t]=+f.call(this,M[t],t);else for(t=0;s>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;s>t;++t)i[t]=+h.call(this,M[t],t);else for(t=0;s>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=ta.behavior.drag().origin(y).on("dragstart.force",Xu).on("drag.force",t).on("dragend.force",$u)),arguments.length?void this.on("mouseover.force",Bu).on("mouseout.force",Wu).call(e):e},ta.rebind(a,c,"on")};var fl=20,hl=1,gl=1/0;ta.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(l=e.call(n,i,i.depth))&&(c=l.length)){for(var c,l,s;--c>=0;)o.push(s=l[c]),s.parent=i,s.depth=i.depth+1;r&&(i.value=0),i.children=l}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Qu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=ei,e=ni,r=ti;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(Ku(t,function(n){n.children&&(n.value=0)}),Qu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ta.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,l=-1;for(r=t.value?r/t.value:0;++l<o;)n(a=i[l],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=ta.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Gu(e,r)},ta.layout.pie=function(){function n(o){var a,c=o.length,l=o.map(function(e,r){return+t.call(n,e,r)}),s=+("function"==typeof r?r.apply(this,arguments):r),f=("function"==typeof u?u.apply(this,arguments):u)-s,h=Math.min(Math.abs(f)/c,+("function"==typeof i?i.apply(this,arguments):i)),g=h*(0>f?-1:1),p=(f-c*g)/ta.sum(l),v=ta.range(c),d=[];return null!=e&&v.sort(e===pl?function(n,t){return l[t]-l[n]}:function(n,t){return e(o[n],o[t])}),v.forEach(function(n){d[n]={data:o[n],value:a=l[n],startAngle:s,endAngle:s+=a*p+g,padAngle:h}}),d}var t=Number,e=pl,r=0,u=La,i=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n.padAngle=function(t){return arguments.length?(i=t,n):i},n};var pl={};ta.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,s,c);l=ta.permute(l,f),s=ta.permute(s,f);var h,g,p,v,d=r.call(n,s,c),m=l[0].length;for(p=0;m>p;++p)for(u.call(n,l[0][p],v=d[p],s[0][p][1]),g=1;h>g;++g)u.call(n,l[g][p],v+=s[g-1][p][1],s[g][p][1]);return a}var t=y,e=ai,r=ci,u=oi,i=ui,o=ii;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:vl.get(t)||ai,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:dl.get(t)||ci,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var vl=ta.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(li),i=n.map(si),o=ta.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return ta.range(n.length).reverse()},"default":ai}),dl=ta.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ci});ta.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=l[i],a>=s[0]&&a<=s[1]&&(o=c[ta.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=pi,u=hi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=Et(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return gi(n,t)}:Et(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ta.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Qu(a,function(n){n.r=+s(n.value)}),Qu(a,Mi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Qu(a,function(n){n.r+=f}),Qu(a,Mi),Qu(a,function(n){n.r-=f})}return _i(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=ta.layout.hierarchy().sort(vi),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Gu(n,e)},ta.layout.tree=function(){function n(n,u){var s=o.call(this,n,u),f=s[0],h=t(f);if(Qu(h,e),h.parent.m=-h.z,Ku(h,r),l)Ku(f,i);else{var g=f,p=f,v=f;Ku(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);Ku(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return s}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Ni(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],l=u.m,s=i.m,f=o.m,h=c.m;o=Ei(o),u=ki(u),o&&u;)c=ki(c),i=Ei(i),i.a=n,r=o.z+f-u.z-l+a(o._,u._),r>0&&(Ai(Ci(o,n,e),n,r),l+=r,s+=r),f+=o.m,l+=u.m,h+=c.m,s+=i.m;o&&!Ei(i)&&(i.t=o,i.m+=f-s),u&&!ki(c)&&(c.t=u,c.m+=l-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=ta.layout.hierarchy().sort(null).value(null),a=Si,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?i:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:i,n):l?c:null},Gu(n,o)},ta.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Qu(c,function(n){var t=n.children;t&&t.length?(n.x=qi(t),n.y=zi(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Li(c),f=Ti(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Qu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=ta.layout.hierarchy().sort(null).value(null),e=Si,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Gu(n,t)},ta.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,v="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,"squarify"!==g||(a=r(s,v))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,v,l,!1),v=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,v,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++i<o;)u=n[i],u.x=a,u.y=l,u.dy=s,a+=u.dx=Math.min(e.x+e.dx-a,s?c(u.area/s):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=s,e.dy-=s}else{for((r||s>e.dx)&&(s=e.dx);++i<o;)u=n[i],u.x=a,u.y=l,u.dx=s,l+=u.dy=Math.min(e.y+e.dy-l,s?c(u.area/s):0);u.z=!1,u.dy+=e.y+e.dy-l,e.x+=s,e.dx-=s}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=l[0],i.dy=l[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=ta.layout.hierarchy(),c=Math.round,l=[1,1],s=null,f=Ri,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));
+return i.size=function(n){return arguments.length?(l=n,i):l},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ri(t):Di(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Di(t,n)}if(!arguments.length)return s;var r;return f=null==(s=n)?Ri:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Gu(i,a)},ta.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=ta.random.normal.apply(ta,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ta.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ta.scale={};var ml={floor:y,ceil:y};ta.scale.linear=function(){return Ii([0,1],[0,1],mu,!1)};var yl={s:1,g:1,p:1,r:1,e:1};ta.scale.log=function(){return Ji(ta.scale.linear().domain([0,1]),10,!0,[1,10])};var Ml=ta.format(".0e"),xl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ta.scale.pow=function(){return Gi(ta.scale.linear(),1,[0,1])},ta.scale.sqrt=function(){return ta.scale.pow().exponent(.5)},ta.scale.ordinal=function(){return Qi([],{t:"range",a:[[]]})},ta.scale.category10=function(){return ta.scale.ordinal().range(bl)},ta.scale.category20=function(){return ta.scale.ordinal().range(_l)},ta.scale.category20b=function(){return ta.scale.ordinal().range(wl)},ta.scale.category20c=function(){return ta.scale.ordinal().range(Sl)};var bl=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(Mt),_l=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(Mt),wl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(Mt),Sl=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(Mt);ta.scale.quantile=function(){return no([],[])},ta.scale.quantize=function(){return to(0,1,[0,1])},ta.scale.threshold=function(){return eo([.5],[0,1])},ta.scale.identity=function(){return ro([0,1])},ta.svg={},ta.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),s=o.apply(this,arguments)-Ra,f=a.apply(this,arguments)-Ra,h=Math.abs(f-s),g=s>f?0:1;if(n>l&&(p=l,l=n,n=p),h>=Ta)return t(l,g)+(n?t(n,1-g):"")+"Z";var p,v,d,m,y,M,x,b,_,w,S,k,E=0,A=0,N=[];if((m=(+c.apply(this,arguments)||0)/2)&&(d=i===kl?Math.sqrt(n*n+l*l):+i.apply(this,arguments),g||(A*=-1),l&&(A=tt(d/l*Math.sin(m))),n&&(E=tt(d/n*Math.sin(m)))),l){y=l*Math.cos(s+A),M=l*Math.sin(s+A),x=l*Math.cos(f-A),b=l*Math.sin(f-A);var C=Math.abs(f-s-2*A)<=qa?0:1;if(A&&so(y,M,x,b)===g^C){var z=(s+f)/2;y=l*Math.cos(z),M=l*Math.sin(z),x=b=null}}else y=M=0;if(n){_=n*Math.cos(f-E),w=n*Math.sin(f-E),S=n*Math.cos(s+E),k=n*Math.sin(s+E);var q=Math.abs(s-f+2*E)<=qa?0:1;if(E&&so(_,w,S,k)===1-g^q){var L=(s+f)/2;_=n*Math.cos(L),w=n*Math.sin(L),S=k=null}}else _=w=0;if((p=Math.min(Math.abs(l-n)/2,+u.apply(this,arguments)))>.001){v=l>n^g?0:1;var T=null==S?[_,w]:null==x?[y,M]:Lr([y,M],[S,k],[x,b],[_,w]),R=y-T[0],D=M-T[1],P=x-T[0],U=b-T[1],j=1/Math.sin(Math.acos((R*P+D*U)/(Math.sqrt(R*R+D*D)*Math.sqrt(P*P+U*U)))/2),F=Math.sqrt(T[0]*T[0]+T[1]*T[1]);if(null!=x){var H=Math.min(p,(l-F)/(j+1)),O=fo(null==S?[_,w]:[S,k],[y,M],l,H,g),I=fo([x,b],[_,w],l,H,g);p===H?N.push("M",O[0],"A",H,",",H," 0 0,",v," ",O[1],"A",l,",",l," 0 ",1-g^so(O[1][0],O[1][1],I[1][0],I[1][1]),",",g," ",I[1],"A",H,",",H," 0 0,",v," ",I[0]):N.push("M",O[0],"A",H,",",H," 0 1,",v," ",I[0])}else N.push("M",y,",",M);if(null!=S){var Y=Math.min(p,(n-F)/(j-1)),Z=fo([y,M],[S,k],n,-Y,g),V=fo([_,w],null==x?[y,M]:[x,b],n,-Y,g);p===Y?N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",V[1],"A",n,",",n," 0 ",g^so(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-g," ",Z[1],"A",Y,",",Y," 0 0,",v," ",Z[0]):N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",Z[0])}else N.push("L",_,",",w)}else N.push("M",y,",",M),null!=x&&N.push("A",l,",",l," 0 ",C,",",g," ",x,",",b),N.push("L",_,",",w),null!=S&&N.push("A",n,",",n," 0 ",q,",",1-g," ",S,",",k);return N.push("Z"),N.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=io,r=oo,u=uo,i=kl,o=ao,a=co,c=lo;return n.innerRadius=function(t){return arguments.length?(e=Et(t),n):e},n.outerRadius=function(t){return arguments.length?(r=Et(t),n):r},n.cornerRadius=function(t){return arguments.length?(u=Et(t),n):u},n.padRadius=function(t){return arguments.length?(i=t==kl?kl:Et(t),n):i},n.startAngle=function(t){return arguments.length?(o=Et(t),n):o},n.endAngle=function(t){return arguments.length?(a=Et(t),n):a},n.padAngle=function(t){return arguments.length?(c=Et(t),n):c},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Ra;return[Math.cos(t)*n,Math.sin(t)*n]},n};var kl="auto";ta.svg.line=function(){return ho(y)};var El=ta.map({linear:go,"linear-closed":po,step:vo,"step-before":mo,"step-after":yo,basis:So,"basis-open":ko,"basis-closed":Eo,bundle:Ao,cardinal:bo,"cardinal-open":Mo,"cardinal-closed":xo,monotone:To});El.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Al=[0,2/3,1/3,0],Nl=[0,1/3,2/3,0],Cl=[0,1/6,2/3,1/6];ta.svg.line.radial=function(){var n=ho(Ro);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},mo.reverse=yo,yo.reverse=mo,ta.svg.area=function(){return Do(y)},ta.svg.area.radial=function(){var n=Do(Ro);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ta.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)-Ra,s=l.call(n,u,r)-Ra;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>qa)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=mr,o=yr,a=Po,c=ao,l=co;return n.radius=function(t){return arguments.length?(a=Et(t),n):a},n.source=function(t){return arguments.length?(i=Et(t),n):i},n.target=function(t){return arguments.length?(o=Et(t),n):o},n.startAngle=function(t){return arguments.length?(c=Et(t),n):c},n.endAngle=function(t){return arguments.length?(l=Et(t),n):l},n},ta.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=mr,e=yr,r=Uo;return n.source=function(e){return arguments.length?(t=Et(e),n):t},n.target=function(t){return arguments.length?(e=Et(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ta.svg.diagonal.radial=function(){var n=ta.svg.diagonal(),t=Uo,e=n.projection;return n.projection=function(n){return arguments.length?e(jo(t=n)):t},n},ta.svg.symbol=function(){function n(n,r){return(zl.get(t.call(this,n,r))||Oo)(e.call(this,n,r))}var t=Ho,e=Fo;return n.type=function(e){return arguments.length?(t=Et(e),n):t},n.size=function(t){return arguments.length?(e=Et(t),n):e},n};var zl=ta.map({circle:Oo,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ll)),e=t*Ll;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ta.svg.symbolTypes=zl.keys();var ql=Math.sqrt(3),Ll=Math.tan(30*Da);_a.transition=function(n){for(var t,e,r=Tl||++Ul,u=Xo(n),i=[],o=Rl||{time:Date.now(),ease:Su,delay:0,duration:250},a=-1,c=this.length;++a<c;){i.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(e=l[s])&&$o(e,s,u,r,o),t.push(e)}return Yo(i,u,r)},_a.interrupt=function(n){return this.each(null==n?Dl:Io(Xo(n)))};var Tl,Rl,Dl=Io(Xo()),Pl=[],Ul=0;Pl.call=_a.call,Pl.empty=_a.empty,Pl.node=_a.node,Pl.size=_a.size,ta.transition=function(n,t){return n&&n.transition?Tl?n.transition(t):n:ta.selection().transition(n)},ta.transition.prototype=Pl,Pl.select=function(n){var t,e,r,u=this.id,i=this.namespace,o=[];n=N(n);for(var a=-1,c=this.length;++a<c;){o.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(r=l[s])&&(e=n.call(r,r.__data__,s,a))?("__data__"in r&&(e.__data__=r.__data__),$o(e,s,i,u,r[i][u]),t.push(e)):t.push(null)}return Yo(o,i,u)},Pl.selectAll=function(n){var t,e,r,u,i,o=this.id,a=this.namespace,c=[];n=C(n);for(var l=-1,s=this.length;++l<s;)for(var f=this[l],h=-1,g=f.length;++h<g;)if(r=f[h]){i=r[a][o],e=n.call(r,r.__data__,h,l),c.push(t=[]);for(var p=-1,v=e.length;++p<v;)(u=e[p])&&$o(u,p,a,o,i),t.push(u)}return Yo(c,a,o)},Pl.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Yo(u,this.namespace,this.id)},Pl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(u){u[r][e].tween.set(n,t)})},Pl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Hu:mu,a=ta.ns.qualify(n);return Zo(this,"attr."+n,t,a.local?i:u)},Pl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=ta.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Pl.style=function(n,e,r){function u(){this.style.removeProperty(n)}function i(e){return null==e?u:(e+="",function(){var u,i=t(this).getComputedStyle(this,null).getPropertyValue(n);return i!==e&&(u=mu(i,e),function(t){this.style.setProperty(n,u(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Zo(this,"style."+n,e,i)},Pl.styleTween=function(n,e,r){function u(u,i){var o=e.call(this,u,i,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,u)},Pl.text=function(n){return Zo(this,"text",n,Vo)},Pl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Pl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ta.ease.apply(ta,arguments)),Y(this,function(r){r[e][t].ease=n}))},Pl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,u,i){r[e][t].delay=+n.call(r,r.__data__,u,i)}:(n=+n,function(r){r[e][t].delay=n}))},Pl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,u,i){r[e][t].duration=Math.max(1,n.call(r,r.__data__,u,i))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Pl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var u=Rl,i=Tl;try{Tl=e,Y(this,function(t,u,i){Rl=t[r][e],n.call(t,t.__data__,u,i)})}finally{Rl=u,Tl=i}}else Y(this,function(u){var i=u[r][e];(i.event||(i.event=ta.dispatch("start","end","interrupt"))).on(n,t)});return this},Pl.transition=function(){for(var n,t,e,r,u=this.id,i=++Ul,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],s=0,f=t.length;f>s;s++)(e=t[s])&&(r=e[o][u],$o(e,s,o,i,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Yo(a,o,i)},ta.svg.axis=function(){function n(n){n.each(function(){var n,l=ta.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):y:t,p=l.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Ca),d=ta.transition(p.exit()).style("opacity",Ca).remove(),m=ta.transition(p.order()).style("opacity",1),M=Math.max(u,0)+o,x=Ui(f),b=l.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ta.transition(b));v.append("line"),v.append("text");var w,S,k,E,A=v.select("line"),N=m.select("line"),C=p.select("text").text(g),z=v.select("text"),q=m.select("text"),L="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=Bo,w="x",k="y",S="x2",E="y2",C.attr("dy",0>L?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+L*i+"V0H"+x[1]+"V"+L*i)):(n=Wo,w="y",k="x",S="y2",E="x2",C.attr("dy",".32em").style("text-anchor",0>L?"end":"start"),_.attr("d","M"+L*i+","+x[0]+"H0V"+x[1]+"H"+L*i)),A.attr(E,L*u),z.attr(k,L*M),N.attr(S,0).attr(E,L*u),q.attr(w,0).attr(k,L*M),f.rangeBand){var T=f,R=T.rangeBand()/2;s=f=function(n){return T(n)+R}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=ta.scale.linear(),r=jl,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Fl?t+"":jl,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var jl="bottom",Fl={top:1,right:1,bottom:1,left:1};ta.svg.brush=function(){function n(t){t.each(function(){var t=ta.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",i).on("touchstart.brush",i),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,y);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Hl[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var c,f=ta.transition(t),h=ta.transition(o);l&&(c=Ui(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),r(f)),s&&(c=Ui(s),h.attr("y",c[0]).attr("height",c[1]-c[0]),u(f)),e(f)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",f[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function u(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function i(){function i(){32==ta.event.keyCode&&(C||(M=null,q[0]-=f[1],q[1]-=h[1],C=2),S())}function v(){32==ta.event.keyCode&&2==C&&(q[0]+=f[1],q[1]+=h[1],C=0,S())}function d(){var n=ta.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ta.event.altKey?(M||(M=[(f[0]+f[1])/2,(h[0]+h[1])/2]),q[0]=f[+(n[0]<M[0])],q[1]=h[+(n[1]<M[1])]):M=null),A&&m(n,l,0)&&(r(k),t=!0),N&&m(n,s,1)&&(u(k),t=!0),t&&(e(k),w({type:"brush",mode:C?"move":"resize"}))}function m(n,t,e){var r,u,i=Ui(t),c=i[0],l=i[1],s=q[e],v=e?h:f,d=v[1]-v[0];return C&&(c-=s,l-=d+s),r=(e?p:g)?Math.max(c,Math.min(l,n[e])):n[e],C?u=(r+=s)+d:(M&&(s=Math.max(c,Math.min(l,2*M[e]-r))),r>s?(u=r,r=s):u=s),v[0]!=r||v[1]!=u?(e?a=null:o=null,v[0]=r,v[1]=u,!0):void 0}function y(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ta.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ta.select(ta.event.target),w=c.of(b,arguments),k=ta.select(b),E=_.datum(),A=!/^(n|s)$/.test(E)&&l,N=!/^(e|w)$/.test(E)&&s,C=_.classed("extent"),z=W(b),q=ta.mouse(b),L=ta.select(t(b)).on("keydown.brush",i).on("keyup.brush",v);if(ta.event.changedTouches?L.on("touchmove.brush",d).on("touchend.brush",y):L.on("mousemove.brush",d).on("mouseup.brush",y),k.interrupt().selectAll("*").interrupt(),C)q[0]=f[0]-q[0],q[1]=h[0]-q[1];else if(E){var T=+/w$/.test(E),R=+/^n/.test(E);x=[f[1-T]-q[0],h[1-R]-q[1]],q[0]=f[T],q[1]=h[R]}else ta.event.altKey&&(M=q.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ta.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=E(n,"brushstart","brush","brushend"),l=null,s=null,f=[0,0],h=[0,0],g=!0,p=!0,v=Ol[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:f,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Tl?ta.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,f=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=yu(f,t.x),r=yu(h,t.y);return o=a=null,function(u){f=t.x=e(u),h=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(l=t,v=Ol[!l<<1|!s],n):l},n.y=function(t){return arguments.length?(s=t,v=Ol[!l<<1|!s],n):s},n.clamp=function(t){return arguments.length?(l&&s?(g=!!t[0],p=!!t[1]):l?g=!!t:s&&(p=!!t),n):l&&s?[g,p]:l?g:s?p:null},n.extent=function(t){var e,r,u,i,c;return arguments.length?(l&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),o=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(c=e,e=r,r=c),(e!=f[0]||r!=f[1])&&(f=[e,r])),s&&(u=t[0],i=t[1],l&&(u=u[1],i=i[1]),a=[u,i],s.invert&&(u=s(u),i=s(i)),u>i&&(c=u,u=i,i=c),(u!=h[0]||i!=h[1])&&(h=[u,i])),n):(l&&(o?(e=o[0],r=o[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(c=e,e=r,r=c))),s&&(a?(u=a[0],i=a[1]):(u=h[0],i=h[1],s.invert&&(u=s.invert(u),i=s.invert(i)),u>i&&(c=u,u=i,i=c))),l&&s?[[e,u],[r,i]]:l?[e,r]:s&&[u,i])},n.clear=function(){return n.empty()||(f=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&f[0]==f[1]||!!s&&h[0]==h[1]},ta.rebind(n,c,"on")};var Hl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ol=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Il=ac.format=gc.timeFormat,Yl=Il.utc,Zl=Yl("%Y-%m-%dT%H:%M:%S.%LZ");Il.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Jo:Zl,Jo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Jo.toString=Zl.toString,ac.second=Ft(function(n){return new cc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ac.seconds=ac.second.range,ac.seconds.utc=ac.second.utc.range,ac.minute=Ft(function(n){return new cc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ac.minutes=ac.minute.range,ac.minutes.utc=ac.minute.utc.range,ac.hour=Ft(function(n){var t=n.getTimezoneOffset()/60;return new cc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ac.hours=ac.hour.range,ac.hours.utc=ac.hour.utc.range,ac.month=Ft(function(n){return n=ac.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ac.months=ac.month.range,ac.months.utc=ac.month.utc.range;var Vl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Xl=[[ac.second,1],[ac.second,5],[ac.second,15],[ac.second,30],[ac.minute,1],[ac.minute,5],[ac.minute,15],[ac.minute,30],[ac.hour,1],[ac.hour,3],[ac.hour,6],[ac.hour,12],[ac.day,1],[ac.day,2],[ac.week,1],[ac.month,1],[ac.month,3],[ac.year,1]],$l=Il.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",Ne]]),Bl={range:function(n,t,e){return ta.range(Math.ceil(n/e)*e,+t,e).map(Ko)},floor:y,ceil:y};Xl.year=ac.year,ac.scale=function(){return Go(ta.scale.linear(),Xl,$l)};var Wl=Xl.map(function(n){return[n[0].utc,n[1]]}),Jl=Yl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",Ne]]);Wl.year=ac.year.utc,ac.scale.utc=function(){return Go(ta.scale.linear(),Wl,Jl)},ta.text=At(function(n){return n.responseText}),ta.json=function(n,t){return Nt(n,"application/json",Qo,t)},ta.html=function(n,t){return Nt(n,"text/html",na,t)},ta.xml=At(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(ta):"object"==typeof module&&module.exports&&(module.exports=ta),this.d3=ta}();
\ No newline at end of file
--- /dev/null
+/*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b=function(){if(a&&a.fn&&a.fn.select2&&a.fn.select2.amd)var b=a.fn.select2.amd;var b;return function(){if(!b||!b.requirejs){b?c=b:b={};var a,c,d;!function(b){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(n=n.slice(0,n.length-1),a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.concat(a),k=0;k<a.length;k+=1)if(m=a[k],"."===m)a.splice(k,1),k-=1;else if(".."===m){if(1===k&&(".."===a[2]||".."===a[0]))break;k>0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,c){return function(){return n.apply(b,v.call(arguments,0).concat([a,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(a){if(e(r,a)){var c=r[a];delete r[a],t[a]=!0,m.apply(b,c)}if(!e(q,a)&&!e(t,a))throw new Error("No "+a);return q[a]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(a,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||a,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;n<c.length;n+=1)if(m=o(c[n],f),k=m.f,"require"===k)u[n]=p.require(a);else if("exports"===k)u[n]=p.exports(a),s=!0;else if("module"===k)h=u[n]=p.module(a);else if(e(q,k)||e(r,k)||e(t,k))u[n]=j(k);else{if(!m.p)throw new Error(a+" missing "+k);m.p.load(m.n,g(f,!0),i(k),{}),u[n]=q[k]}l=d?d.apply(q[a],u):void 0,a&&(h&&h.exports!==b&&h.exports!==q[a]?q[a]=h.exports:l===b&&s||(q[a]=l))}else a&&(q[a]=d)},a=c=n=function(a,c,d,e,f){if("string"==typeof a)return p[a]?p[a](c):j(o(a,c).f);if(!a.splice){if(s=a,s.deps&&n(s.deps,s.callback),!c)return;c.splice?(a=c,c=d,d=null):a=b}return c=c||function(){},"function"==typeof d&&(d=e,e=f),e?m(b,a,c,d):setTimeout(function(){m(b,a,c,d)},4),n},n.config=function(a){return n(a)},a._defined=q,d=function(a,b,c){b.splice||(c=b,b=[]),e(q,a)||e(r,a)||(r[a]=[a,b,c])},d.amd={jQuery:!0}}(),b.requirejs=a,b.require=c,b.define=d}}(),b.define("almond",function(){}),b.define("jquery",[],function(){var b=a||$;return null==b&&console&&console.error&&console.error("Select2: An instance of jQuery or a jQuery-compatible library was not found. Make sure that you are including jQuery before Select2 on your web page."),b}),b.define("select2/utils",["jquery"],function(a){function b(a){var b=a.prototype,c=[];for(var d in b){var e=b[d];"function"==typeof e&&"constructor"!==d&&c.push(d)}return c}var c={};c.Extend=function(a,b){function c(){this.constructor=a}var d={}.hasOwnProperty;for(var e in b)d.call(b,e)&&(a[e]=b[e]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},c.Decorate=function(a,c){function d(){var b=Array.prototype.unshift,d=c.prototype.constructor.length,e=a.prototype.constructor;d>0&&(b.call(arguments,a.prototype.constructor),e=c.prototype.constructor),e.apply(this,arguments)}function e(){this.constructor=d}var f=b(c),g=b(a);c.displayName=a.displayName,d.prototype=new e;for(var h=0;h<g.length;h++){var i=g[h];d.prototype[i]=a.prototype[i]}for(var j=(function(a){var b=function(){};a in d.prototype&&(b=d.prototype[a]);var e=c.prototype[a];return function(){var a=Array.prototype.unshift;return a.call(arguments,b),e.apply(this,arguments)}}),k=0;k<f.length;k++){var l=f[k];d.prototype[l]=j(l)}return d};var d=function(){this.listeners={}};return d.prototype.on=function(a,b){this.listeners=this.listeners||{},a in this.listeners?this.listeners[a].push(b):this.listeners[a]=[b]},d.prototype.trigger=function(a){var b=Array.prototype.slice;this.listeners=this.listeners||{},a in this.listeners&&this.invoke(this.listeners[a],b.call(arguments,1)),"*"in this.listeners&&this.invoke(this.listeners["*"],arguments)},d.prototype.invoke=function(a,b){for(var c=0,d=a.length;d>c;c++)a[c].apply(this,b)},c.Observable=d,c.generateChars=function(a){for(var b="",c=0;a>c;c++){var d=Math.floor(36*Math.random());b+=d.toString(36)}return b},c.bind=function(a,b){return function(){a.apply(b,arguments)}},c._convertData=function(a){for(var b in a){var c=b.split("-"),d=a;if(1!==c.length){for(var e=0;e<c.length;e++){var f=c[e];f=f.substring(0,1).toLowerCase()+f.substring(1),f in d||(d[f]={}),e==c.length-1&&(d[f]=a[b]),d=d[f]}delete a[b]}}return a},c.hasScroll=function(b,c){var d=a(c),e=c.style.overflowX,f=c.style.overflowY;return e!==f||"hidden"!==f&&"visible"!==f?"scroll"===e||"scroll"===f?!0:d.innerHeight()<c.scrollHeight||d.innerWidth()<c.scrollWidth:!1},c.escapeMarkup=function(a){var b={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return"string"!=typeof a?a:String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})},c.appendMany=function(b,c){if("1.7"===a.fn.jquery.substr(0,3)){var d=a();a.map(c,function(a){d=d.add(a)}),c=d}b.append(c)},c}),b.define("select2/results",["jquery","./utils"],function(a,b){function c(a,b,d){this.$element=a,this.data=d,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<ul class="select2-results__options" role="tree"></ul>');return this.options.get("multiple")&&b.attr("aria-multiselectable","true"),this.$results=b,b},c.prototype.clear=function(){this.$results.empty()},c.prototype.displayMessage=function(b){var c=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var d=a('<li role="treeitem" class="select2-results__option"></li>'),e=this.options.get("translations").get(b.message);d.append(c(e(b.args))),this.$results.append(d)},c.prototype.append=function(a){this.hideLoading();var b=[];if(null==a.results||0===a.results.length)return void(0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"}));a.results=this.sort(a.results);for(var c=0;c<a.results.length;c++){var d=a.results[c],e=this.option(d);b.push(e)}this.$results.append(b)},c.prototype.position=function(a,b){var c=b.find(".select2-results");c.append(a)},c.prototype.sort=function(a){var b=this.options.get("sorter");return b(a)},c.prototype.setClasses=function(){var b=this;this.data.current(function(c){var d=a.map(c,function(a){return a.id.toString()}),e=b.$results.find(".select2-results__option[aria-selected]");e.each(function(){var b=a(this),c=a.data(this,"data"),e=""+c.id;null!=c.element&&c.element.selected||null==c.element&&a.inArray(e,d)>-1?b.attr("aria-selected","true"):b.attr("aria-selected","false")});var f=e.filter("[aria-selected=true]");f.length>0?f.first().trigger("mouseenter"):e.first().trigger("mouseenter")})},c.prototype.showLoading=function(a){this.hideLoading();var b=this.options.get("translations").get("searching"),c={disabled:!0,loading:!0,text:b(a)},d=this.option(c);d.className+=" loading-results",this.$results.prepend(d)},c.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},c.prototype.option=function(b){var c=document.createElement("li");c.className="select2-results__option";var d={role:"treeitem","aria-selected":"false"};b.disabled&&(delete d["aria-selected"],d["aria-disabled"]="true"),null==b.id&&delete d["aria-selected"],null!=b._resultId&&(c.id=b._resultId),b.title&&(c.title=b.title),b.children&&(d.role="group",d["aria-label"]=b.text,delete d["aria-selected"]);for(var e in d){var f=d[e];c.setAttribute(e,f)}if(b.children){var g=a(c),h=document.createElement("strong");h.className="select2-results__group";{a(h)}this.template(b,h);for(var i=[],j=0;j<b.children.length;j++){var k=b.children[j],l=this.option(k);i.push(l)}var m=a("<ul></ul>",{"class":"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b){var c=this,d=b.id+"-results";this.$results.attr("id",d),b.on("results:all",function(a){c.clear(),c.append(a.data),b.isOpen()&&c.setClasses()}),b.on("results:append",function(a){c.append(a.data),b.isOpen()&&c.setClasses()}),b.on("query",function(a){c.showLoading(a)}),b.on("select",function(){b.isOpen()&&c.setClasses()}),b.on("unselect",function(){b.isOpen()&&c.setClasses()}),b.on("open",function(){c.$results.attr("aria-expanded","true"),c.$results.attr("aria-hidden","false"),c.setClasses(),c.ensureHighlightVisible()}),b.on("close",function(){c.$results.attr("aria-expanded","false"),c.$results.attr("aria-hidden","true"),c.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=c.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=c.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?c.trigger("close"):c.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=c.getHighlightedResults(),b=c.$results.find("[aria-selected]"),d=b.index(a);if(0!==d){var e=d-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=c.$results.offset().top,h=f.offset().top,i=c.$results.scrollTop()+(h-g);0===e?c.$results.scrollTop(0):0>h-g&&c.$results.scrollTop(i)}}),b.on("results:next",function(){var a=c.getHighlightedResults(),b=c.$results.find("[aria-selected]"),d=b.index(a),e=d+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=c.$results.offset().top+c.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=c.$results.scrollTop()+h-g;0===e?c.$results.scrollTop(0):h>g&&c.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){c.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=c.$results.scrollTop(),d=c.$results.get(0).scrollHeight-c.$results.scrollTop()+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&d<=c.$results.height();e?(c.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(c.$results.scrollTop(c.$results.get(0).scrollHeight-c.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var d=a(this),e=d.data("data");return"true"===d.attr("aria-selected")?void(c.options.get("multiple")?c.trigger("unselect",{originalEvent:b,data:e}):c.trigger("close")):void c.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(){var b=a(this).data("data");c.getHighlightedResults().removeClass("select2-results__option--highlighted"),c.trigger("results:focus",{data:b,element:a(this)})})},c.prototype.getHighlightedResults=function(){var a=this.$results.find(".select2-results__option--highlighted");return a},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),2>=c?this.$results.scrollTop(0):(g>this.$results.outerHeight()||0>g)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){var a={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return a}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('<span class="select2-selection" role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-expanded="false"></span>');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a){var b=this,d=(a.id+"-container",a.id+"-results");this.container=a,this.$selection.on("focus",function(a){b.trigger("focus",a)}),this.$selection.on("blur",function(a){b.trigger("blur",a)}),this.$selection.on("keydown",function(a){b.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){b.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){b.update(a.data)}),a.on("open",function(){b.$selection.attr("aria-expanded","true"),b.$selection.attr("aria-owns",d),b._attachCloseHandler(a)}),a.on("close",function(){b.$selection.attr("aria-expanded","false"),b.$selection.removeAttr("aria-activedescendant"),b.$selection.removeAttr("aria-owns"),b.$selection.focus(),b._detachCloseHandler(a)}),a.on("enable",function(){b.$selection.attr("tabindex",b._tabindex)}),a.on("disable",function(){b.$selection.attr("tabindex","-1")})},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2"),e=a(".select2.select2-container--open");e.each(function(){var b=a(this);if(this!=d[0]){var c=b.data("element");c.select2("close")}})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){var c=b.find(".selection");c.append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c){function d(){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html('<span class="select2-selection__rendered"></span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span>'),a},d.prototype.bind=function(a){var b=this;d.__super__.bind.apply(this,arguments);var c=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",c),this.$selection.attr("aria-labelledby",c),this.$selection.on("mousedown",function(a){1===a.which&&b.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(){}),this.$selection.on("blur",function(){}),a.on("selection:update",function(a){b.update(a.data)})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a){var b=this.options.get("templateSelection"),c=this.options.get("escapeMarkup");return c(b(a))},d.prototype.selectionContainer=function(){return a("<span></span>")},d.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.display(b),d=this.$selection.find(".select2-selection__rendered");d.empty().append(c),d.prop("title",b.title||b.text)},d}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('<ul class="select2-selection__rendered"></ul>'),a},d.prototype.bind=function(){var b=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){b.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(c){var d=a(this),e=d.parent(),f=e.data("data");b.trigger("unselect",{originalEvent:c,data:f})})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a){var b=this.options.get("templateSelection"),c=this.options.get("escapeMarkup");return c(b(a))},d.prototype.selectionContainer=function(){var b=a('<li class="select2-selection__choice"><span class="select2-selection__choice__remove" role="presentation">×</span></li>');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d<a.length;d++){var e=a[d],f=this.display(e),g=this.selectionContainer();g.append(f),g.prop("title",e.title||e.text),g.data("data",e),b.push(g)}var h=this.$selection.find(".select2-selection__rendered");c.appendMany(h,b)}},d}),b.define("select2/selection/placeholder",["../utils"],function(){function a(a,b,c){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c)}return a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.createPlaceholder=function(a,b){var c=this.selectionContainer();return c.html(this.display(b)),c.addClass("select2-selection__placeholder").removeClass("select2-selection__choice"),c},a.prototype.update=function(a,b){var c=1==b.length&&b[0].id!=this.placeholder.id,d=b.length>1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},a}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e<d.length;e++){var f={data:d[e]};if(this.trigger("unselect",f),f.prevented)return}this.$element.val(this.placeholder.id).trigger("change"),this.trigger("toggle")}}},c.prototype._handleKeyboardClear=function(a,c,d){d.isOpen()||(c.which==b.DELETE||c.which==b.BACKSPACE)&&this._handleClear(c)},c.prototype.update=function(b,c){if(b.call(this,c),!(this.$selection.find(".select2-selection__placeholder").length>0||0===c.length)){var d=a('<span class="select2-selection__clear">×</span>');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('<li class="select2-search select2-search--inline"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" /></li>');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus()}),b.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val(""),e.$search.focus()}),b.on("enable",function(){e.$search.prop("disabled",!1)}),b.on("disable",function(){e.$search.prop("disabled",!0)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e.trigger("blur",a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}}),this.$selection.on("input",".select2-search--inline",function(){e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input",".select2-search--inline",function(a){e.handleSearch(a)})},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.trigger("open"),this.$search.val(b.text+" ")},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f<a.length;f++){var g=a[f].id;-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")});else{var d=a.id;this.$element.val(d),this.$element.trigger("change")}},d.prototype.unselect=function(a){var b=this;if(this.$element.prop("multiple"))return a.selected=!1,c(a.element).is("option")?(a.element.selected=!1,void this.$element.trigger("change")):void this.current(function(d){for(var e=[],f=0;f<d.length;f++){var g=d[f].id;g!==a.id&&-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")})},d.prototype.bind=function(a){var b=this;this.container=a,a.on("select",function(a){b.select(a.data)}),a.on("unselect",function(a){b.unselect(a.data)})},d.prototype.destroy=function(){this.$element.find("*").each(function(){c.removeData(this,"data")})},d.prototype.query=function(a,b){var d=[],e=this,f=this.$element.children();f.each(function(){var b=c(this);if(b.is("option")||b.is("optgroup")){var f=e.item(b),g=e.matches(a,f);null!==g&&d.push(g)}}),b({results:d})},d.prototype.addOptions=function(a){b.appendMany(this.$element,a)},d.prototype.option=function(a){var b;a.children?(b=document.createElement("optgroup"),b.label=a.text):(b=document.createElement("option"),void 0!==b.textContent?b.textContent=a.text:b.innerText=a.text),a.id&&(b.value=a.id),a.disabled&&(b.disabled=!0),a.selected&&(b.selected=!0),a.title&&(b.title=a.title);var d=c(b),e=this._normalizeItem(a);return e.element=b,c.data(b,"data",e),d},d.prototype.item=function(a){var b={};
+if(b=c.data(a[0],"data"),null!=b)return b;if(a.is("option"))b={id:a.val(),text:a.text(),disabled:a.prop("disabled"),selected:a.prop("selected"),title:a.prop("title")};else if(a.is("optgroup")){b={text:a.prop("label"),children:[],title:a.prop("title")};for(var d=a.children("option"),e=[],f=0;f<d.length;f++){var g=c(d[f]),h=this.item(g);e.push(h)}b.children=e}return b=this._normalizeItem(b),b.element=a[0],c.data(a[0],"data",b),b},d.prototype._normalizeItem=function(a){c.isPlainObject(a)||(a={id:a,text:a}),a=c.extend({},{text:""},a);var b={selected:!1,disabled:!1};return null!=a.id&&(a.id=a.id.toString()),null!=a.text&&(a.text=a.text.toString()),null==a._resultId&&a.id&&null!=this.container&&(a._resultId=this.generateResultId(this.container,a)),c.extend({},b,a)},d.prototype.matches=function(a,b){var c=this.options.get("matcher");return c(a,b)},d}),b.define("select2/data/array",["./select","../utils","jquery"],function(a,b,c){function d(a,b){var c=b.get("data")||[];d.__super__.constructor.call(this,a,b),this.addOptions(this.convertToOptions(c))}return b.Extend(d,a),d.prototype.select=function(a){var b=this.$element.find("option").filter(function(b,c){return c.value==a.id.toString()});0===b.length&&(b=this.option(a),this.addOptions(b)),d.__super__.select.call(this,a)},d.prototype.convertToOptions=function(a){function d(a){return function(){return c(this).val()==a.id}}for(var e=this,f=this.$element.find("option"),g=f.map(function(){return e.item(c(this)).id}).get(),h=[],i=0;i<a.length;i++){var j=this._normalizeItem(a[i]);if(c.inArray(j.id,g)>=0){var k=f.filter(d(j)),l=this.item(k),m=(c.extend(!0,{},l,j),this.option(l));k.replaceWith(m)}else{var n=this.option(j);if(j.children){var o=this.convertToOptions(j.children);b.appendMany(n,o)}h.push(n)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(b,c){this.ajaxOptions=this._applyDefaults(c.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),a.__super__.constructor.call(this,b,c)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return{q:a.term}},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url(a)),"function"==typeof f.data&&(f.data=f.data(a)),this.ajaxOptions.delay&&""!==a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");if(void 0!==f&&(this.createTag=f),b.call(this,c,d),a.isArray(e))for(var g=0;g<e.length;g++){var h=e[g],i=this._normalizeItem(h),j=this.option(i);this.$element.append(j)}}return b.prototype.query=function(a,b,c){function d(a,f){for(var g=a.results,h=0;h<g.length;h++){var i=g[h],j=null!=i.children&&!d({results:i.children},!0),k=i.text===b.term;if(k||j)return f?!1:(a.data=g,void c(a))}if(f)return!0;var l=e.createTag(b);if(null!=l){var m=e.option(l);m.attr("data-select2-tag",!0),e.addOptions([m]),e.insertTag(g,l)}a.results=g,c(a)}var e=this;return this._removeOldTags(),null==b.term||null!=b.page?void a.call(this,b,c):void a.call(this,b,d)},b.prototype.createTag=function(b,c){var d=a.trim(c.term);return""===d?null:{id:d,text:d}},b.prototype.insertTag=function(a,b,c){b.unshift(c)},b.prototype._removeOldTags=function(){var b=(this._lastTag,this.$element.find("option[data-select2-tag]"));b.each(function(){this.selected||a(this).remove()})},b}),b.define("select2/data/tokenizer",["jquery"],function(a){function b(a,b,c){var d=c.get("tokenizer");void 0!==d&&(this.tokenizer=d),a.call(this,b,c)}return b.prototype.bind=function(a,b,c){a.call(this,b,c),this.$search=b.dropdown.$search||b.selection.$search||c.find(".select2-search__field")},b.prototype.query=function(a,b,c){function d(a){e.select(a)}var e=this;b.term=b.term||"";var f=this.tokenizer(b,this.options,d);f.term!==b.term&&(this.$search.length&&(this.$search.val(f.term),this.$search.focus()),b.term=f.term),a.call(this,b,c)},b.prototype.tokenizer=function(b,c,d,e){for(var f=d.get("tokenSeparators")||[],g=c.term,h=0,i=this.createTag||function(a){return{id:a.term,text:a.term}};h<g.length;){var j=g[h];if(-1!==a.inArray(j,f)){var k=g.substr(0,h),l=a.extend({},c,{term:k}),m=i(l);e(m),g=g.substr(h+1)||"",h=0}else h++}return{term:g}},b}),b.define("select2/data/minimumInputLength",[],function(){function a(a,b,c){this.minimumInputLength=c.get("minimumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",b.term.length<this.minimumInputLength?void this.trigger("results:message",{message:"inputTooShort",args:{minimum:this.minimumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumInputLength",[],function(){function a(a,b,c){this.maximumInputLength=c.get("maximumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",this.maximumInputLength>0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<span class="select2-dropdown"><span class="select2-results"></span></span>');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.position=function(){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a){function b(){}return b.prototype.render=function(b){var c=b.call(this),d=a('<span class="select2-search select2-search--dropdown"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" /></span>');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},b.prototype.handleSearch=function(){if(!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},b.prototype.showSearch=function(){return!0},b}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('<li class="option load-more" role="treeitem"></li>'),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(a,b,c){this.$dropdownParent=c.get("dropdownParent")||document.body,a.call(this,b,c)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a("<span></span>"),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c){var d=this,e="scroll.select2."+c.id,f="resize.select2."+c.id,g="orientationchange.select2."+c.id,h=this.$container.parents().filter(b.hasScroll);h.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),h.on(e,function(){var b=a(this).data("select2-scroll-position");a(this).scrollTop(b.y)}),a(window).on(e+" "+f+" "+g,function(){d._positionDropdown(),d._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c){var d="scroll.select2."+c.id,e="resize.select2."+c.id,f="orientationchange.select2."+c.id,g=this.$container.parents().filter(b.hasScroll);g.off(d),a(window).off(d+" "+e+" "+f)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=(this.$container.position(),this.$container.offset());f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.top<f.top-h.height,k=i.bottom>f.bottom+h.height,l={left:f.left,top:g.bottom};c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){this.$dropdownContainer.width();var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d<b.length;d++){var e=b[d];e.children?c+=a(e.children):c++}return c}function b(a,b,c,d){this.minimumResultsForSearch=c.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),a.call(this,b,c,d)}return b.prototype.showSearch=function(b,c){return a(c.data.results)<this.minimumResultsForSearch?!1:b.call(this,c)},b}),b.define("select2/dropdown/selectOnClose",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("close",function(){d._handleSelectOnClose()})},a.prototype._handleSelectOnClose=function(){var a=this.getHighlightedResults();a.length<1||this.trigger("select",{data:a.data("data")})},a}),b.define("select2/dropdown/closeOnSelect",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("select",function(a){d._selectTriggered(a)}),b.on("unselect",function(a){d._selectTriggered(a)})},a.prototype._selectTriggered=function(a,b){var c=b.originalEvent;c&&c.ctrlKey||this.trigger("close")},a}),b.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(a){var b=a.input.length-a.maximum,c="Please delete "+b+" character";return 1!=b&&(c+="s"),c},inputTooShort:function(a){var b=a.minimum-a.input.length,c="Please enter "+b+" or more characters";return c},loadingMore:function(){return"Loading more results…"},maximumSelected:function(a){var b="You can only select "+a.maximum+" item";return 1!=a.maximum&&(b+="s"),b},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),b.define("select2/defaults",["jquery","require","./results","./selection/single","./selection/multiple","./selection/placeholder","./selection/allowClear","./selection/search","./selection/eventRelay","./utils","./translation","./diacritics","./data/select","./data/array","./data/ajax","./data/tags","./data/tokenizer","./data/minimumInputLength","./data/maximumInputLength","./data/maximumSelectionLength","./dropdown","./dropdown/search","./dropdown/hidePlaceholder","./dropdown/infiniteScroll","./dropdown/attachBody","./dropdown/minimumResultsForSearch","./dropdown/selectOnClose","./dropdown/closeOnSelect","./i18n/en"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C){function D(){this.reset()}D.prototype.apply=function(l){if(l=a.extend({},this.defaults,l),null==l.dataAdapter){if(l.dataAdapter=null!=l.ajax?o:null!=l.data?n:m,l.minimumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.selectionAdapter=l.multiple?e:d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L<K.length;L++){var M=K[L],N={};try{N=k.loadPath(M)}catch(O){try{M=this.defaults.amdLanguageBase+M,N=k.loadPath(M)}catch(P){l.debug&&window.console&&console.warn&&console.warn('Select2: The language file for "'+M+'" could not be automatically loaded. A fallback will be used instead.');continue}}J.extend(N)}l.translations=J}else{var Q=k.loadPath(this.defaults.amdLanguageBase+"en"),R=new k(l.language);R.extend(Q),l.translations=R}return l},D.prototype.reset=function(){function b(a){function b(a){return l[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function c(d,e){if(""===a.trim(d.term))return e;if(e.children&&e.children.length>0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(this.options.dir=a.prop("dir")?a.prop("dir"):a.closest("[dir]").prop("dir")?a.closest("[dir]").prop("dir"):"ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this._sync=c.bind(this._syncAttributes,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._sync);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._sync)}),this._observer.observe(this.$element[0],{attributes:!0,subtree:!1})):this.$element[0].addEventListener&&this.$element[0].addEventListener("DOMAttrModified",b._sync,!1)},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("focus",function(){a.$container.addClass("select2-container--focus")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open"),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ENTER?(a.trigger("results:select"),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle"),b.preventDefault()):c===d.UP?(a.trigger("results:previous"),b.preventDefault()):c===d.DOWN?(a.trigger("results:next"),b.preventDefault()):(c===d.ESC||c===d.TAB)&&(a.close(),b.preventDefault()):(c===d.ENTER||c===d.SPACE||(c===d.DOWN||c===d.UP)&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable")):this.trigger("enable")},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||(this.trigger("query",{}),this.trigger("open"))},e.prototype.close=function(){this.isOpen()&&this.trigger("close")},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._sync),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&this.$element[0].removeEventListener("DOMAttrModified",this._sync,!1),this._sync=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},e.prototype.render=function(){var b=a('<span class="select2 select2-container"><span class="selection"></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("select2/compat/utils",["jquery"],function(a){function b(b,c,d){var e,f,g=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0===this.indexOf("select2-")&&g.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&(f=d(this),null!=f&&g.push(f))})),b.attr("class",g.join(" "))}return{syncCssClasses:b}}),b.define("select2/compat/containerCss",["jquery","./utils"],function(a,b){function c(){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("containerCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptContainerCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("containerCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/dropdownCss",["jquery","./utils"],function(a,b){function c(){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("dropdownCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptDropdownCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("dropdownCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/initSelection",["jquery"],function(a){function b(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=c.get("initSelection"),this._isInitialized=!1,a.call(this,b,c)}return b.prototype.current=function(b,c){var d=this;return this._isInitialized?void b.call(this,c):void this.initSelection.call(null,this.$element,function(b){d._isInitialized=!0,a.isArray(b)||(b=[b]),c(b)})},b}),b.define("select2/compat/inputData",["jquery"],function(a){function b(a,b,c){this._currentData=[],this._valueSeparator=c.get("valueSeparator")||",","hidden"===b.prop("type")&&c.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a `<select>` element instead."),a.call(this,b,c)}return b.prototype.current=function(b,c){function d(b,c){var e=[];return b.selected||-1!==a.inArray(b.id,c)?(b.selected=!0,e.push(b)):b.selected=!1,b.children&&e.push.apply(e,d(b.children,c)),e}for(var e=[],f=0;f<this._currentData.length;f++){var g=this._currentData[f];e.push.apply(e,d(g,this.$element.val().split(this._valueSeparator)))}c(e)},b.prototype.select=function(b,c){if(this.options.get("multiple")){var d=this.$element.val();d+=this._valueSeparator+c.id,this.$element.val(d),this.$element.trigger("change")}else this.current(function(b){a.map(b,function(a){a.selected=!1})}),this.$element.val(c.id),this.$element.trigger("change")},b.prototype.unselect=function(a,b){var c=this;b.selected=!1,this.current(function(a){for(var d=[],e=0;e<a.length;e++){var f=a[e];
+b.id!=f.id&&d.push(f.id)}c.$element.val(d.join(c._valueSeparator)),c.$element.trigger("change")})},b.prototype.query=function(a,b,c){for(var d=[],e=0;e<this._currentData.length;e++){var f=this._currentData[e],g=this.matches(b,f);null!==g&&d.push(g)}c({results:d})},b.prototype.addOptions=function(b,c){var d=a.map(c,function(b){return a.data(b[0],"data")});this._currentData.push.apply(this._currentData,d)},b}),b.define("select2/compat/matcher",["jquery"],function(a){function b(b){function c(c,d){var e=a.extend(!0,{},d);if(null==c.term||""===a.trim(c.term))return e;if(d.children){for(var f=d.children.length-1;f>=0;f--){var g=d.children[f],h=b(c.term,g.text,g);h||e.children.splice(f,1)}if(e.children.length>0)return e}return b(c.term,d.text,d)?e:null}return c}return b}),b.define("select2/compat/query",[],function(){function a(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `query` option has been deprecated in favor of a custom data adapter that overrides the `query` method. Support will be removed for the `query` option in future versions of Select2."),a.call(this,b,c)}return a.prototype.query=function(a,b,c){b.callback=c;var d=this.options.get("query");d.call(null,b)},a}),b.define("select2/dropdown/attachContainer",[],function(){function a(a,b,c){a.call(this,b,c)}return a.prototype.position=function(a,b,c){var d=c.find(".dropdown-wrapper");d.append(b),b.addClass("select2-dropdown--below"),c.addClass("select2-container--below")},a}),b.define("select2/dropdown/stopPropagation",[],function(){function a(){}return a.prototype.bind=function(a,b,c){a.call(this,b,c);var d=["blur","change","click","dblclick","focus","focusin","focusout","input","keydown","keyup","keypress","mousedown","mouseenter","mouseleave","mousemove","mouseover","mouseup","search","touchend","touchstart"];this.$dropdown.on(d.join(" "),function(a){a.stopPropagation()})},a}),b.define("select2/selection/stopPropagation",[],function(){function a(){}return a.prototype.bind=function(a,b,c){a.call(this,b,c);var d=["blur","change","click","dblclick","focus","focusin","focusout","input","keydown","keyup","keypress","mousedown","mouseenter","mouseleave","mousemove","mouseover","mouseup","search","touchend","touchstart"];this.$selection.on(d.join(" "),function(a){a.stopPropagation()})},a}),b.define("jquery.select2",["jquery","require","./select2/core","./select2/defaults"],function(a,b,c,d){if(b("jquery.mousewheel"),null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if(b=b||{},"object"==typeof b)return this.each(function(){{var d=a.extend({},b,!0);new c(a(this),d)}}),this;if("string"==typeof b){var d=this.data("select2");null==d&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2.");var f=Array.prototype.slice.call(arguments,1),g=d[b](f);return a.inArray(b,e)>-1?this:g}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),function(c){"function"==typeof b.define&&b.define.amd?b.define("jquery.mousewheel",["jquery"],c):"object"==typeof exports?module.exports=c:c(a)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c});
\ No newline at end of file
--- /dev/null
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j<k;j++){o(M.4[j][i]!=0){1c=[];1s=1n;J{p=1n-1s;1c.19(M.4[i][p]+M.4[j][p])}H(--1s);M.4[i]=1c;1I}}}o(M.4[i][i]!=0){2e(j=i+1;j<k;j++){9 a=M.4[j][i]/M.4[i][i];1c=[];1s=1n;J{p=1n-1s;1c.19(p<=i?0:M.4[j][p]-M.4[i][p]*a)}H(--1s);M.4[j]=1c}}}H(--n);8 M},3h:l(){8 7.1K()},2z:l(){o(!7.1y()){8 w}9 M=7.1K();9 a=M.4[0][0],n=M.4.q-1,k=n,i;J{i=k-n+1;a=a*M.4[i][i]}H(--n);8 a},3f:l(){8 7.2z()},2y:l(){8(7.1y()&&7.2z()===0)},2Y:l(){o(!7.1y()){8 w}9 a=7.4[0][0],n=7.4.q-1,k=n,i;J{i=k-n+1;a+=7.4[i][i]}H(--n);8 a},3e:l(){8 7.2Y()},1Y:l(){9 M=7.1K(),1Y=0;9 a=7.4.q,15=a,i,G,10=7.4[0].q,j;J{i=15-a;G=10;J{j=10-G;o(F.13(M.4[i][j])>17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j<i;j++){1c=[];b=1n;J{p=1n-b;1c.19(M.4[j][p]-M.4[i][p]*M.4[j][i])}H(--b);M.4[j]=1c}}H(--a);8 S.u(c)},3c:l(){8 7.2w()},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(p){8(F.13(p-x)<=17.16)?x:p})},2n:l(){9 a=[];9 n=7.4.q,k=n,i;J{i=k-n;a.19(v.u(7.4[i]).2n())}H(--n);8 a.2K(\'\\n\')},26:l(a){9 i,4=a.4||a;o(1g(4[0][0])!=\'1f\'){9 b=4.q,15=b,G,10,j;7.4=[];J{i=15-b;G=4[i].q;10=G;7.4[i]=[];J{j=10-G;7.4[i][j]=4[i][j]}H(--G)}H(--b);8 7}9 n=4.q,k=n;7.4=[];J{i=k-n;7.4.19([4[i]])}H(--n);8 7}};S.u=l(a){9 M=25 S();8 M.26(a)};S.I=l(n){9 a=[],k=n,i,G,j;J{i=k-n;a[i]=[];G=k;J{j=k-G;a[i][j]=(i==j)?1:0}H(--G)}H(--n);8 S.u(a)};S.2X=l(a){9 n=a.q,k=n,i;9 M=S.I(n);J{i=k-n;M.4[i][i]=a[i]}H(--n);8 M};S.1R=l(b,a){o(!a){8 S.u([[F.1H(b),-F.1G(b)],[F.1G(b),F.1H(b)]])}9 d=a.1q();o(d.4.q!=3){8 w}9 e=d.1u();9 x=d.4[0]/e,y=d.4[1]/e,z=d.4[2]/e;9 s=F.1G(b),c=F.1H(b),t=1-c;8 S.u([[t*x*x+c,t*x*y-s*z,t*x*z+s*y],[t*x*y+s*z,t*y*y+c,t*y*z-s*x],[t*x*z-s*y,t*y*z+s*x,t*z*z+c]])};S.3b=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[1,0,0],[0,c,-s],[0,s,c]])};S.39=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[c,0,s],[0,1,0],[-s,0,c]])};S.38=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[c,-s,0],[s,c,0],[0,0,1]])};S.2J=l(n,m){8 S.1j(n,m).1b(l(){8 F.2F()})};S.1j=l(n,m){9 a=[],12=n,i,G,j;J{i=n-12;a[i]=[];G=m;J{j=m-G;a[i][j]=0}H(--G)}H(--12);8 S.u(a)};l 14(){}14.23={24:l(a){8(7.1m(a)&&7.1h(a.K))},1q:l(){8 14.u(7.K,7.U)},2U:l(a){9 V=a.4||a;8 14.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.U)},1m:l(a){o(a.W){8 a.1m(7)}9 b=7.U.1C(a.U);8(F.13(b)<=17.16||F.13(b-F.1A)<=17.16)},1o:l(a){o(a.W){8 a.1o(7)}o(a.U){o(7.1m(a)){8 7.1o(a.K)}9 N=7.U.2f(a.U).2q().4;9 A=7.K.4,B=a.K.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,D=7.U.4;9 b=P[0]-A[0],2a=P[1]-A[1],29=(P[2]||0)-A[2];9 c=F.1x(b*b+2a*2a+29*29);o(c===0)8 0;9 d=(b*D[0]+2a*D[1]+29*D[2])/c;9 e=1-d*d;8 F.13(c*F.1x(e<0?0:e))}},1h:l(a){9 b=7.1o(a);8(b!==w&&b<=17.16)},2T:l(a){8 a.1h(7)},1v:l(a){o(a.W){8 a.1v(7)}8(!7.1m(a)&&7.1o(a)<=17.16)},1U:l(a){o(a.W){8 a.1U(7)}o(!7.1v(a)){8 w}9 P=7.K.4,X=7.U.4,Q=a.K.4,Y=a.U.4;9 b=X[0],1z=X[1],1B=X[2],1T=Y[0],1S=Y[1],1M=Y[2];9 c=P[0]-Q[0],2s=P[1]-Q[1],2r=P[2]-Q[2];9 d=-b*c-1z*2s-1B*2r;9 e=1T*c+1S*2s+1M*2r;9 f=b*b+1z*1z+1B*1B;9 g=1T*1T+1S*1S+1M*1M;9 h=b*1T+1z*1S+1B*1M;9 k=(d*g/f+h*e)/(g-h*h);8 v.u([P[0]+k*b,P[1]+k*1z,P[2]+k*1B])},1r:l(a){o(a.U){o(7.1v(a)){8 7.1U(a)}o(7.1m(a)){8 w}9 D=7.U.4,E=a.U.4;9 b=D[0],1l=D[1],1k=D[2],1P=E[0],1O=E[1],1Q=E[2];9 x=(1k*1P-b*1Q),y=(b*1O-1l*1P),z=(1l*1Q-1k*1O);9 N=v.u([x*1Q-y*1O,y*1P-z*1Q,z*1O-x*1P]);9 P=11.u(a.K,N);8 P.1U(7)}1d{9 P=a.4||a;o(7.1h(P)){8 v.u(P)}9 A=7.K.4,D=7.U.4;9 b=D[0],1l=D[1],1k=D[2],1w=A[0],18=A[1],1a=A[2];9 x=b*(P[1]-18)-1l*(P[0]-1w),y=1l*((P[2]||0)-1a)-1k*(P[1]-18),z=1k*(P[0]-1w)-b*((P[2]||0)-1a);9 V=v.u([1l*x-1k*z,1k*y-b*x,b*z-1l*y]);9 k=7.1o(P)/V.1u();8 v.u([P[0]+V.4[0]*k,P[1]+V.4[1]*k,(P[2]||0)+V.4[2]*k])}},1V:l(t,a){o(1g(a.U)==\'1f\'){a=14.u(a.1N(),v.k)}9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,D=7.U.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 14.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*D[0]+R[0][1]*D[1]+R[0][2]*D[2],R[1][0]*D[0]+R[1][1]*D[1]+R[1][2]*D[2],R[2][0]*D[0]+R[2][1]*D[1]+R[2][2]*D[2]])},1t:l(a){o(a.W){9 A=7.K.4,D=7.U.4;9 b=A[0],18=A[1],1a=A[2],2N=D[0],1l=D[1],1k=D[2];9 c=7.K.1t(a).4;9 d=b+2N,2h=18+1l,2o=1a+1k;9 Q=a.1r([d,2h,2o]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2h)-c[1],Q[2]+(Q[2]-2o)-c[2]];8 14.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 14.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.U)}},1Z:l(a,b){a=v.u(a);b=v.u(b);o(a.4.q==2){a.4.19(0)}o(b.4.q==2){b.4.19(0)}o(a.4.q>3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{}))
\ No newline at end of file
--- /dev/null
+define(['app/ovsdb/lib/sylvester'], function() {
+ function Transform(a, b, c, d , e, f) {
+ if (a)
+ this.transform = $M([
+ [a, b, c],
+ [d, e, f],
+ [0, 0, 1]
+ ]);
+ else
+ this.transform = Matrix.I(3);
+ }
+
+ Transform.fromString = function(string) {
+ if(!string) {
+ return new Transform();
+ }
+ var g = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+ g.setAttribute('transform', string);
+ var t = g.transform.baseVal.consolidate();
+ var m = t.matrix;
+ return new Transform(m.a, m.b, m.c, m.d, m.e, m.f);
+ }
+
+ Transform.combine = function(ma, mb) {
+ var t = new Transform();
+ t.transform = ma.transform.x(mb.transform);
+ return t;
+ }
+
+ Transform.prototype.translate = function(tx, ty) {
+ this.transform = $M([[1, 0, tx], [0, 1, ty], [0, 0, 1]]).x(this.transform);
+ return this;
+ };
+
+ Transform.prototype.rotate = function(deg) {
+ var rad = parseFloat(deg) * (Math.PI/180),
+ cos = Math.cos(rad),
+ sin = Math.sin(rad);
+
+ this.transform = $M([[cos, -sin, 0], [sin, cos, 0], [0, 0, 1]]).x(this.transform);
+ return this;
+ };
+
+ Transform.prototype.scale = function(x, y) {
+ var x = x,
+ y = y || x;
+
+ this.transform = $M([[x, 0, 0], [0, y, 0], [0, 0, 1]]).x(this.transform);
+ return this;
+ };
+
+ Transform.prototype.skew = function(x, y) {
+ var alpha = Math.tan(parseFloat(x) * (Math.PI/180)),
+ betha = Math.tan(parseFloat(y) * (Math.PI/180));
+
+ this.transform = $M([[1, alpha, 0], [betha, 1, 0], [0, 0, 1]]).x(this.transform);
+ return this;
+ };
+
+ Transform.prototype.transformPoint = function(x, y) {
+ var v = $V([x, y, 1]);
+ return this.transform.x(v);
+ };
+
+ Transform.prototype.toString = function() {
+ return this.transform.inspect();
+ }
+
+ return {
+ Matrix: Transform // Matrix function name already used by Sylvester
+ };
+});
+++ /dev/null
-define([], function() {
-
-});
+++ /dev/null
-define([], function() {
- var ovsdb = angular.module('app.ovsdb', []);
-
- ovsdb.register = {
- controller: ovsdb.controller,
- service: ovsdb.service,
- factory: ovsdb.factory
- };
-
- return ovsdb;
-
-})
+++ /dev/null
-define([], function() {
-
-});
--- /dev/null
+define(['app/ovsdb/ovsdb.module'], function(ovsdb) {
+
+ ovsdb.register.constant('nodeIdentifier', {
+ IP: 'ip',
+ ID: 'node-id',
+ REMOTE_PORT: 'remote-port',
+ SRC_NODE: 'source-node',
+ DEST_NODE: 'dest-node',
+ SRC_TP: 'source-tp',
+ DEST_TP: 'dest-tp',
+ ADDRESSES: 'addresses'
+ });
+
+ ovsdb.register.constant('ovsNodeKeys', {
+ NODE_ID: 'node-id',
+ CONNECTION_INFO: 'ovsdb:connection-info',
+ OVS_VERSION: 'ovsdb:ovs-version',
+ LOCAL_IP: 'local-ip',
+ LOCAL_PORT: 'local-port',
+ REMOTE_IP: 'remote-ip',
+ REMOTE_PORT: 'remote-port',
+ OTHER_CONFIG: 'ovsdb:openvswitch-other-configs',
+ OTHER_CONFIG_KEY: 'other-config-key',
+ OTHER_CONFIG_VALUE: 'other-config-value'
+ });
+
+ ovsdb.register.constant('bridgeNodeKeys', {
+ NODE_ID: 'node-id',
+ CONTROLLER_ENTRY: 'ovsdb:controller-entry',
+ TARGET: 'target',
+ IS_CONNECTED: 'is-connected',
+ DATA_PATH: 'ovsdb:datapath-id',
+ BRIDGE_NAME: 'ovsdb:bridge-name',
+ TP: 'termination-point'
+ });
+
+ ovsdb.register.constant('tpKeys', {
+ NAME: 'ovsdb:name',
+ OF_PORT: 'ovsdb:ofport',
+ INTERFACE_TYPE: 'ovsdb:interface-type',
+ ATTACHED_MAC: 'attached-mac',
+ IFACE_ID: 'iface-id',
+ EXTERNAL_KEY_ID: 'external-id-key',
+ EXTERNAL_KEY_VALUE: 'external-id-value'
+ });
+
+ ovsdb.register.constant('flowInfoKeys', {
+ FEATURE: 'flow-node-inventory:switch-features',
+ SOFTWARE: 'flow-node-inventory:software',
+ HARDWARE: 'flow-node-inventory:hardware',
+ MANUFACTURER: 'flow-node-inventory:manufacturer',
+ IP: 'flow-node-inventory:ip-address',
+ TABLE: 'flow-node-inventory:table'
+ });
+
+ ovsdb.register.constant('linkIdentifier', {
+ SRC: 'source',
+ l3_unicast: 'l3-unicast-igp-topology:igp-link-attributes',
+ overlay_tunnel_type: 'overlay:tunnel-type',
+ supported_link: 'supporting-link',
+ ID: 'link-id',
+ DEST: 'destination'
+ });
+});
* terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
* and is available at http://www.eclipse.org/legal/epl-v10.html\r
*/\r
-\r
-define(['jquery', 'app/ovsdb/ovsdb.module','app/ovsdb/ovsdb.services'], function($, ovsdb) {\r
+define(['jquery', 'underscore', 'app/ovsdb/ovsdb.module', 'app/ovsdb/OvsCore', 'app/ovsdb/ovsdb.directives', 'app/ovsdb/ovsdb.services', 'app/ovsdb/lib/select2.full.min'], function ($, _, ovsdb, OvsCore) {\r
'use strict';\r
\r
- var RootOvsdbCtrl = function($rootScope) {\r
- $rootScope['section_logo'] = 'logo_ovsdb';\r
- };\r
- RootOvsdbCtrl.$inject = ['$rootScope'];\r
+ var RootOvsdbCtrl = function ($rootScope, cssInjector) {\r
+ $rootScope['section_logo'] = 'logo_ovsdb';\r
+ cssInjector.add('src/app/ovsdb/css/select2.min.css');\r
+ cssInjector.add('src/app/ovsdb/css/toggle-switch.css');\r
\r
- var BaseOvsdbCtrl = function($scope) {\r
- $scope['err'] = {\r
- "message": "",\r
- "tag": "",\r
- "type": ""\r
- };\r
+ cssInjector.add('src/app/ovsdb/css/ovsdb.css');\r
+ };\r
+ RootOvsdbCtrl.$inject = ['$rootScope', 'cssInjector'];\r
\r
- $scope.showError = function() {\r
- $('#errorMessage').fadeIn().delay(3000).fadeOut();\r
- };\r
+ var BaseOvsdbCtrl = function ($scope) {\r
+ $scope.err = {\r
+ "message": "",\r
+ "tag": "",\r
+ "type": ""\r
+ };\r
+ $scope.showError = function () {\r
+ $('#errorMessage').fadeIn().delay(3000).fadeOut();\r
+ };\r
};\r
BaseOvsdbCtrl.$inject = ['$scope'];\r
\r
- var OvsdbCtrl = function($scope, TopologyNetworkSvc) {\r
- BaseOvsdbCtrl.call(this, $scope);\r
+ var OvsdbCtrl = function ($q, $scope, TopologySvc, NeutronSvc, OvsUtil) {\r
+ BaseOvsdbCtrl.call(this, $scope);\r
+ var lgraphDataDefer = $q.defer(),\r
+ physDataDefer = $q.defer(),\r
+ filterTenant = {\r
+ bridgeIds : [''],\r
+ ovsdbIds : ['']\r
+ },\r
+ filterSubnet = {\r
+ bridgeIds : [''],\r
+ ovsdbIds : ['']\r
+ };\r
+\r
+ $scope.dataPromise = physDataDefer.promise;\r
+ $scope.lgraphIsReadyPromise = lgraphDataDefer.promise;\r
+ $scope.canvasWidth = $('#tabs').width();\r
+ $scope.canvasHeight = 580;\r
+\r
+ $scope.dialogData = ['d'];\r
+\r
+ $scope.tenants = [];\r
+ $scope.subnets = [];\r
+ $scope.selectedTenant = '';\r
+ $scope.selectedSubnet = '';\r
+\r
+ $scope.toggleLayer = function () {\r
+ $scope.rotateGraph($scope.opt.layer);\r
+ };\r
+\r
+ $scope.resizeGraph = function () {\r
+ var $row = $('#ovsdb_contain > div.row:first');\r
+ var h = $row.height();\r
+ $row.data('ph', h);\r
+ $row.fadeOut();\r
+ $('#nv_graph > svg').animate({\r
+ height: '+=' + h\r
+ });\r
+ };\r
+\r
+ $scope.minimizeGraph = function () {\r
+ var $row = $('#ovsdb_contain > div.row:first');\r
+ var h = $row.data('ph');\r
+ $row.fadeIn();\r
+ $('#nv_graph > svg').animate({\r
+ height: '-=' + h\r
+ });\r
+ };\r
+\r
+ function applyFilter(inverse) {\r
+ var bridgeIds = _.uniq(filterTenant.bridgeIds.concat(filterSubnet.bridgeIds));\r
+ var ovsdbIds = _.uniq(filterTenant.ovsdbIds.concat(filterSubnet.ovsdbIds));\r
+ $scope.filterNode(bridgeIds, '.bridge');\r
+ $scope.filterNode(ovsdbIds, '.switch');\r
+ $scope.filterLink();\r
+ }\r
+\r
+ function removeFilter() {\r
+ $scope.filterNode([''], '.bridge', false);\r
+ $scope.filterNode([''], '.switch', false);\r
+ $scope.filterLink();\r
+ }\r
+\r
+ $scope.fiterByTenant = function() {\r
+ if ($scope.selectedTenant) {\r
+ var tenant = $scope.selectedTenant;\r
+ OvsUtil.extractLogicalByTenant(tenant.id).then(function(result) {\r
+ var bridgeId = result[0],\r
+ ovsdbId = result[1];\r
+\r
+ filterTenant.bridgeIds = _.uniq(filterTenant.bridgeIds.concat(bridgeId));\r
+ filterTenant.ovsdbIds = _.uniq(filterTenant.ovsdbIds.concat(ovsdbId));\r
+ applyFilter();\r
+ });\r
+ } else {\r
+ filterTenant.bridgeIds = [''];\r
+ filterTenant.ovsdbIds = [''];\r
+ applyFilter();\r
+ }\r
+ };\r
+\r
+ $scope.filterBySubnet = function() {\r
+ if (!_.isEmpty($scope.selectedSubnet)) {\r
+ var subnets = _.map($scope.selectedSubnet, function(d) {\r
+ return d.id;\r
+ });\r
+ OvsUtil.extractLogicalBySubnet(subnets).then(function(result) {\r
+ var bridgeId = result[0],\r
+ ovsdbId = result[1];\r
+ filterSubnet.bridgeIds = _.uniq(filterSubnet.bridgeIds.concat(bridgeId));\r
+ filterSubnet.ovsdbIds = _.uniq(filterSubnet.ovsdbIds.concat(ovsdbId));\r
+ applyFilter();\r
+ });\r
+ } else {\r
+ filterSubnet.bridgeIds = [''];\r
+ filterSubnet.ovsdbIds = [''];\r
+ applyFilter();\r
+ }\r
+ };\r
+\r
+ $scope.onNodeClick = function (d, nodes, links) {\r
+ $scope.pDialogData = d.node.pretty();\r
+ $scope.$apply();\r
+ };\r
+\r
+ $('#tenantSelect').select2({\r
+ width: "200",\r
+ minimumResultsForSearch: Infinity\r
+ }).next().children('span').children('span').css('width', '200'); //hack to have the arrow with the same background\r
+\r
+ $("#tagPicker").select2({\r
+ width: "230",\r
+ });\r
+\r
+ var $tabs = $('#tabs').tabs({selected: 0});\r
+\r
+ $scope.goToPhysicalView = function(d) {\r
+ $tabs.tabs("option", "active", 1);\r
+ $('#tenantSelect').val(d.tenantId).change();\r
+\r
+ if ( d instanceof OvsCore.Neutron.Network) {\r
+ $('#tagPicker').val(d.subnets.map(function(d){return d.id;})).change();\r
+ }\r
+ };\r
+\r
+ OvsUtil.getLogicalTopology().then(function(networks) {\r
+ var tenantList = NeutronSvc.getAllTenants();\r
+ _.each(tenantList, function(t) {\r
+ $scope.tenants.push({id : t, name: t});\r
+ });\r
+ NeutronSvc.getSubNets().then(function(subHash) {\r
+ $scope.subnets = _.values(subHash).map(function(n) { return n[0]; });\r
+ });\r
+\r
+ lgraphDataDefer.resolve(networks);\r
+ });\r
+\r
+ TopologySvc.getTopologies().then(function(d) {\r
+ physDataDefer.resolve(d);\r
+ });\r
\r
};\r
- OvsdbCtrl.$inject = ['$scope', 'TopologyNetworkSvc'];\r
+\r
+ OvsdbCtrl.$inject = ['$q', '$scope', 'TopologySvc', 'NeutronSvc', 'OvsUtil'];\r
OvsdbCtrl.prototype = Object.create(BaseOvsdbCtrl.prototype);\r
\r
ovsdb.register.controller('RootOvsdbCtrl', RootOvsdbCtrl);\r
+++ /dev/null
-/*
- * Copyright (c) 2015 Inocybe Technologies 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
-*/
-
-#errorMessage {
- display:none;
-}
--- /dev/null
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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
+ */
+define(['app/ovsdb/ovsdb.module', 'app/ovsdb/lib/d3.min', 'app/ovsdb/Graph', 'app/ovsdb/LogicalGraph','app/ovsdb/OvsCore', 'underscore', 'jquery', 'jquery-ui'], function (ovsdb, d3, Graph, LogicalGraph, OvsCore, _, $) {
+ 'use strict';
+
+ ovsdb.register.directive('logicalGraph', function() {
+ return {
+ restrict: 'EA',
+ scope: false,
+ link : function (scope, elem, attr) {
+ var lgraph = null,
+ tabCreated = false,
+ width = scope.canvasWidth, //ele[0].clientWidth,
+ height = scope.canvasHeight;
+
+ scope.lDialogData = {};
+
+ scope.lgraphIsReadyPromise.then(function(ltopo) {
+ if (!lgraph) {
+ lgraph = new LogicalGraph(elem[0], width, height);
+ }
+
+ lgraph.networks = ltopo;
+
+ lgraph.start();
+
+ lgraph.onClick = function(e, d) {
+ var dialogId = '#lDialog';
+ scope.lDialogData = d.pretty();
+ scope.$apply();
+
+ if (!tabCreated) {
+ $(dialogId).tabs();
+ $(dialogId).draggable({
+ containment: 'parent',
+ cancel:'.window_content'
+ });
+ tabCreated = true;
+ } else {
+ $(dialogId).tabs('refresh');
+ }
+
+ var $dia = $(dialogId);
+ $dia.css('left', e.left + 30);
+ $dia.css('top', e.top + 35);
+ $dia.show();
+
+ };
+
+ lgraph.dblClick = function(d) {
+ scope.goToPhysicalView(d);
+ };
+ });
+ scope.hideLogicalDialog = function() {
+ $('#lDialog').tabs("option", "active", 0)
+ .hide();
+ };
+ elem.on('$destroy', function () {
+ if (lgraph) {
+ lgraph.freeDOM();
+ }
+ });
+ }
+ };
+ });
+
+ ovsdb.register.directive('physicalGraph', function (CacheFactory) {
+ return {
+ restrict: 'EA',
+ scope: false,
+ //templateUrl: 'src/app/ovsdb/views/graph_header.tpl.html',
+ link: function (scope, ele, attr) {
+
+ var graph = null,
+ tabCreated = false,
+ width = scope.canvasWidth,
+ height = scope.canvasHeight;
+
+ scope.reset = function () {
+ var transform = d3.transform(vis.attr('transform')),
+ ix = d3.interpolate(x.domain(), [-width / 2, width / 2]),
+ iy = d3.interpolate(y.domain(), [-height / 2, height / 2]),
+ px = x.domain(ix(1)),
+ py = y.domain(iy(1));
+
+ vis.transition().duration(750).call(zoom.x(px).y(py).scale(1).event);
+ };
+
+ scope.dataPromise.then(function (topo) {
+ if (!graph) {
+ console.log('physical graph created');
+ graph = new Graph(ele[0], width, height);
+ }
+ var nodes = _.clone(topo.nodes);
+ var links = _.clone(topo.links);
+
+ graph.setPosCache(CacheFactory.getCacheObj('nodePos'));
+
+ graph.links = _.values(links);
+ graph.nodes = _.map(nodes, function (value) {
+ return {
+ node: value
+ };
+ });
+ graph.start();
+
+ scope.nbOpenFlowSwitch = _.size(topo.bridgeNodes);
+ scope.nbOvsNode = _.size(topo.ovsdbNodes);
+
+ var linkedByIndex = {};
+ _.each(topo.flowLinks, function (d) {
+ linkedByIndex[d.source + ',' + d.target] = true;
+ });
+
+ function isConnected(a, b) {
+ return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
+ }
+
+ function hasConnections(a) {
+ for (var property in linkedByIndex) {
+ var s = property.split(",");
+ if ((s[0] == a.index || s[1] == a.index) && linkedByIndex[property])
+ return true;
+ }
+ return false;
+ }
+
+ graph.onNodeOver = function (d, nodes, links) {
+ nodes.selectAll('.switch > rect').style("stroke", function (o) {
+ return isConnected(d, o) ? "blue" : "black";
+ });
+
+ links.style("stroke", function (o) {
+ return ((o.source.index == d.index || o.target.index == d.index) && o.linkType != 'tunnel') ? "blue" : o.color;
+ });
+ };
+
+ graph.onNodeOut = function (d, nodes, links) {
+ nodes.selectAll('.switch > rect').style("stroke", "black");
+ links.style("stroke", function(o) { return o.color; });
+ };
+
+ graph.onNodeClick = function (d, nodes, links, ctx) {
+ /*var node = d3.select(ctx);
+ d3.select('.node_selected').classed('node_selected', false).attr('filter', 'none');
+ node.classed('node_selected', true).attr('filter', 'url(#selectNode)');*/
+ scope.onNodeClick(d);
+ var dialogId = '#pDialog',
+ $dia = $(dialogId);
+
+ if (!tabCreated) {
+ $(dialogId).tabs();
+ $(dialogId).draggable({
+ containment: 'parent',
+ cancel:'.window_content'
+ });
+ tabCreated = true;
+ } else {
+ $(dialogId).tabs('refresh');
+ }
+
+ $dia.css('left', /*e.left + */30);
+ $dia.css('top', /*e.top + */35);
+ $dia.show();
+ };
+
+ });
+
+ ele.on('$destroy', function() {
+ graph.freeDOM();
+ });
+
+ scope.hidePhysicalDialog = function() {
+ $('#pDialog').tabs("option", "active", 0)
+ .hide();
+ };
+
+ scope.rotateGraph = function (value) {
+ var b = value ? 1 : -1;
+ graphs.applyPerspective(value);
+ graphs.update();
+ $('path.tunnel').toggle();
+ };
+
+ scope.filterNode = function(nodeIds, tags, exclude) {
+ exclude = (exclude === null) ? true : exclude;
+ var nodes = d3.selectAll(tags);
+ nodes.each(function(d) {
+ if (nodeIds.indexOf(d.node.nodeId) < 0) {
+ d.hidden = exclude;
+ } else {
+ d.hidden = !exclude;
+ }
+ });
+ nodes.transition().duration(200).style('opacity', function(d) {
+ return d.hidden ? '0.3' : '1';
+ });
+
+ };
+
+ scope.filterLink = function() {
+ var links = d3.selectAll(".tunnel, .link, .bridgeOvsLink");
+
+ links.each(function(d, i) {
+ d.hidden = d.source.hidden || d.target.hidden;
+ });
+ links.transition().duration(200).style('opacity', function(d) {
+ return d.hidden ? '0.3' : '1';
+ });
+ };
+ }
+ };
+ });
+
+});
var ovsdb = angular.module('app.ovsdb', ['app.core', 'pascalprecht.translate', 'ui.router.state', 'restangular', 'config']);\r
ovsdb.register = ovsdb; // for unit test\r
\r
- ovsdb.config(function($stateProvider, $compileProvider, $controllerProvider, $provide, NavHelperProvider) {\r
+ // Filter to access neutron opendaylight.\r
+ // This factory need to be to avoid circular dependencies.\r
+ ovsdb.factory('NeutronInterceptor', ['$q', '$window', 'Base64', function($q, $window, Base64) {\r
+ return {\r
+ request : function(config) {\r
+ // Use AAA basic authentication\r
+ if (config.url.indexOf('controller/nb/v2') != -1) {\r
+ config.headers = config.headers || {};\r
+ if ($window.sessionStorage.odlUser && $window.sessionStorage.odlPass) {\r
+ var encoded = Base64.encode('admin' + ':' + 'admin');\r
+ config.headers.Authorization = 'Basic ' + encoded;\r
+ }\r
+ }\r
+ return config;\r
+ },\r
+ response : function(response) {\r
+ return response || $q.when(response);\r
+ }\r
+ };\r
+ }]);\r
+\r
+ ovsdb.config(function($stateProvider, $compileProvider, $controllerProvider, $provide, $httpProvider, NavHelperProvider) {\r
ovsdb.register = {\r
controller : $controllerProvider.register,\r
directive : $compileProvider.directive,\r
factory : $provide.factory,\r
- service : $provide.service\r
+ service : $provide.service,\r
+ constant: $provide.constant\r
\r
};\r
\r
NavHelperProvider.addToMenu('Ovsdb', {\r
"link" : "#/ovsdb/index",\r
"active" : "main.ovsdb.*",\r
- "title" : "OVSDB",\r
+ "title" : "Network Virtualization",\r
"icon" : "icon-sitemap",\r
"page" : {\r
- "title" : "OVSDB",\r
+ "title" : "NetWork Virtualization",\r
"description" : "OVSDB"\r
}\r
});\r
abstract: true,\r
views : {\r
'content' : {\r
- templateUrl: 'src/app/ovsdb/root.tpl.html',\r
+ templateUrl: 'src/app/ovsdb/views/root.tpl.html',\r
controller: 'RootOvsdbCtrl'\r
}\r
}\r
access: access.admin,\r
views: {\r
'': {\r
- templateUrl: 'src/app/ovsdb/index.tpl.html',\r
+ templateUrl: 'src/app/ovsdb/views/index.tpl.html',\r
controller: 'OvsdbCtrl'\r
}\r
}\r
});\r
+\r
+ $httpProvider.interceptors.push('NeutronInterceptor');\r
});\r
\r
return ovsdb;\r
-/*\r
- * Copyright (c) 2015 Inocybe Technologies and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-\r
-define(['app/ovsdb/ovsdb.module'],function(ovsdb) {\r
- 'use strict';\r
-\r
- ovsdb.register.factory('TopologyNetworkRestangular', function(Restangular, ENV) {\r
- return Restangular.withConfig(function(RestangularConfig) {\r
- RestangularConfig.setBaseUrl(ENV.getBaseURL("AD_SAL"));\r
- });\r
- });\r
-\r
- ovsdb.register.factory('TopologyNetworkSvc', function(TopologyNetworkRestangular) {\r
- var svc = {\r
- base: function(name) {\r
- return TopologyNetworkRestangular.one('restconf', name).one('network-topology:network-topology');\r
- },\r
- data : null\r
- };\r
-\r
- svc.getCurrentData = function() {\r
- return svc.data;\r
- };\r
-\r
- svc.getTopologiesIds = function() {\r
- svc.data = svc.base('operational').getList();\r
- return svc.data;\r
- };\r
-\r
- svc.getConfigNode = function(topologyId, nodeId) {\r
- return svc.base('config').one('topology', topologyId).one('node', nodeId).get();\r
- };\r
-\r
- svc.addConfigNode = function(topologyId, nodeId, data) {\r
- return svc.base('config').one('topology', topologyId).one('node').put(nodeId, data);\r
- };\r
-\r
- svc.addConfigBridge = function(topologyId, nodeId, data) {\r
- return svc.base('config').one('topology', topologyId).put(nodeId, data);\r
- };\r
-\r
- svc.removeConfigNode = function(topologyId, nodeId) {\r
- return svc.base('config').one('topology', topologyId).one('node', nodeId).remove();\r
- };\r
-\r
- svc.addTerminationPointConfig = function(topologyId, nodeId, terminationId, data) {\r
- return svc.base('config').one('topology', topologyId).one('node', nodeId).one('termination-point').put(terminationId, data);\r
- };\r
-\r
- svc.getTerminationPointConfig = function(topologyId, nodeId, terminationId) {\r
- return svc.base('config').one('topology', topologyId).one('node', nodeId).one('termination-point', terminationId).get();\r
- };\r
-\r
- svc.removeTerminationPointConfig = function(topologyId, nodeId, terminationId) {\r
- return svc.base('config').one('topology', topologyId).one('node', nodeId).one('termination-point', terminationId).remove();\r
- };\r
- return svc;\r
- });\r
-\r
-\r
- ovsdb.register.factory('TopologyNetworkFactory', function() {\r
-\r
- var factory = {\r
- createOvsdbNodeObject: function(nodeId, nodePort, nodeRemoteIp) {\r
- return {\r
- "network-topology:node": [\r
- {\r
- "node-id": nodeId,\r
- "connection-info": {\r
- "ovsdb:remote-port": nodePort,\r
- "ovsdb:remote-ip": nodeRemoteIp\r
- }\r
- }\r
- ]\r
- };\r
- },\r
- createConfigNode: function(nodeId, bridgeName,datapathId, protocolEntries, controllerEntries, managedBy) {\r
- var configNode = {\r
- "network-topology:node": [\r
- {\r
- "node-id": nodeId,\r
- "ovsdb:bridge-name": bridgeName,\r
- "ovsdb:datapath-id": datapathId,\r
- "ovsdb:protocol-entry": [ ],\r
- "ovsdb:controller-entry": [ ],\r
- "ovsdb:managed-by": managedBy\r
- }\r
- ]\r
- };\r
-\r
- for (var protocolEntry in protocolEntries) {\r
- configNode[0]['ovsdb:protocal-entry'].push({\r
- "protocol": protocolEntry\r
- });\r
- }\r
-\r
- for (var controllerEntry in controllerEntries) {\r
- configNode[0]['ovsdb:controller-entry'].push({\r
- "protocol" : controllerEntry\r
- });\r
- }\r
-\r
- return configNode;\r
-\r
- },\r
- createEndPoint: function(ovsdb_options, name, interface_type, tp_id, vlan_tag, trunks, vlan_mode) {\r
- var termination_point = {\r
- "network-topology:termination-point": [\r
- {\r
- "ovsdb:options": [ ],\r
- "ovsdb:name": name,\r
- "ovsdb:interface-type": interface_type,\r
- "tp-id": tp_id,\r
- "vlan-tag": vlan_tag,\r
- "trunks": [ ],\r
- "vlan-mode":vlan_mode\r
- }\r
- ]\r
- };\r
-\r
- for (var ovsdb_option in ovsdb_options) {\r
- termination_point[0]['ovsdb:options'].push({\r
- "ovsdb:option": ovsdb_option.option,\r
- "ovsdb:value" : ovsdb_option.value\r
- });\r
- }\r
-\r
- for (var trunk in trunks) {\r
- termination_point[0]['trunks'].push({\r
- "trunk":trunk\r
- });\r
- }\r
-\r
- return termination_point;\r
- }\r
- };\r
-\r
- return factory;\r
-\r
- });\r
-\r
-});\r
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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
+ */
+define(['app/ovsdb/ovsdb.module', 'app/ovsdb/OvsCore', 'underscore', 'app/ovsdb/ovsdb.constant'], function(ovsdb, OvsCore, _) {
+ 'use strict';
+
+ ovsdb.register.factory('OvsdbRestangular', ['Restangular', 'ENV', function(Restangular, ENV) {
+ return Restangular.withConfig(function(RestangularConfig) {
+ RestangularConfig.setBaseUrl(ENV.getBaseURL("MD_SAL"));
+ });
+ }]);
+
+ // nbv2 support depricated in dlux
+ ovsdb.register.factory('NeutronRestangular', ['Restangular', function(Restangular) {
+ return Restangular.withConfig(function(RestangularConfig) {
+ RestangularConfig.setBaseUrl('http://localhost:8080/controller/nb/v2/neutron');
+ });
+ }]);
+
+ ovsdb.register.factory('CacheFactory', function($q) {
+ var svc = {},
+ ovsCache = {};
+ /*BUG : Using the persistant cache make the physical
+ * graph links to stop reacting with the force layout
+ * algorithm. The current behavior is to use the cache
+ * only the pile up the datas.
+ */
+ svc.obtainDataFromCache = function(key, fn, ctx) {
+ var cacheDefer = $q.defer();
+
+ if (angular.isUndefined(ovsCache[key])) {
+ fn.call(ctx, function(data) {
+ ovsCache[key] = {
+ obj : data,
+ timestamp : Date.now() + 2000//300000 // 5 mintues
+ };
+ cacheDefer.resolve(data);
+ });
+ } else {
+ var cacheObj = ovsCache[key];
+ if (cacheObj.timestamp < Date.now() || _.isEmpty(cacheObj.obj)) {
+ fn.call(ctx, function(data) {
+ ovsCache[key] = {
+ obj : data,
+ timestamp : Date.now() + 2000//300000 // 5 mintues
+ };
+ cacheDefer.resolve(data);
+ });
+ } else {
+ cacheDefer.resolve(cacheObj.obj);
+ }
+ }
+
+ return cacheDefer.promise;
+ };
+
+ svc.getCacheObj = function(key) {
+ if (angular.isUndefined(ovsCache[key])) {
+ ovsCache[key] = {};
+ }
+ return ovsCache[key];
+ };
+
+ return svc;
+ });
+
+ var TopologySvc = function(OvsdbRestangular, nodeIdentifier, ovsNodeKeys, bridgeNodeKeys, tpKeys, flowInfoKeys, linkIdentifier, $q, $http, CacheFactory) {
+ var svc = {
+ base: function(type) {
+ return OvsdbRestangular.one('restconf').one(type);
+ }
+ };
+
+ function parseOvsdbNode(node) {
+ var inetMgr = '',
+ inetNode = '',
+ otherLocalIp = '',
+ otherInfo = null,
+ connectionInfo = null;
+
+ connectionInfo = node[ovsNodeKeys.CONNECTION_INFO];
+ otherInfo = node[ovsNodeKeys.OTHER_CONFIG];
+
+ if (_.isObject(connectionInfo)) {
+ inetMgr = connectionInfo[ovsNodeKeys.LOCAL_IP] + ':' + connectionInfo[ovsNodeKeys.LOCAL_PORT];
+ inetNode = connectionInfo[ovsNodeKeys.REMOTE_IP] + ':' + connectionInfo[ovsNodeKeys.REMOTE_PORT];
+ }
+
+ if (_.isArray(otherInfo)) {
+ _.each(otherInfo, function(value) {
+ if (value[ovsNodeKeys.OTHER_CONFIG_KEY] === 'local_ip') {
+ otherLocalIp = value[ovsNodeKeys.OTHER_CONFIG_VALUE];
+ }
+ });
+ }
+
+ return new OvsCore.OvsNode(node[ovsNodeKeys.NODE_ID], inetMgr, inetNode, otherLocalIp, node[ovsNodeKeys.OVS_VERSION]);
+ }
+
+ function parseBridgeNode(node) {
+ var bridgeNode = null,
+ controllerTarget = '',
+ controllerConnected = false,
+ tp = node[bridgeNodeKeys.TP],
+ controllerEntries = node[bridgeNodeKeys.CONTROLLER_ENTRY];
+
+ _.each(controllerEntries, function(value) {
+ controllerTarget = value[bridgeNodeKeys.TARGET];
+ controllerEntries = value[bridgeNodeKeys.IS_CONNECTED];
+ return false; // break the anonymus function
+ });
+
+ bridgeNode = new OvsCore.BridgeNode(node[bridgeNodeKeys.NODE_ID], node[bridgeNodeKeys.DATA_PATH], node[bridgeNodeKeys.BRIDGE_NAME], controllerTarget, controllerConnected);
+
+ _.each(tp, function(value) {
+ var tp = parseBridgeTP(value);
+
+ if (tp.ofPort == '65534' && (tp.name === 'br-ex' || tp.name === 'br-int')) {
+ return;
+ } else {
+ bridgeNode.addTerminationPoint(tp);
+ }
+
+ });
+
+ return bridgeNode;
+ }
+
+ function parseBridgeTP(tp) {
+ var mac = '',
+ ifaceId = '',
+ extInfo = tp['ovsdb:port-external-ids'] || tp['ovsdb:interface-external-ids'];
+
+ _.each(extInfo, function(ext) {
+ if (ext[tpKeys.EXTERNAL_KEY_ID] === tpKeys.ATTACHED_MAC) {
+ mac = ext[tpKeys.EXTERNAL_KEY_VALUE];
+ }
+ if (ext[tpKeys.EXTERNAL_KEY_ID] === tpKeys.IFACE_ID) {
+ ifaceId = ext[tpKeys.EXTERNAL_KEY_VALUE] || '';
+ }
+ });
+
+ return new OvsCore.TerminationPoint(tp[tpKeys.NAME], tp[tpKeys.OF_PORT], tp[tpKeys.INTERFACE_TYPE], mac, ifaceId);
+ }
+
+ function fetchTopology(cb) {
+ var invNodeDefer = this.base('operational').one('opendaylight-inventory:nodes').getList();
+ var netTopoDefer = this.base('operational').one('network-topology:network-topology').getList();
+
+ // be sure all data are loaded
+ $q.all([invNodeDefer, netTopoDefer]).then(function(values) {
+ var invNode = values[0],
+ netTopo = values[1],
+ index_hash = [],
+ i = 0;
+
+ // check if the data look fine in network topology
+ if (!netTopo || !netTopo['network-topology'] || !netTopo['network-topology'].topology) {
+ throw new Error('Invalid json format while parsing network-topology');
+ }
+
+ // check if the data look fine in inventory node
+ if (!invNode || !invNode.nodes || !invNode.nodes.node) {
+ throw new Error('Invalid JSON format while parsing inventory-node');
+ }
+
+ // get all topologies and start looping
+ var topologies = netTopo['network-topology'].topology,
+ nodes = invNode.nodes.node,
+ topo = new OvsCore.Topology();
+
+ _.each(topologies, function(topology, topo_index) {
+ if (!topology.hasOwnProperty('topology-id')) {
+ throw new Error('Invalide JSON format, no topology-id for the topology [' + topo_index + ']');
+ }
+
+ // if there no node it will be an empty array so noop
+ (topology.node || []).forEach(function(node) {
+ if (!node[nodeIdentifier.ID]) {
+ throw new Error('Unexpected node : undefined ' + nodeIdentifier.ID + ' key');
+ }
+ index_hash[node[nodeIdentifier.ID]] = i++;
+
+ if (node['ovsdb:bridge-name']) {
+ //bridge Node
+ topo.registerBridgeNode(parseBridgeNode(node));
+ } else if (node['ovsdb:connection-info']) {
+ // obsvdb Node
+ topo.registerOvsdbNode(parseOvsdbNode(node));
+ }
+ });
+
+ // if there no link it will be an empty array so noop
+ (topology.link || []).forEach(function(link) {
+
+ var source = link[linkIdentifier.SRC]['source-node'],
+ dest = link[linkIdentifier.DEST]['dest-node'];
+
+ topo.registerLink(new OvsCore.Link(link[linkIdentifier.ID], source, dest));
+ });
+
+ });
+
+ _.each(nodes, function(node, index) {
+ if (!node.id) {
+ return;
+ }
+
+ var bridgeId = node.id;
+
+ var bridgeNode = _.filter(topo.bridgeNodes, function(bridgeNode) {
+ return bridgeNode.getFLowName() === bridgeId;
+ })[0];
+
+ // match info for bridge node
+ if (bridgeNode) {
+ bridgeNode.flowInfo.features = node[flowInfoKeys.FEATURE];
+ bridgeNode.flowInfo.software = node[flowInfoKeys.SOFTWARE];
+ bridgeNode.flowInfo.hardware = node[flowInfoKeys.HARDWARE];
+ bridgeNode.flowInfo.manufacturer = node[flowInfoKeys.MANUFACTURER];
+ bridgeNode.flowInfo.ip = node[flowInfoKeys.IP];
+
+ _.each(node[flowInfoKeys.TABLE], function(entry) {
+ if (!_.isUndefined(entry.id)) {
+ _.each(entry.flow, function(flow) {
+ bridgeNode.addFlowTableInfo({ key: flow.table_id, value: flow.id});
+ });
+ }
+ });
+ }
+ });
+
+ // show relation between ovsNode and switch with a link
+ _.each(topo.ovsdbNodes, function(node, index) {
+ var bridges = _.filter(topo.bridgeNodes, function(bnode) {
+ return bnode.nodeId.indexOf(node.nodeId) > -1;
+ });
+ _.each(bridges, function(bridge) {
+ var size = _.size(topo.links),
+ link = new OvsCore.BridgeOvsLink(++size, node.nodeId, bridge.nodeId);
+ topo.registerLink(link);
+ });
+ });
+
+ function findVxlan(bridgeNode) {
+ var tunnels = [];
+
+ _.each(bridgeNode, function(node) {
+ var ovsdbNode = _.find(topo.ovsdbNodes, function(oNode) {
+ return node.nodeId.indexOf(oNode.nodeId) > -1;
+ });
+ if (!ovsdbNode) {
+ return false;
+ }
+ _.each(node.tPs, function(tp, index) {
+ if (tp.name.indexOf('vxlan-') > -1) {
+ tunnels.push({
+ port : tp,
+ bridge : node,
+ ovsIp : ovsdbNode.otherLocalIp || ovsdbNode.inetMgr
+ });
+ }
+ });
+ });
+
+ return tunnels;
+ }
+
+ // extract all tunnel paired with their bridge
+ var tunnels = findVxlan(topo.bridgeNodes);
+ // loop over all pairs
+ _.each(tunnels, function(tunnel, index) {
+ var currIp = tunnel.ovsIp,
+ destIp = tunnel.port.name.replace('vxlan-', ''),
+ linkedBridge = _.find(tunnels.slice(index), function(t) {
+ var vxlanIp = t.port.name.replace('vxlan-', '');
+ return vxlanIp === currIp;
+ });
+
+ if (linkedBridge) {
+ topo.registerLink(new OvsCore.TunnelLink(tunnel.port.name + linkedBridge.port.name, tunnel.bridge.nodeId, linkedBridge.bridge.nodeId));
+ }
+ });
+
+ topo.updateLink();
+ cb(topo);
+ },
+ function(err) {
+ throw err;
+ }
+ );
+ }
+
+ svc.getTopologies = function() {
+ return CacheFactory.obtainDataFromCache('topologies', fetchTopology, this);
+ };
+
+ return svc;
+ };
+ TopologySvc.$inject = ['OvsdbRestangular', 'nodeIdentifier', 'ovsNodeKeys', 'bridgeNodeKeys', 'tpKeys', 'flowInfoKeys', 'linkIdentifier', '$q', '$http', 'CacheFactory'];
+
+ var NeutronSvc = function(NeutronRestangular, CacheFactory, $q, $http) {
+ var svc = {
+ base: function(type) {
+ return NeutronRestangular.one(type);
+ }
+ },
+ tenant_hash = {};
+
+ function fetchSubNetworks(cb) {
+ var subnetskDefer = svc.base('subnets').getList();
+ subnetskDefer.then(function(data) {
+ var subnets = data,
+ subnetHash = {};
+
+ if (!subnets || !subnets.subnets) {
+ throw new Error('Invalid format from neutron subnets');
+ }
+
+ _.each(subnets.subnets, function(subnet) {
+ if (!subnetHash[subnet.network_id]) {
+ subnetHash[subnet.network_id] = [];
+ }
+ tenant_hash[subnet.tenant_id] = {};
+ subnetHash[subnet.network_id].push(new OvsCore.Neutron.SubNet(
+ subnet.id,
+ subnet.network_id,
+ subnet.name,
+ subnet.ip_version,
+ subnet.cidr,
+ subnet.gateway_ip,
+ subnet.tenant_id
+ ));
+ });
+ cb(subnetHash);
+ });
+ }
+
+ function fetchNetworks(cb) {
+ var networkDefer = svc.base('networks').getList();
+ var subnetskDefer = svc.getSubNets();
+
+ $q.all([subnetskDefer, networkDefer]).then(function(datas) {
+ var subnetsHash = datas[0],
+ networks = datas[1],
+ networkArray = [];
+
+ if (!networks || !networks.networks) {
+ throw new Error('Invalid format from neutron networks');
+ }
+
+ _.each(networks.networks, function(network) {
+ var net = new OvsCore.Neutron.Network(
+ network.id,
+ network.name,
+ network.shared,
+ network.status,
+ network['router:external'],
+ network.tenant_id
+ );
+ tenant_hash[net.tenantId] = {};
+ net.addSubNets(subnetsHash[net.id]);
+ networkArray.push(net);
+ });
+ cb(networkArray);
+ });
+ }
+
+ function fetchRouters(cb) {
+ var routerDefer = svc.base('routers').getList();
+ routerDefer.then(function(data) {
+ var routers = data.routers,
+ routerArray = [];
+
+ if (!routers) {
+ throw new Error('Invalid format from neutron routers');
+ }
+ _.each(routers, function(router) {
+ var id = router.id,
+ name = router.name,
+ status = router.status,
+ tenantId = router.tenant_id,
+ extGateWayInfo = router.external_gateway_info;
+ tenant_hash[tenantId] = {};
+ routerArray.push(new OvsCore.Neutron.Router(
+ id, name, status, tenantId, extGateWayInfo
+ ));
+ });
+ cb(routerArray);
+ });
+ }
+
+ function fetchPorts(cb) {
+ var portDefer = svc.base('ports').getList();
+ portDefer.then(function(data){
+ var ports = data.ports,
+ portArray = [];
+
+ if (!ports) {
+ throw new Error('Invalid format from neutron ports');
+ }
+ _.each(ports, function(port) {
+ tenant_hash[port.tenant_id] = {};
+ portArray.push(new OvsCore.Neutron.Port(
+ port.id,
+ port.network_id,
+ port.name,
+ port.tenant_id,
+ port.device_id,
+ port.device_owner,
+ port.fixed_ips,
+ port.mac_address
+ ));
+ });
+ cb(portArray);
+ });
+ }
+
+ function fetchFloatingIps(cb) {
+ var floatingIpDefer = svc.base('floatingips').getList();
+ floatingIpDefer.then(function(data) {
+ var floatingIps = data.floatingips,
+ floatingIpArray = [];
+
+ if (!floatingIps) {
+ throw new Error('Invalid format from neutron floatingIps');
+ }
+
+ _.each(floatingIps, function(fIp) {
+ tenant_hash[fIp.tenant_id] = {};
+ floatingIpArray.push(new OvsCore.Neutron.FloatingIp(
+ fIp.id,
+ fIp.floating_network_id,
+ fIp.port_id,
+ fIp.fixed_ip_address,
+ fIp.floating_ip_address,
+ fIp.tenant_id,
+ fIp.status
+ ));
+ });
+
+ cb(floatingIpArray);
+ });
+ }
+
+ svc.getNetworks = function() {
+ return CacheFactory.obtainDataFromCache('networks', fetchNetworks, this);
+ };
+
+ svc.getSubNets = function() {
+ return CacheFactory.obtainDataFromCache('subnet', fetchSubNetworks, this);
+ };
+
+ svc.getPorts = function() {
+ return CacheFactory.obtainDataFromCache('ports', fetchPorts, this);
+ };
+
+ svc.getRouters = function() {
+ return CacheFactory.obtainDataFromCache('routers', fetchRouters, this);
+ };
+
+ svc.getFloatingIps = function() {
+ return CacheFactory.obtainDataFromCache('floatingips', fetchFloatingIps, this);
+ };
+
+ svc.getAllTenants = function() {
+ return Object.keys(tenant_hash);
+ };
+
+ return svc;
+ };
+ NeutronSvc.$inject = ['NeutronRestangular', 'CacheFactory', '$q', '$http'];
+
+ var OvsUtil = function(NeutronSvc, TopologySvc, CacheFactory, $q) {
+ var svc = {};
+
+ function findOvsdbNodeForBridge(ovsdbNodes, bridge) {
+ return _.find(ovsdbNodes, function(node) {
+ return bridge.nodeId.indexOf(node.nodeId) > -1;
+ });
+ }
+
+ function pileUpTopologyData(cb) {
+ var networksDefer = NeutronSvc.getNetworks(),
+ routersDefer = NeutronSvc.getRouters(),
+ portsDefer = NeutronSvc.getPorts(),
+ floatingDefer = NeutronSvc.getFloatingIps(),
+ netTopoDefer = TopologySvc.getTopologies();
+
+ $q.all([networksDefer, routersDefer, portsDefer, floatingDefer, netTopoDefer]).then(function (datas) {
+ var networks = datas[0],
+ routers = datas[1],
+ ports = datas[2],
+ floatingIps = datas[3],
+ topo = datas[4];
+
+ // match ports with elements
+ _.each(ports, function(port) {
+ port.topoInfo = [];
+ // corelate port.topoInfo data with network topology termination point
+ _.each(topo.bridgeNodes, function(bridge) {
+ _.each(bridge.tPs, function(tp) {
+ if (tp.ifaceId === port.id) {
+ port.topoInfo.push({
+ name : tp.name,
+ ofPort : tp.ofPort,
+ mac : bridge.dpIp,
+ bridge : bridge,
+ ovsNode : findOvsdbNodeForBridge(topo.ovsdbNodes, bridge)
+ });
+ }
+ });
+ });
+
+ switch(port.deviceOwner) {
+ case 'network:router_gateway':
+ case 'network:router_interface':
+ var router = _.find(routers, function(r) { return r.id === port.deviceId; });
+ if (router) {
+ router.interfaces.push({
+ id: port.id,
+ networkId : port.networkId,
+ ip : port.fixed_ips[0],
+ mac : port.mac,
+ type: port.deviceOwner.replace('network:', ''),
+ tenantId : port.tenantId,
+ topoInfo: port.topoInfo
+ });
+ }
+ break;
+ case 'compute:None':
+ case 'compute:nova':
+ case 'network:dhcp':
+ var network = _.find(networks, function(n) { return n.id === port.networkId;}),
+ inst = null;
+
+ if (network) {
+ inst = new OvsCore.Neutron.Instance(port.id, port.networkId,
+ port.name, port.fixed_ips[0].ip_address, port.mac,
+ port.deviceOwner, port.tenantId, port.topoInfo );
+
+ inst.extractFloatingIps(floatingIps);
+ network.instances.push(inst);
+ }
+ break;
+ }
+
+ });
+
+ // find all routers for a specific network
+ _.each(networks, function(network) {
+ network.routers = _.filter(routers, function(router) {
+ return network.id === router.externalGateway.network_id;
+ });
+
+ // order instance by ip
+ network.instances.sort(function(a, b) {
+ var ipA = a.ip.slice(a.ip.lastIndexOf('.') + 1),
+ ipB = b.ip.slice(b.ip.lastIndexOf('.') + 1);
+ return ipA - ipB;
+ });
+ });
+
+ cb(networks);
+ });
+ }
+
+ svc.getLogicalTopology = function() {
+ return CacheFactory.obtainDataFromCache('logicalTopology', pileUpTopologyData, this);
+ };
+
+ svc.extractLogicalByTenant = function(tenantId, subSet) {
+ var lTopoDefer = svc.getLogicalTopology(),
+ resultDefer = $q.defer();
+ lTopoDefer.then(function() {
+ var ports = CacheFactory.getCacheObj('ports').obj,
+ filteredPorts = _.filter(ports, function(p) {
+ return p.tenantId === tenantId;
+ });
+
+ if (!_.isEmpty(filteredPorts)) {
+ var bridgeHash = {};
+ _.each(filteredPorts, function(p) {
+ if (!_.isEmpty(p.topoInfo) && !bridgeHash[p.topoInfo[0].bridge.nodeId]) {
+ bridgeHash[p.topoInfo[0].bridge.nodeId] = {};
+ }
+ });
+ var ovsdbHash = {};
+ _.each(filteredPorts, function(p) {
+ if (!_.isEmpty(p.topoInfo) && !ovsdbHash[p.topoInfo[0].ovsNode.nodeId]) {
+ ovsdbHash[p.topoInfo[0].ovsNode.nodeId] = {};
+ }
+ });
+
+ resultDefer.resolve([Object.keys(bridgeHash), Object.keys(ovsdbHash)]);
+ } else {
+ resultDefer.resolve([], []);
+ }
+ });
+ return resultDefer.promise;
+ };
+
+ svc.extractLogicalBySubnet = function(subnets, subSet) {
+ var lTopoDefer = svc.getLogicalTopology(),
+ resultDefer = $q.defer();
+ lTopoDefer.then(function() {
+ var ports = CacheFactory.getCacheObj('ports').obj,
+ networks = CacheFactory.getCacheObj('networks').obj;
+
+ var filteredPorts = _.filter(ports, function(p) {
+ var net = _.find(networks, function(d) {
+ return d.id === p.networkId;
+ });
+
+ return net.asSubnet(subnets);
+ });
+ if (!_.isEmpty(filteredPorts)) {
+ var bridgeHash = {};
+ _.each(filteredPorts, function(p) {
+ if (!_.isEmpty(p.topoInfo) && !bridgeHash[p.topoInfo[0].bridge.nodeId]) {
+ bridgeHash[p.topoInfo[0].bridge.nodeId] = {};
+ }
+ });
+ var ovsdbHash = {};
+ _.each(filteredPorts, function(p) {
+ if (!_.isEmpty(p.topoInfo) && !ovsdbHash[p.topoInfo[0].ovsNode.nodeId]) {
+ ovsdbHash[p.topoInfo[0].ovsNode.nodeId] = {};
+ }
+ });
+ resultDefer.resolve([Object.keys(bridgeHash), Object.keys(ovsdbHash)]);
+ } else {
+ resultDefer.resolve([], []);
+ }
+ });
+ return resultDefer.promise;
+ };
+
+ return svc;
+ };
+
+ OvsUtil.$inject = ['NeutronSvc', 'TopologySvc', 'CacheFactory', '$q'];
+
+ ovsdb.register.factory('TopologySvc', TopologySvc);
+ ovsdb.register.factory('NeutronSvc', NeutronSvc);
+ ovsdb.register.factory('OvsUtil', OvsUtil);
+});
+++ /dev/null
-define(['ovsdb/ovsdb.controller'], function() {
- describe('A fake test', function() {
- it('Should be retuning true', function() {
- expect(true).toBe(true);
- });
- });
-});
--- /dev/null
+<!-- <div id="graph_header">
+ <span style="color:black; margin-left:15px;">Network Visualizer</span>
+ <i class="icon-fullscreen" style="float:right;" ng-click="resizeGraph()"></i>
+ <i class="icon-resize-small icon-2" style="float:right" ng-click="minimizeGraph()"></i>
+</div>
+-->
+
+<div id="graph_summary" data-option="false" data-title="Network Summary" nv-window style="text-align:center;">
+ <p style="font-style:italic;">{{nbOpenFlowSwitch}} brides
+ <br/> {{nbOvsNode}} switch</p>
+</div>
--- /dev/null
+<!--\r
+ * Copyright (c) 2015 Inocybe Technologies and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+-->\r
+<div id="ovsdb_contain">\r
+<!--\r
+<div class="row">\r
+ <div class="col-md-2 form-inline">\r
+ <label class="switch-light well">\r
+ <input type="checkbox" ng-model="opt.layer" ng-change="toggleLayer();">\r
+ <span>\r
+ Layer 3\r
+ <span>Off</span>\r
+ <span>On</span>\r
+ </span>\r
+\r
+ <a class="btn btn-orange"></a>\r
+ </label>\r
+ </div>\r
+ <div class="col-md-2 form-inline">\r
+ <label class="switch-light well">\r
+ <input type="checkbox" ng-model="opt.underlay" ng-change="toggleUnderlay();">\r
+ <span>\r
+ Underlay\r
+ <span>Off</span>\r
+ <span>On</span>\r
+ </span>\r
+\r
+ <a class="btn btn-orange"></a>\r
+ </label>\r
+ </div>\r
+</div>\r
+-->\r
+<div class="row">\r
+ <div class="col-md-12">\r
+ <div id="tabs" >\r
+ <ul class="nav nav-tabs tabsHeader" style="margin-bottom:15px;">\r
+ <li><a href="#logical_view">Logical View</a></li>\r
+ <li><a href="#2d_view">2D View</a></li>\r
+ <li><a href="#3d_view">3D View</a></li>\r
+ </ul>\r
+ <div id="logical_view" style="background-color:white; position:relative;">\r
+ <div id="l_graph" style="position:relative; height:580px;" logical-graph ></div>\r
+\r
+ <div id="lDialog" class="ovsDialog arrow-left">\r
+ <div style="height:10px;">\r
+ <i data-ng-click="hideLogicalDialog()" class="window-icon icon-remove"></i>\r
+ </div>\r
+ <div class="window_content">\r
+ <ul class="nav nav-tabs tabsHeader">\r
+ <li ng-repeat="tab in lDialogData.tabs track by $index" >\r
+ <a href="#lDialogTab_{{$index}}" class="active">{{tab}}</a>\r
+ </li>\r
+ </ul>\r
+ <div ng-repeat="tabContaint in lDialogData.containts track by $index" id="lDialogTab_{{$index}}">\r
+ <table ng-if="!tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+ <tr ng-repeat="info in tabContaint.datas track by $index">\r
+ <td > {{info.key}} </td> <td> {{ info.value }} </td>\r
+ </tr>\r
+ </table>\r
+ <table ng-if="tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+ <tr>\r
+ <th ng-repeat=" h in tabContaint.header track by $index">{{h}}</th>\r
+ </tr>\r
+ <tr ng-repeat="item in tabContaint.datas track by $index">\r
+ <td ng-repeat="value in item track by $index"> {{ value }} </td>\r
+ </tr>\r
+ </table>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+ </div>\r
+ <div id="2d_view">\r
+ <div class="row">\r
+ <div class="col-md-4 col-md-offset-1 form-inline">\r
+ <span>Tenant</span>\r
+ <select id="tenantSelect" ng-model="selectedTenant" ng-change="fiterByTenant()" ng-options="tenant.name for tenant in tenants track by tenant.id">\r
+ <option value="">---All---</option>\r
+ </select>\r
+ </div>\r
+ <div class="col-md-4 form-inline">\r
+ <span>Subnet</span>\r
+ <select id="tagPicker" multiple="multiple" ng-model="selectedSubnet" ng-change="filterBySubnet()" ng-options="subnet.name for subnet in subnets track by subnet.id">\r
+ </select>\r
+ </div>\r
+ </div>\r
+ <div id="nv_graph" style="position:relative; height:580px;" physical-graph></div>\r
+ <div id="pDialog" class="ovsDialog arrow-left">\r
+ <div style="height:10px">\r
+ <i data-ng-click="hidePhysicalDialog()" class="window-icon icon-remove"></i>\r
+ </div>\r
+ <div class="window_content">\r
+ <ul class="nav nav-tabs tabsHeader">\r
+ <li ng-repeat="tab in pDialogData.tabs track by $index" >\r
+ <a href="#pDialogTab_{{$index}}" class="active">{{tab}}</a>\r
+ </li>\r
+ </ul>\r
+ <div ng-repeat="tabContaint in pDialogData.containts track by $index" id="pDialogTab_{{$index}}">\r
+ <table ng-if="!tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+ <tr ng-repeat="info in tabContaint.datas track by $index">\r
+ <td > {{info.key}} </td> <td> {{ info.value }} </td>\r
+ </tr>\r
+ </table>\r
+ <table ng-if="tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+ <tr>\r
+ <th ng-repeat=" h in tabContaint.header track by $index">{{h}}</th>\r
+ </tr>\r
+ <tr ng-repeat="item in tabContaint.datas track by $index">\r
+ <td ng-repeat="value in item track by $index"> {{ value }} </td>\r
+ </tr>\r
+ </table>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+ </div>\r
+ <!-- <div id="3d_view">\r
+ </div> -->\r
+ </div><!-- tab -->\r
+</div>\r
-<!--
-* Copyright (c) 2015 Inocybe Technologies 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
--->
-<div class="main" ui-view></div>
+<!--\r
+* Copyright (c) 2015 Inocybe Technologies and others. All rights reserved.\r
+*\r
+* This program and the accompanying materials are made available under the\r
+* terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+* and is available at http://www.eclipse.org/legal/epl-v10.html\r
+-->\r
+<div class="main" ui-view></div>\r
--- /dev/null
+{
+ "id": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "name": "NetvirtSfc",
+ "requests": [
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"http-acl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"http-rule\",\n \"matches\": {\n \"destination-port-range\": {\n \"lower-port\": \"80\",\n \"upper-port\": \"80\"\n }\n },\n \"actions\": {\n \"netvirt-sfc-acl:redirect-sfc\": \"acl\"\n }\n }\n ]\n }\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Content-Type: application/json\n",
+ "id": "19b44f74-e2ea-9267-50af-ad79b6309859",
+ "method": "PUT",
+ "name": "ietf-acl redirect-sfc",
+ "time": 1445298337983,
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"service-function-forwarders\": {\n \"service-function-forwarder\": [\n {\n \"name\": \"SFF1\",\n \"service-node\": \"OVSDB2\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"sw2\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"firewall-72\",\n \"type\": \"service-function-type:firewall\",\n \"sff-sf-data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.71\",\n \"transport\": \"service-locator:vxlan-gpe\"\n }\n }\n ],\n \"sff-data-plane-locator\": [\n {\n \"name\": \"sfc-tun2\",\n \"data-plane-locator\": {\n \"transport\": \"service-locator:vxlan-gpe\",\n \"port\": 6633,\n \"ip\": \"192.168.50.71\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"remote-ip\": \"flow\",\n \"dst-port\": \"6633\",\n \"key\": \"flow\",\n \"nsp\": \"flow\",\n \"nsi\": \"flow\",\n \"nshc1\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc4\": \"flow\"\n }\n }\n ]\n },\n {\n \"name\": \"SFF2\",\n \"service-node\": \"OVSDB2\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"sw4\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"dpi-74\",\n \"type\": \"service-function-type:dpi\",\n \"sff-sf-data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.73\",\n \"transport\": \"service-locator:vxlan-gpe\"\n }\n }\n ],\n \"sff-data-plane-locator\": [\n {\n \"name\": \"sfc-tun4\",\n \"data-plane-locator\": {\n \"transport\": \"service-locator:vxlan-gpe\",\n \"port\": 6633,\n \"ip\": \"192.168.50.73\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"remote-ip\": \"flow\",\n \"dst-port\": \"6633\",\n \"key\": \"flow\",\n \"nsp\": \"flow\",\n \"nsi\": \"flow\",\n \"nshc1\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc4\": \"flow\"\n }\n }\n ]\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "id": "1b067065-f0d5-d871-28cf-5e7e195eb463",
+ "method": "PUT",
+ "name": "service-function-forwarders",
+ "time": 1445302610648,
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"http-acl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"http-rule\",\n \"matches\": {\n \"destination-port-range\": {\n \"lower-port\": \"80\",\n \"upper-port\": \"80\"\n }\n },\n \"actions\": {\n \"permit\": \"true\"\n\n }\n }\n ]\n }\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Content-Type: application/json\n",
+ "id": "62e3b4d9-2672-e2bd-25c9-70bfb6771026",
+ "method": "PUT",
+ "name": "ietf-acl",
+ "time": 1445298397905,
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"classifiers\": {\n \"classifier\": [\n {\n \"name\": \"http-classifier\",\n \"acl\": \"http-acl\",\n \"sffs\": {\n \"sff\": [\n {\n \"name\": \"sff1\"\n }\n ]\n }\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "id": "718ed9fd-f7f3-3862-4a53-b12d83c880ae",
+ "method": "PUT",
+ "name": "Classifier",
+ "time": 1444924721709,
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/netvirt-sfc-classifier:classifiers",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"http-acl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"http-rule\",\n \"matches\": {\n \"destination-port-range\": {\n \"lower-port\": \"80\",\n \"upper-port\": \"80\"\n }\n },\n \"actions\": {\n \"permit\": {}\n }\n }\n ]\n }\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Content-Type: application/json\n",
+ "id": "7412ee0c-b116-5cf1-0646-efa65f0da784",
+ "method": "GET",
+ "name": "ietf-acl",
+ "responses": [],
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"classifiers\": {\n \"classifier\": [\n {\n \"name\": \"http-classifier\",\n \"acl\": \"http-acl\",\n \"sffs\": {\n \"sff\": [\n {\n \"name\": \"sff1\"\n }\n ]\n }\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "id": "76b32432-5a24-9d6d-8ba2-76eb816411af",
+ "method": "DELETE",
+ "name": "Classifier",
+ "responses": [],
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/netvirt-sfc-classifier:classifiers",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"access-lists\": {\n \"acl\": [\n {\n \"acl-name\": \"http-acl\",\n \"access-list-entries\": {\n \"ace\": [\n {\n \"rule-name\": \"http-rule\",\n \"matches\": {\n \"destination-port-range\": {\n \"lower-port\": \"80\",\n \"upper-port\": \"80\"\n }\n },\n \"actions\": {\n \"netvirt-sfc-acl:redirect-sfc\": \"acl\"\n }\n }\n ]\n }\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Content-Type: application/json\n",
+ "id": "99dc6bb5-f01a-64cd-a024-c333fdf82643",
+ "method": "DELETE",
+ "name": "ietf-acl redirect-sfc",
+ "responses": [],
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n\t\"sfc\": {\n \"name\": \"sfc1\"\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "id": "9d418a4b-197d-47c2-e85f-e68f6b5f5c40",
+ "method": "GET",
+ "name": "Sfc",
+ "responses": [],
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/netvirt-sfc:sfc/",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"classifiers\": {\n \"classifier\": [\n {\n \"name\": \"http-classifier\",\n \"acl\": \"http-acl\",\n \"sffs\": {\n \"sff\": [\n {\n \"name\": \"sff1\"\n }\n ]\n }\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "id": "b2d13061-80e0-ad8f-d0e6-d6939ea2b0a4",
+ "method": "GET",
+ "name": "Classifier",
+ "responses": [],
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/netvirt-sfc-classifier:classifiers",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"service-functions\": {\n \"service-function\": [\n {\n \"name\": \"firewall-72\",\n \"ip-mgmt-address\": \"192.168.50.72\",\n \"type\": \"service-function-type:firewall\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"2\",\n \"port\": 6633,\n \"ip\": \"192.168.50.72\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-forwarder\": \"SFF1\"\n }\n ]\n },\n {\n \"name\": \"dpi-74\",\n \"ip-mgmt-address\": \"192.168.50.74\",\n \"type\": \"service-function-type:dpi\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"3\",\n \"port\": 6633,\n \"ip\": \"192.168.50.74\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-forwarder\": \"SFF2\"\n }\n ]\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "id": "bf4f1148-5192-fd7d-3026-5a11668db75d",
+ "method": "PUT",
+ "name": "service-functions",
+ "time": 1445302596335,
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/service-function:service-functions",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"service-function-forwarders\": {\n \"service-function-forwarder\": [\n {\n \"name\": \"SFF1\",\n \"service-node\": \"OVSDB2\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"sw2\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"firewall-72\",\n \"type\": \"service-function-type:firewall\",\n \"sff-sf-data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.71\",\n \"transport\": \"service-locator:vxlan-gpe\"\n }\n }\n ],\n \"sff-data-plane-locator\": [\n {\n \"name\": \"sfc-tun2\",\n \"data-plane-locator\": {\n \"transport\": \"service-locator:vxlan-gpe\",\n \"port\": 6633,\n \"ip\": \"192.168.50.71\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"remote-ip\": \"flow\",\n \"dst-port\": \"6633\",\n \"key\": \"flow\",\n \"nsp\": \"flow\",\n \"nsi\": \"flow\",\n \"nshc1\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc4\": \"flow\"\n }\n }\n ]\n },\n {\n \"name\": \"SFF2\",\n \"service-node\": \"OVSDB2\",\n \"service-function-forwarder-ovs:ovs-bridge\": {\n \"bridge-name\": \"sw4\"\n },\n \"service-function-dictionary\": [\n {\n \"name\": \"dpi-74\",\n \"type\": \"service-function-type:dpi\",\n \"sff-sf-data-plane-locator\": {\n \"port\": 6633,\n \"ip\": \"192.168.50.73\",\n \"transport\": \"service-locator:vxlan-gpe\"\n }\n }\n ],\n \"sff-data-plane-locator\": [\n {\n \"name\": \"sfc-tun4\",\n \"data-plane-locator\": {\n \"transport\": \"service-locator:vxlan-gpe\",\n \"port\": 6633,\n \"ip\": \"192.168.50.73\"\n },\n \"service-function-forwarder-ovs:ovs-options\": {\n \"remote-ip\": \"flow\",\n \"dst-port\": \"6633\",\n \"key\": \"flow\",\n \"nsp\": \"flow\",\n \"nsi\": \"flow\",\n \"nshc1\": \"flow\",\n \"nshc2\": \"flow\",\n \"nshc3\": \"flow\",\n \"nshc4\": \"flow\"\n }\n }\n ]\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "id": "e6542ed1-832c-71c9-fe74-2d25c9e7f7ad",
+ "method": "GET",
+ "name": "service-function-forwarders",
+ "responses": [],
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n\t\"sfc\": {\n \"name\": \"sfc1\"\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "id": "ea1c70a0-6528-862c-cabc-a9b187d483c7",
+ "method": "PUT",
+ "name": "Sfc",
+ "responses": [],
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/netvirt-sfc:sfc/",
+ "version": 2
+ },
+ {
+ "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+ "data": "{\n \"service-functions\": {\n \"service-function\": [\n {\n \"name\": \"firewall-72\",\n \"ip-mgmt-address\": \"192.168.50.72\",\n \"type\": \"service-function-type:firewall\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"2\",\n \"port\": 6633,\n \"ip\": \"192.168.50.72\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-forwarder\": \"SFF1\"\n }\n ]\n },\n {\n \"name\": \"dpi-74\",\n \"ip-mgmt-address\": \"192.168.50.74\",\n \"type\": \"service-function-type:dpi\",\n \"nsh-aware\": \"true\",\n \"sf-data-plane-locator\": [\n {\n \"name\": \"3\",\n \"port\": 6633,\n \"ip\": \"192.168.50.74\",\n \"transport\": \"service-locator:vxlan-gpe\",\n \"service-function-forwarder\": \"SFF2\"\n }\n ]\n }\n ]\n }\n}",
+ "dataMode": "raw",
+ "description": "",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "id": "fff50fa7-aa2d-71a4-db49-4ea10b82937e",
+ "method": "GET",
+ "name": "service-functions",
+ "responses": [],
+ "timestamp": 0,
+ "url": "http://localhost:8181/restconf/config/service-function:service-functions",
+ "version": 2
+ }
+ ],
+ "timestamp": 1444922427094
+}
- 3-Node-Cluster-Setup-Environment-Variables.postman_environment : Postman environment file that defines variables for Restconf request for southbound plugin running in 3 node cluster environment
-
+- NetvirtSfc.json.postman_collection : Collection of REST-APIs to interact with Netvirt-Sfc.
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
//register instance entity to get the ownership of the provider
Entity instanceEntity = new Entity(ENTITY_TYPE, ENTITY_TYPE);
try {
+ Optional<EntityOwnershipState> ownershipStateOpt = entityOwnershipService.getOwnershipState(instanceEntity);
registration = entityOwnershipService.registerCandidate(instanceEntity);
+ if (ownershipStateOpt.isPresent()) {
+ EntityOwnershipState ownershipState = ownershipStateOpt.get();
+ if (ownershipState.hasOwner() && !ownershipState.isOwner()) {
+ if (ovsdbConnection == null) {
+ ovsdbConnection = new OvsdbConnectionService();
+ ovsdbConnection.registerConnectionListener(cm);
+ ovsdbConnection.startOvsdbManager(SouthboundConstants.DEFAULT_OVSDB_PORT);
+ }
+ }
+ }
} catch (CandidateAlreadyRegisteredException e) {
LOG.warn("OVSDB Southbound Provider instance entity {} was already "
+ "registered for {} ownership", instanceEntity, e);
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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;
import static org.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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;
import static org.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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;
import static org.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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;
import static org.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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;
import static org.mockito.Matchers.any;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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;
import static org.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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;
import static org.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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;
import static org.mockito.Matchers.any;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
when(entityOwnershipService.registerListener(anyString(), any(EntityOwnershipListener.class))).thenReturn(mock(EntityOwnershipListenerRegistration.class));
when(entityOwnershipService.registerCandidate(any(Entity.class))).thenReturn(registration);
+ EntityOwnershipState entityOwnershipState = mock(EntityOwnershipState.class);
+ when(entityOwnershipService.getOwnershipState(any(Entity.class))).thenReturn(Optional.of(entityOwnershipState));
southboundProvider.onSessionInitiated(session);
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.mockito.Matchers.any;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.*;
-import static org.mockito.Matchers.*;
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.HashMap;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
-import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
import org.opendaylight.ovsdb.schema.openvswitch.Manager;
import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.*;
-import static org.mockito.Matchers.*;
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.HashMap;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
-import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
-import org.opendaylight.ovsdb.schema.openvswitch.Controller;
import org.opendaylight.ovsdb.schema.openvswitch.Manager;
import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
import org.opendaylight.ovsdb.southbound.SouthboundMapper;
import org.opendaylight.ovsdb.southbound.SouthboundUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.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.ovsdb.bridge.attributes.ControllerEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntryKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.powermock.api.mockito.PowerMockito;
-import org.powermock.api.support.membermodification.MemberMatcher;
import org.powermock.api.support.membermodification.MemberModifier;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.*;
--- /dev/null
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.Column;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+import org.opendaylight.ovsdb.schema.openvswitch.Port;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+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.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+@PrepareForTest({TyperUtils.class, SouthboundMapper.class, InstanceIdentifier.class})
+@RunWith(PowerMockRunner.class)
+public class OvsdbPortRemoveCommandTest {
+ private static final String PORT_NAME = "port0";
+ private OvsdbPortRemoveCommand ovsdbPortRemoveCommand;
+
+ @Before
+ public void setUp() throws Exception {
+ ovsdbPortRemoveCommand = PowerMockito.mock(OvsdbPortRemoveCommand.class, Mockito.CALLS_REAL_METHODS);
+ }
+
+ @Test
+ public void testOvsdbPortRemoveCommandTest() {
+ OvsdbConnectionInstance key = mock(OvsdbConnectionInstance.class);
+ TableUpdates updates = mock(TableUpdates.class);
+ DatabaseSchema dbSchema = mock(DatabaseSchema.class);
+ OvsdbPortRemoveCommand ovsdbPortRemoveCommand1 = new OvsdbPortRemoveCommand(key, updates, dbSchema);
+ assertEquals(key, Whitebox.getInternalState(ovsdbPortRemoveCommand1, "key"));
+ assertEquals(updates, Whitebox.getInternalState(ovsdbPortRemoveCommand1, "updates"));
+ assertEquals(dbSchema, Whitebox.getInternalState(ovsdbPortRemoveCommand1, "dbSchema"));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testExecute() throws Exception {
+ ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+ when(ovsdbPortRemoveCommand.getUpdates()).thenReturn(mock(TableUpdates.class));
+ when(ovsdbPortRemoveCommand.getDbSchema()).thenReturn(mock(DatabaseSchema.class));
+ PowerMockito.mockStatic(TyperUtils.class);
+ UUID uuid = mock(UUID.class);
+ Map<UUID, Port> portRemovedRows = new HashMap<>();
+ Port port = mock(Port.class);
+ portRemovedRows.put(uuid, port);
+ when(TyperUtils.extractRowsRemoved(eq(Port.class), any(TableUpdates.class), any(DatabaseSchema.class))).thenReturn(portRemovedRows);
+ Map<UUID, Bridge> bridgeUpdatedRows = new HashMap<>();
+ Bridge updatedBridgeData = mock(Bridge.class);
+ bridgeUpdatedRows.put(uuid, updatedBridgeData);
+ when(TyperUtils.extractRowsUpdated(eq(Bridge.class), any(TableUpdates.class), any(DatabaseSchema.class))).thenReturn(bridgeUpdatedRows);
+ Map<UUID, Bridge> bridgeUpdatedOldRows = new HashMap<>();
+ Bridge oldBridgeData = mock(Bridge.class);
+ bridgeUpdatedOldRows.put(uuid, oldBridgeData);
+ when(TyperUtils.extractRowsOld(eq(Bridge.class), any(TableUpdates.class), any(DatabaseSchema.class))).thenReturn(bridgeUpdatedOldRows);
+
+ Column<GenericTableSchema, Set<UUID>> column = mock(Column.class);
+ when(oldBridgeData.getPortsColumn()).thenReturn(column);
+ Set<UUID> setUUID = new HashSet<>();
+ setUUID.add(uuid);
+ when(column.getData()).thenReturn(setUUID);
+
+ Column<GenericTableSchema, UUID> uuidColumn = mock(Column.class);
+ when(port.getUuidColumn()).thenReturn(uuidColumn);
+ when(uuidColumn.getData()).thenReturn(uuid);
+
+ when(port.getName()).thenReturn(PORT_NAME);
+ PowerMockito.mockStatic(SouthboundMapper.class);
+ InstanceIdentifier<Node> nodeIID = mock(InstanceIdentifier.class);
+ when(ovsdbPortRemoveCommand.getOvsdbConnectionInstance()).thenReturn(mock(OvsdbConnectionInstance.class));
+ when(SouthboundMapper.createInstanceIdentifier(any(OvsdbConnectionInstance.class), any(Bridge.class))).thenReturn(nodeIID);
+ MemberModifier.suppress(MemberModifier.methodsDeclaredIn(InstanceIdentifier.class));
+ doNothing().when(transaction).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+
+ ovsdbPortRemoveCommand.execute(transaction);
+ verify(transaction).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.Column;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+import org.opendaylight.ovsdb.schema.openvswitch.Interface;
+import org.opendaylight.ovsdb.schema.openvswitch.Port;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.ovsdb.southbound.SouthboundUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeInternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
+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.OvsdbPortInterfaceAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes.VlanMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.TrunksBuilder;
+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.TpId;
+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.NodeKey;
+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.TerminationPointBuilder;
+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.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberMatcher;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+@PrepareForTest({TyperUtils.class, OvsdbPortUpdateCommand.class, SouthboundUtil.class, SouthboundMapper.class})
+@RunWith(PowerMockRunner.class)public class OvsdbPortUpdateCommandTest {
+
+ private static final String OTHER_CONFIG_KEY = "key";
+ private static final String OTHER_CONFIG_VALUE = "value";
+ private static final String EXTERNAL_ID_KEY = "key";
+ private static final String EXTERNAL_ID_VALUE = "value";
+ private static final String INTERFACE_NAME = "interface_name";
+ private static final String VLAN_MODE_ACCESS = "access";
+ private static final String OVSDB_INTERFACE_TYPE = "internal";
+ private static final String PORT_NAME = "port_name";
+ private static final String TP_NAME = "tp_name";
+ private static final String TERMINATION_POINT_NAME = "termination_point_name";
+
+ private Map<UUID, Port> portUpdatedRows;
+ private Map<UUID, Port> portOldRows;
+ private Map<UUID, Interface> interfaceUpdatedRows;
+ private Map<UUID, Interface> interfaceOldRows;
+ private Map<UUID, Bridge> bridgeUpdatedRows;
+ private OvsdbPortUpdateCommand ovsdbPortUpdateCommand;
+
+ @Before
+ public void setUp() throws Exception {
+ ovsdbPortUpdateCommand = PowerMockito.mock(OvsdbPortUpdateCommand.class, Mockito.CALLS_REAL_METHODS);
+ }
+
+ @Test
+ public void testOvsdbPortUpdateCommand() throws Exception {
+ OvsdbConnectionInstance key = mock(OvsdbConnectionInstance.class);
+ TableUpdates updates = mock(TableUpdates.class);
+ DatabaseSchema dbSchema = mock(DatabaseSchema.class);
+
+ PowerMockito.mockStatic(TyperUtils.class);
+ PowerMockito.when(TyperUtils.extractRowsUpdated(Port.class, updates, dbSchema)).thenReturn(portUpdatedRows);
+ PowerMockito.when(TyperUtils.extractRowsOld(Port.class, updates, dbSchema)).thenReturn(portOldRows);
+ PowerMockito.when(TyperUtils.extractRowsUpdated(Interface.class, updates, dbSchema)).thenReturn(interfaceUpdatedRows);
+ PowerMockito.when(TyperUtils.extractRowsOld(Interface.class, updates, dbSchema)).thenReturn(interfaceOldRows);
+ PowerMockito.when(TyperUtils.extractRowsUpdated(Bridge.class, updates, dbSchema)).thenReturn(bridgeUpdatedRows);
+
+ OvsdbPortUpdateCommand ovsdbPortUpdateCommand1 = new OvsdbPortUpdateCommand(key, updates, dbSchema);
+ assertEquals(portUpdatedRows, Whitebox.getInternalState(ovsdbPortUpdateCommand1, "portUpdatedRows"));
+ assertEquals(portOldRows, Whitebox.getInternalState(ovsdbPortUpdateCommand1, "portOldRows"));
+ assertEquals(dbSchema, Whitebox.getInternalState(ovsdbPortUpdateCommand1, "dbSchema"));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testExecute() throws Exception {
+ ReadWriteTransaction transaction= mock(ReadWriteTransaction.class);
+ portUpdatedRows = new HashMap<>();
+ interfaceOldRows = new HashMap<>();
+ portUpdatedRows.put(mock(UUID.class), mock(Port.class));
+ interfaceOldRows.put(mock(UUID.class), mock(Interface.class));
+ MemberModifier.field(OvsdbPortUpdateCommand.class, "portUpdatedRows").set(ovsdbPortUpdateCommand, portUpdatedRows);
+ MemberModifier.field(OvsdbPortUpdateCommand.class, "interfaceOldRows").set(ovsdbPortUpdateCommand, interfaceOldRows);
+
+ OvsdbConnectionInstance ovsdbConnectionInstance = mock(OvsdbConnectionInstance.class);
+ when(ovsdbPortUpdateCommand.getOvsdbConnectionInstance()).thenReturn(ovsdbConnectionInstance);
+ InstanceIdentifier<Node> connectionIId = mock(InstanceIdentifier.class);
+ when(ovsdbConnectionInstance.getInstanceIdentifier()).thenReturn(connectionIId);
+
+ //case 1: portUpdatedRows & interfaceOldRows not null, not empty
+ Optional<Node> node = mock(Optional.class);
+ PowerMockito.doReturn(node).when(ovsdbPortUpdateCommand, "readNode", any(ReadWriteTransaction.class), any(InstanceIdentifier.class));
+ when(node.isPresent()).thenReturn(true);
+ when(node.get()).thenReturn(mock(Node.class));
+ PowerMockito.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateTerminationPoints", ReadWriteTransaction.class, Node.class));
+ ovsdbPortUpdateCommand.execute(transaction);
+ verify(ovsdbConnectionInstance).getInstanceIdentifier();
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateTerminationPoints", any(ReadWriteTransaction.class), any(Node.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateTerminationPoints() throws Exception {
+ ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+ Node node = mock(Node.class);
+
+ portUpdatedRows = new HashMap<>();
+ Port port = mock(Port.class);
+ UUID uuid = mock(UUID.class);
+ portUpdatedRows.put(uuid, port);
+ MemberModifier.field(OvsdbPortUpdateCommand.class, "portUpdatedRows").set(ovsdbPortUpdateCommand, portUpdatedRows);
+ Column<GenericTableSchema, String> bridgeColumn = mock(Column.class);
+ when(port.getNameColumn()).thenReturn(bridgeColumn);
+ when(bridgeColumn.getData()).thenReturn(TERMINATION_POINT_NAME);
+
+ Optional<InstanceIdentifier<Node>> bridgeIid = mock(Optional.class);
+ PowerMockito.doReturn(bridgeIid).when(ovsdbPortUpdateCommand, "getTerminationPointBridge", any(UUID.class));
+
+ //bridgeIid.isPresent() is true
+ when(bridgeIid.isPresent()).thenReturn(true);
+ when(bridgeIid.get()).thenReturn(mock(InstanceIdentifier.class));
+ NodeId bridgeId = mock(NodeId.class);
+ PowerMockito.mockStatic(SouthboundMapper.class);
+ PowerMockito.when(SouthboundMapper.createManagedNodeId(any(InstanceIdentifier.class))).thenReturn(bridgeId);
+
+ PowerMockito.whenNew(TpId.class).withAnyArguments().thenReturn(mock(TpId.class));
+ TerminationPointKey tpKey = mock(TerminationPointKey.class);
+ PowerMockito.whenNew(TerminationPointKey.class).withAnyArguments().thenReturn(tpKey);
+ TerminationPointBuilder tpBuilder = mock(TerminationPointBuilder.class);
+ PowerMockito.whenNew(TerminationPointBuilder.class).withNoArguments().thenReturn(tpBuilder);
+ when(tpBuilder.setKey(any(TerminationPointKey.class))).thenReturn(tpBuilder);
+ when(tpKey.getTpId()).thenReturn(mock(TpId.class));
+ when(tpBuilder.setTpId(any(TpId.class))).thenReturn(tpBuilder);
+ InstanceIdentifier<TerminationPoint> tpPath = mock(InstanceIdentifier.class);
+ PowerMockito.doReturn(tpPath).when(ovsdbPortUpdateCommand, "getInstanceIdentifier", any(InstanceIdentifier.class), any(Port.class));
+
+ OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ PowerMockito.whenNew(OvsdbTerminationPointAugmentationBuilder.class).withNoArguments().thenReturn(tpAugmentationBuilder);
+ PowerMockito.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "buildTerminationPoint", OvsdbTerminationPointAugmentationBuilder.class, Port.class));
+
+ Column<GenericTableSchema, Set<UUID>> interfacesColumn = mock(Column.class);
+ when(port.getInterfacesColumn()).thenReturn(interfacesColumn);
+ Set<UUID> setUUID = new HashSet<>();
+ UUID interfaceUUID = mock(UUID.class);
+ setUUID.add(interfaceUUID);
+ when(interfacesColumn.getData()).thenReturn(setUUID);
+
+ interfaceUpdatedRows = new HashMap<>();
+ interfaceOldRows = new HashMap<>();
+ Interface iface = mock(Interface.class);
+ interfaceUpdatedRows.put(interfaceUUID, iface);
+ Interface interfaceUpdate = mock(Interface.class);
+ interfaceUpdatedRows.put(uuid, interfaceUpdate);
+ interfaceOldRows.put(interfaceUUID, iface);
+ MemberModifier.field(OvsdbPortUpdateCommand.class, "interfaceUpdatedRows").set(ovsdbPortUpdateCommand, interfaceUpdatedRows);
+ MemberModifier.field(OvsdbPortUpdateCommand.class, "interfaceOldRows").set(ovsdbPortUpdateCommand, interfaceOldRows);
+ PowerMockito.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "buildTerminationPoint", OvsdbTerminationPointAugmentationBuilder.class, Interface.class));
+
+ when(tpAugmentationBuilder.build()).thenReturn(mock(OvsdbTerminationPointAugmentation.class));
+ when(tpBuilder.addAugmentation(eq(OvsdbTerminationPointAugmentation.class), any(OvsdbTerminationPointAugmentation.class))).thenReturn(tpBuilder);
+ when(tpBuilder.build()).thenReturn(mock(TerminationPoint.class));
+ portOldRows = new HashMap<>();
+ portOldRows.put(uuid, port);
+ MemberModifier.field(OvsdbPortUpdateCommand.class, "portOldRows").set(ovsdbPortUpdateCommand, portOldRows);
+ doNothing().when(transaction).merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(TerminationPoint.class));
+ doNothing().when(transaction).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(TerminationPoint.class));
+
+ Column<GenericTableSchema, String> interfaceColumn = mock(Column.class);
+ when(interfaceUpdate.getNameColumn()).thenReturn(interfaceColumn);
+ when(interfaceColumn.getData()).thenReturn(INTERFACE_NAME);
+
+ PowerMockito.doReturn(bridgeIid).when(ovsdbPortUpdateCommand, "getTerminationPointBridge", any(ReadWriteTransaction.class), any(Node.class), anyString());
+ PowerMockito.when(SouthboundMapper.createManagedNodeId(any(InstanceIdentifier.class))).thenReturn(bridgeId);
+ PowerMockito.whenNew(TopologyKey.class).withAnyArguments().thenReturn(mock(TopologyKey.class));
+ PowerMockito.whenNew(NodeKey.class).withAnyArguments().thenReturn(mock(NodeKey.class));
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateTerminationPoints", transaction, node);
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("getInstanceIdentifier", any(OvsdbTerminationPointAugmentationBuilder.class), any(Port.class));
+ verify(transaction, times(2)).merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(TerminationPoint.class));
+ }
+
+ @Test
+ public void testBuildTerminationPoint() throws Exception {
+ OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Port portUpdate = mock(Port.class);
+ when(portUpdate.getName()).thenReturn(PORT_NAME);
+ when(portUpdate.getUuid()).thenReturn(mock(UUID.class));
+ PowerMockito.whenNew(Uuid.class).withAnyArguments().thenReturn(mock(Uuid.class));
+ when(tpAugmentationBuilder.setName(anyString())).thenReturn(tpAugmentationBuilder);
+ when(tpAugmentationBuilder.setPortUuid(any(Uuid.class))).thenReturn(tpAugmentationBuilder);
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updatePort", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "buildTerminationPoint", tpAugmentationBuilder, portUpdate);
+ verify(tpAugmentationBuilder).setName(anyString());
+ verify(tpAugmentationBuilder).setPortUuid(any(Uuid.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updatePort", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ }
+
+ @Test
+ public void testBuildTerminationPoint1() throws Exception {
+ OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Interface interfaceUpdate = mock(Interface.class);
+ when(interfaceUpdate.getName()).thenReturn(INTERFACE_NAME);
+ when(interfaceUpdate.getUuid()).thenReturn(mock(UUID.class));
+ PowerMockito.whenNew(Uuid.class).withAnyArguments().thenReturn(mock(Uuid.class));
+ when(tpAugmentationBuilder.setName(anyString())).thenReturn(tpAugmentationBuilder);
+ when(tpAugmentationBuilder.setInterfaceUuid(any(Uuid.class))).thenReturn(tpAugmentationBuilder);
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateInterfaces", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "buildTerminationPoint", tpAugmentationBuilder, interfaceUpdate);
+ verify(tpAugmentationBuilder).setName(anyString());
+ verify(tpAugmentationBuilder).setInterfaceUuid(any(Uuid.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateInterfaces", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testReadNode() throws Exception {
+ ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+ InstanceIdentifier<Node> nodePath = mock(InstanceIdentifier.class);
+ Optional<Node> node = mock(Optional.class);
+ CheckedFuture<Optional<Node>, ReadFailedException> checkedFuture = mock(CheckedFuture.class);
+ when(transaction.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(checkedFuture);
+ when(checkedFuture.checkedGet()).thenReturn(node);
+ assertEquals(node, Whitebox.invokeMethod(ovsdbPortUpdateCommand, "readNode", transaction, nodePath));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testGetTerminationPointBridge() throws Exception {
+ UUID portUUID = mock(UUID.class);
+ bridgeUpdatedRows = new HashMap<UUID, Bridge>();
+ UUID bridgeUUID = mock(UUID.class);
+ Bridge bridge = mock(Bridge.class);
+ bridgeUpdatedRows.put(bridgeUUID, bridge);
+ MemberModifier.field(OvsdbPortUpdateCommand.class, "bridgeUpdatedRows").set(ovsdbPortUpdateCommand, bridgeUpdatedRows);
+
+ Column<GenericTableSchema, Set<UUID>> column = mock(Column.class);
+ when(bridge.getPortsColumn()).thenReturn(column);
+ Set<UUID> set = new HashSet<>();
+ set.add(portUUID);
+ when(column.getData()).thenReturn(set);
+
+ PowerMockito.mockStatic(SouthboundMapper.class);
+ when(ovsdbPortUpdateCommand.getOvsdbConnectionInstance()).thenReturn(mock(OvsdbConnectionInstance.class));
+ InstanceIdentifier<Node> nodeIid = mock(InstanceIdentifier.class);
+ PowerMockito.when(SouthboundMapper.createInstanceIdentifier(any(OvsdbConnectionInstance.class), any(Bridge.class))).thenReturn(nodeIid);
+
+ Optional<InstanceIdentifier<Node>> testResult = Optional.of(nodeIid);
+ assertEquals(testResult, Whitebox.invokeMethod(ovsdbPortUpdateCommand, "getTerminationPointBridge", portUUID));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testGetTerminationPointBridge1() throws Exception {
+ ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+ Node node = mock(Node.class);
+ OvsdbNodeAugmentation ovsdbNode = mock(OvsdbNodeAugmentation.class);
+ when(node.getAugmentation(OvsdbNodeAugmentation.class)).thenReturn(ovsdbNode);
+ List<ManagedNodeEntry> managedNodes = new ArrayList<>();
+ ManagedNodeEntry managedNodeEntry = mock(ManagedNodeEntry.class);
+ managedNodes.add(managedNodeEntry);
+ when(ovsdbNode.getManagedNodeEntry()).thenReturn(managedNodes);
+
+ Node managedNode = mock(Node.class);
+ OvsdbBridgeRef ovsdbBridgeRef = mock(OvsdbBridgeRef.class);
+ when(managedNodeEntry.getBridgeRef()).thenReturn(ovsdbBridgeRef);
+ InstanceIdentifier<Node> iidNode = mock(InstanceIdentifier.class);
+ when((InstanceIdentifier<Node>) ovsdbBridgeRef.getValue()).thenReturn(iidNode);
+ Optional<Node> optionalNode = Optional.of(managedNode);
+ PowerMockito.doReturn(optionalNode).when(ovsdbPortUpdateCommand, "readNode", any(ReadWriteTransaction.class), any(InstanceIdentifier.class));
+
+ TerminationPointBuilder tpBuilder = mock(TerminationPointBuilder.class);
+ PowerMockito.whenNew(TerminationPointBuilder.class).withNoArguments().thenReturn(tpBuilder);
+ PowerMockito.whenNew(TpId.class).withAnyArguments().thenReturn(mock(TpId.class));
+ PowerMockito.whenNew(TerminationPointKey.class).withAnyArguments().thenReturn(mock(TerminationPointKey.class));
+ when(tpBuilder.setKey(any(TerminationPointKey.class))).thenReturn(tpBuilder);
+
+ List<TerminationPoint> terminationPointList = new ArrayList<>();
+ TerminationPoint terminationPoint = mock(TerminationPoint.class);
+ terminationPointList.add(terminationPoint);
+ when(tpBuilder.build()).thenReturn(terminationPoint);
+ when(managedNode.getTerminationPoint()).thenReturn(terminationPointList);
+
+ when(managedNode.getAugmentation(OvsdbBridgeAugmentation.class)).thenReturn(mock(OvsdbBridgeAugmentation.class));
+
+ Optional<InstanceIdentifier<Node>> testResult = Optional.of(iidNode);
+ Optional<InstanceIdentifier<Node>> result = Whitebox.invokeMethod(ovsdbPortUpdateCommand, "getTerminationPointBridge", transaction, node, TP_NAME);
+ assertEquals(testResult, result);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateInterfaces() throws Exception {
+ Interface interfaceUpdate = mock(Interface.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Column<GenericTableSchema, String> typeColumn = mock(Column.class);
+ when(interfaceUpdate.getTypeColumn()).thenReturn(typeColumn);
+ when(typeColumn.getData()).thenReturn(OVSDB_INTERFACE_TYPE);
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateInterface", Interface.class, String.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateInterfaces", interfaceUpdate, ovsdbTerminationPointBuilder);
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateInterface", any(Interface.class), anyString(), any(OvsdbTerminationPointAugmentationBuilder.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateInterface() throws Exception {
+ Interface interf = mock(Interface.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ when(interf.getUuid()).thenReturn(mock(UUID.class));
+ PowerMockito.whenNew(Uuid.class).withAnyArguments().thenReturn(mock(Uuid.class));
+ when(ovsdbTerminationPointBuilder.setInterfaceUuid(any(Uuid.class))).thenReturn(ovsdbTerminationPointBuilder);
+ PowerMockito.mockStatic(SouthboundMapper.class);
+ PowerMockito.when(SouthboundMapper.createInterfaceType(anyString())).thenAnswer(new Answer<Class<? extends InterfaceTypeBase>>() {
+ public Class<? extends InterfaceTypeBase> answer(
+ InvocationOnMock invocation) throws Throwable {
+ return (Class<? extends InterfaceTypeBase>) InterfaceTypeInternal.class;
+ }
+ });
+ when(ovsdbTerminationPointBuilder.setInterfaceType(any(Class.class))).thenReturn(ovsdbTerminationPointBuilder);
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateOfPort", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateOfPortRequest", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateInterfaceExternalIds", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateOptions", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateInterfaceOtherConfig", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateInterface", interf, OVSDB_INTERFACE_TYPE, ovsdbTerminationPointBuilder);
+ verify(ovsdbTerminationPointBuilder).setInterfaceUuid(any(Uuid.class));
+ verify(ovsdbTerminationPointBuilder).setInterfaceType(any(Class.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateOfPort", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateOfPortRequest", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateInterfaceExternalIds", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateOptions", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateInterfaceOtherConfig", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ }
+
+ @Test
+ public void testUpdatePort() throws Exception {
+ Port port = mock(Port.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateVlan", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateVlanTrunks", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateVlanMode", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updatePortExternalIds", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+ MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updatePortOtherConfig", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updatePort", port, ovsdbTerminationPointBuilder);
+
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateVlan", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateVlanTrunks", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateVlanMode", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updatePortExternalIds", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updatePortOtherConfig", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateVlan() throws Exception {
+ Port port = mock(Port.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Column<GenericTableSchema, Set<Long>> column = mock(Column.class);
+ when(port.getTagColumn()).thenReturn(column);
+ Set<Long> vlanId = new HashSet<>();
+ vlanId.add((long) 808);
+ when(column.getData()).thenReturn(vlanId);
+ PowerMockito.whenNew(VlanId.class).withAnyArguments().thenReturn(mock(VlanId.class));
+ when(ovsdbTerminationPointBuilder.setVlanTag(any(VlanId.class))).thenReturn(ovsdbTerminationPointBuilder);
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateVlan", port, ovsdbTerminationPointBuilder);
+ verify(ovsdbTerminationPointBuilder).setVlanTag(any(VlanId.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateVlanTrunks() throws Exception {
+ Port port = mock(Port.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Column<GenericTableSchema, Set<Long>> column = mock(Column.class);
+ when(port.getTrunksColumn()).thenReturn(column);
+ Set<Long> portTrunks = new HashSet<>();
+ portTrunks.add((long) 300);
+ when(column.getData()).thenReturn(portTrunks);
+
+ TrunksBuilder trunksBuilder = mock(TrunksBuilder.class);
+ PowerMockito.whenNew(TrunksBuilder.class).withNoArguments().thenReturn(trunksBuilder);
+ PowerMockito.whenNew(VlanId.class).withAnyArguments().thenReturn(mock(VlanId.class));
+ when(trunksBuilder.setTrunk(any(VlanId.class))).thenReturn(trunksBuilder);
+ when(ovsdbTerminationPointBuilder.setTrunks(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateVlanTrunks", port, ovsdbTerminationPointBuilder);
+ verify(trunksBuilder).setTrunk(any(VlanId.class));
+ verify(ovsdbTerminationPointBuilder).setTrunks(any(List.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateVlanMode() throws Exception {
+ Port port = mock(Port.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Column<GenericTableSchema, Set<String>> column = mock(Column.class);
+ when(port.getVlanModeColumn()).thenReturn(column);
+ Set<String> set = new HashSet<>();
+ set.add(VLAN_MODE_ACCESS);
+ when(column.getData()).thenReturn(set);
+ when(ovsdbTerminationPointBuilder.setVlanMode(OvsdbPortInterfaceAttributes.VlanMode.Access)).thenReturn(ovsdbTerminationPointBuilder);
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateVlanMode", port, ovsdbTerminationPointBuilder);
+ verify(ovsdbTerminationPointBuilder).setVlanMode(any(VlanMode.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateOfPort() throws Exception {
+ Interface interf = mock(Interface.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Set<Long> ofPorts = new HashSet<>();
+ ofPorts.add((long) 10000);
+ Column<GenericTableSchema, Set<Long>> column = mock(Column.class);
+ when(interf.getOpenFlowPortColumn()).thenReturn(column);
+ when(column.getData()).thenReturn(ofPorts);
+ when(ovsdbTerminationPointBuilder.setOfport(any(Long.class))).thenReturn(ovsdbTerminationPointBuilder);
+ when(interf.getName()).thenReturn(INTERFACE_NAME);
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateOfPort", interf, ovsdbTerminationPointBuilder);
+ verify(ovsdbTerminationPointBuilder).setOfport(any(Long.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateOfPortRequest() throws Exception {
+ Interface interf = mock(Interface.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Set<Long> ofPortRequests = new HashSet<>();
+ ofPortRequests.add((long) 10000);
+ Column<GenericTableSchema, Set<Long>> column = mock(Column.class);
+ when(interf.getOpenFlowPortRequestColumn()).thenReturn(column);
+ when(column.getData()).thenReturn(ofPortRequests);
+ when(ovsdbTerminationPointBuilder.setOfportRequest(any(Integer.class))).thenReturn(ovsdbTerminationPointBuilder);
+ when(interf.getName()).thenReturn(INTERFACE_NAME);
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateOfPortRequest", interf, ovsdbTerminationPointBuilder);
+ verify(ovsdbTerminationPointBuilder).setOfportRequest(any(Integer.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateInterfaceExternalIds() throws Exception {
+ Interface interf = mock(Interface.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+ when(interf.getExternalIdsColumn()).thenReturn(column);
+ Map<String, String> map = new HashMap<>();
+ when(column.getData()).thenReturn(map);
+ map.put(EXTERNAL_ID_KEY, EXTERNAL_ID_VALUE);
+ when(column.getData()).thenReturn(map);
+
+ InterfaceExternalIdsBuilder interfaceExternalIdsBuilder = mock(InterfaceExternalIdsBuilder.class);
+ PowerMockito.whenNew(InterfaceExternalIdsBuilder.class).withNoArguments().thenReturn(interfaceExternalIdsBuilder);
+
+ when(interfaceExternalIdsBuilder.setExternalIdKey(anyString())).thenReturn(interfaceExternalIdsBuilder);
+ when(interfaceExternalIdsBuilder.setExternalIdValue(anyString())).thenReturn(interfaceExternalIdsBuilder);
+ when(interfaceExternalIdsBuilder.build()).thenReturn(mock(InterfaceExternalIds.class));
+ when(ovsdbTerminationPointBuilder.setInterfaceExternalIds(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateInterfaceExternalIds", interf, ovsdbTerminationPointBuilder);
+ verify(interfaceExternalIdsBuilder).setExternalIdKey(anyString());
+ verify(interfaceExternalIdsBuilder).setExternalIdValue(anyString());
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdatePortExternalIds() throws Exception {
+ Port port = mock(Port.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+ when(port.getExternalIdsColumn()).thenReturn(column);
+ Map<String, String> map = new HashMap<>();
+ when(column.getData()).thenReturn(map);
+ map.put(EXTERNAL_ID_KEY, EXTERNAL_ID_VALUE);
+ when(column.getData()).thenReturn(map);
+
+ PortExternalIdsBuilder portExternalIdsBuilder = mock(PortExternalIdsBuilder.class);
+ PowerMockito.whenNew(PortExternalIdsBuilder.class).withNoArguments().thenReturn(portExternalIdsBuilder);
+
+ when(portExternalIdsBuilder.setExternalIdKey(anyString())).thenReturn(portExternalIdsBuilder);
+ when(portExternalIdsBuilder.setExternalIdValue(anyString())).thenReturn(portExternalIdsBuilder);
+ when(portExternalIdsBuilder.build()).thenReturn(mock(PortExternalIds.class));
+ when(ovsdbTerminationPointBuilder.setPortExternalIds(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updatePortExternalIds", port, ovsdbTerminationPointBuilder);
+ verify(portExternalIdsBuilder).setExternalIdKey(anyString());
+ verify(portExternalIdsBuilder).setExternalIdValue(anyString());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdatePortOtherConfig() throws Exception {
+ Port port = mock(Port.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+ when(port.getOtherConfigColumn()).thenReturn(column);
+ Map<String, String> map = new HashMap<>();
+ map.put(OTHER_CONFIG_KEY, OTHER_CONFIG_VALUE);
+ when(column.getData()).thenReturn(map);
+
+ PortOtherConfigsBuilder portOtherConfigsBuilder = mock(PortOtherConfigsBuilder.class);
+ PowerMockito.whenNew(PortOtherConfigsBuilder.class).withNoArguments().thenReturn(portOtherConfigsBuilder);
+
+ when(portOtherConfigsBuilder.setOtherConfigKey(anyString())).thenReturn(portOtherConfigsBuilder);
+ when(portOtherConfigsBuilder.setOtherConfigValue(anyString())).thenReturn(portOtherConfigsBuilder);
+ when(portOtherConfigsBuilder.build()).thenReturn(mock(PortOtherConfigs.class));
+ when(ovsdbTerminationPointBuilder.setInterfaceOtherConfigs(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updatePortOtherConfig", port, ovsdbTerminationPointBuilder);
+ verify(portOtherConfigsBuilder).setOtherConfigKey(anyString());
+ verify(portOtherConfigsBuilder).setOtherConfigValue(anyString());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpdateInterfaceOtherConfig() throws Exception {
+ Interface interf = mock(Interface.class);
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+ Map<String, String> interfaceOtherConfigMap = new HashMap<>();
+ interfaceOtherConfigMap.put(OTHER_CONFIG_KEY, OTHER_CONFIG_VALUE);
+ Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+ when(interf.getOtherConfigColumn()).thenReturn(column);
+ when(column.getData()).thenReturn(interfaceOtherConfigMap);
+
+ InterfaceOtherConfigsBuilder interfaceOtherConfigsBuilder = mock(InterfaceOtherConfigsBuilder.class);
+ PowerMockito.whenNew(InterfaceOtherConfigsBuilder.class).withNoArguments().thenReturn(interfaceOtherConfigsBuilder);
+
+ when(interfaceOtherConfigsBuilder.setOtherConfigKey(anyString())).thenReturn(interfaceOtherConfigsBuilder);
+ when(interfaceOtherConfigsBuilder.setOtherConfigValue(anyString())).thenReturn(interfaceOtherConfigsBuilder);
+ when(interfaceOtherConfigsBuilder.build()).thenReturn(mock(InterfaceOtherConfigs.class));
+ when(ovsdbTerminationPointBuilder.setInterfaceOtherConfigs(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+
+ Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateInterfaceOtherConfig", interf, ovsdbTerminationPointBuilder);
+ verify(interfaceOtherConfigsBuilder).setOtherConfigKey(anyString());
+ verify(interfaceOtherConfigsBuilder).setOtherConfigValue(anyString());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testGetInstanceIdentifier() throws Exception {
+ InstanceIdentifier<Node> bridgeIid = mock(InstanceIdentifier.class);
+ Port port = mock(Port.class);
+ Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+ when(port.getExternalIdsColumn()).thenReturn(column);
+ Map<String, String> map = new HashMap<>();
+ map.put(SouthboundConstants.IID_EXTERNAL_ID_KEY, "opendaylight-iid");
+ when(column.getData()).thenReturn(map);
+
+ PowerMockito.mockStatic(SouthboundUtil.class);
+ InstanceIdentifier<TerminationPoint> terminationPointIId = mock(InstanceIdentifier.class);
+ PowerMockito.when((InstanceIdentifier<TerminationPoint>) SouthboundUtil.deserializeInstanceIdentifier(anyString())).thenReturn(terminationPointIId);
+ assertEquals(terminationPointIId, Whitebox.invokeMethod(ovsdbPortUpdateCommand, "getInstanceIdentifier", bridgeIid, port));
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+@PrepareForTest({TransactionInvokerImpl.class})
+@RunWith(PowerMockRunner.class)
+public class TransactionInvokerImplTest {
+ private static final int QUEUE_SIZE = 10000;
+ @Mock private BindingTransactionChain chain;
+ @Mock private DataBroker db;
+ private BlockingQueue<TransactionCommand> inputQueue = new LinkedBlockingQueue<TransactionCommand>(QUEUE_SIZE);
+ private BlockingQueue<ReadWriteTransaction> successfulTransactionQueue
+ = new LinkedBlockingQueue<ReadWriteTransaction>(QUEUE_SIZE);
+ private BlockingQueue<AsyncTransaction<?, ?>> failedTransactionQueue
+ = new LinkedBlockingQueue<AsyncTransaction<?, ?>>(QUEUE_SIZE);
+ @Mock private ExecutorService executor;
+ private Map<ReadWriteTransaction,TransactionCommand> transactionToCommand
+ = new HashMap<ReadWriteTransaction,TransactionCommand>();
+ private List<ReadWriteTransaction> pendingTransactions = new ArrayList<ReadWriteTransaction>();
+ private TransactionInvokerImpl transactionInvokerImpl;
+
+ @Before
+ public void setUp() throws Exception {
+ transactionInvokerImpl = PowerMockito.mock(TransactionInvokerImpl.class, Mockito.CALLS_REAL_METHODS);
+ MemberModifier.field(TransactionInvokerImpl.class, "chain").set(transactionInvokerImpl, chain);
+ MemberModifier.field(TransactionInvokerImpl.class, "db").set(transactionInvokerImpl, db);
+ }
+
+ @Test
+ public void testTransactionInvokerImpl() throws Exception {
+ MemberModifier.field(TransactionInvokerImpl.class, "inputQueue").set(transactionInvokerImpl, inputQueue);
+ when(db.createTransactionChain(any(TransactionChainListener.class))).thenReturn(mock(BindingTransactionChain.class));
+ TransactionInvokerImpl transactionInvokerImpl1 = new TransactionInvokerImpl(db);
+ verify(db).createTransactionChain(any(TransactionChainListener.class));
+ assertNotNull(Whitebox.getInternalState(transactionInvokerImpl1, "executor"));
+ }
+
+ @Test
+ public void testInvoke() throws Exception {
+ MemberModifier.field(TransactionInvokerImpl.class, "inputQueue").set(transactionInvokerImpl, inputQueue);
+ TransactionCommand command = mock(TransactionCommand.class);
+ transactionInvokerImpl.invoke(command);
+ BlockingQueue<TransactionCommand> testInputQueue = Whitebox.getInternalState(transactionInvokerImpl, "inputQueue");
+ assertTrue(testInputQueue.contains(command));
+ }
+
+ @Test
+ public void testOnTransactionChainFailed() throws Exception {
+ MemberModifier.field(TransactionInvokerImpl.class, "failedTransactionQueue").set(transactionInvokerImpl, failedTransactionQueue);
+ TransactionChain<?, ?> chain = mock(TransactionChain.class);
+ AsyncTransaction<?, ?> transaction = mock(AsyncTransaction.class);
+ Throwable cause = mock(Throwable.class);
+ transactionInvokerImpl.onTransactionChainFailed(chain, transaction, cause);
+ BlockingQueue<AsyncTransaction<?, ?>> testFailedTransactionQueue = Whitebox.getInternalState(transactionInvokerImpl, "failedTransactionQueue");
+ assertTrue(testFailedTransactionQueue.contains(transaction));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test
+ public void testExtractResubmitCommands() throws Exception {
+ AsyncTransaction<?, ?> transaction = mock(ReadWriteTransaction.class);
+ failedTransactionQueue.put(transaction);
+ MemberModifier.field(TransactionInvokerImpl.class, "failedTransactionQueue").set(transactionInvokerImpl, failedTransactionQueue);
+
+ AsyncTransaction tx1 = mock(ReadWriteTransaction.class);
+ AsyncTransaction tx2 = mock(ReadWriteTransaction.class);
+ pendingTransactions.add((ReadWriteTransaction) tx1);
+ pendingTransactions.add((ReadWriteTransaction) transaction);
+ pendingTransactions.add((ReadWriteTransaction) tx2);
+ MemberModifier.field(TransactionInvokerImpl.class, "pendingTransactions").set(transactionInvokerImpl, pendingTransactions);
+
+ List<ReadWriteTransaction> transactions= new ArrayList<ReadWriteTransaction>();
+ transactions.add((ReadWriteTransaction) tx1);
+
+ TransactionCommand txCommand = mock(TransactionCommand.class);
+ transactionToCommand.put((ReadWriteTransaction) tx1, txCommand);
+ transactionToCommand.put((ReadWriteTransaction) tx2, txCommand);
+ transactionToCommand.put((ReadWriteTransaction) transaction, txCommand);
+ MemberModifier.field(TransactionInvokerImpl.class, "transactionToCommand").set(transactionInvokerImpl, transactionToCommand);
+ PowerMockito.suppress(MemberModifier.method(TransactionInvokerImpl.class, "resetTransactionQueue"));
+
+ List<TransactionCommand> testCommands = new ArrayList<TransactionCommand>();
+ testCommands.add(txCommand);
+
+ assertEquals(testCommands, Whitebox.invokeMethod(transactionInvokerImpl, "extractResubmitCommands"));
+ }
+
+ @Test
+ public void testResetTransactionQueue() throws Exception {
+ doNothing().when(chain).close();
+ when(db.createTransactionChain(any(TransactionInvokerImpl.class))).thenReturn(chain);
+
+ failedTransactionQueue.add(mock(AsyncTransaction.class));
+ MemberModifier.field(TransactionInvokerImpl.class, "pendingTransactions").set(transactionInvokerImpl, pendingTransactions);
+ MemberModifier.field(TransactionInvokerImpl.class, "transactionToCommand").set(transactionInvokerImpl, transactionToCommand);
+ MemberModifier.field(TransactionInvokerImpl.class, "failedTransactionQueue").set(transactionInvokerImpl, failedTransactionQueue);
+ MemberModifier.field(TransactionInvokerImpl.class, "successfulTransactionQueue").set(transactionInvokerImpl, successfulTransactionQueue);
+
+ Whitebox.invokeMethod(transactionInvokerImpl, "resetTransactionQueue");
+ assertNotNull(Whitebox.getInternalState(transactionInvokerImpl, "pendingTransactions"));
+ assertNotNull(Whitebox.getInternalState(transactionInvokerImpl, "transactionToCommand"));
+ BlockingQueue<AsyncTransaction<?, ?>> testFailedTransactionQueue = Whitebox.getInternalState(transactionInvokerImpl, "failedTransactionQueue");
+ assertEquals(0, testFailedTransactionQueue.size());
+ }
+
+ @Test
+ public void testRecordPendingTransaction() throws Exception {
+ TransactionCommand command = mock(TransactionCommand.class);
+ ReadWriteTransaction transaction= mock(ReadWriteTransaction.class);
+ MemberModifier.field(TransactionInvokerImpl.class, "pendingTransactions").set(transactionInvokerImpl, pendingTransactions);
+ MemberModifier.field(TransactionInvokerImpl.class, "transactionToCommand").set(transactionInvokerImpl, transactionToCommand);
+ Whitebox.invokeMethod(transactionInvokerImpl, "recordPendingTransaction", command, transaction);
+
+ List<ReadWriteTransaction> testPendingTransactions = Whitebox.getInternalState(transactionInvokerImpl, "pendingTransactions");
+ assertEquals(1, testPendingTransactions.size());
+
+ Map<ReadWriteTransaction, TransactionCommand> testTransactionToCommand = Whitebox.getInternalState(transactionInvokerImpl, "transactionToCommand");
+ assertEquals(1, testTransactionToCommand.size());
+ }
+
+ @Test
+ public void testExtractCommands() throws Exception {
+ List<TransactionCommand> commands = new ArrayList<>();
+ PowerMockito.doReturn(commands).when(transactionInvokerImpl, "extractResubmitCommands");
+
+ List<TransactionCommand> resubmitCommands = new ArrayList<>();
+ resubmitCommands.add(mock(TransactionCommand.class));
+ PowerMockito.doReturn(resubmitCommands).when(transactionInvokerImpl, "extractCommandsFromQueue");
+
+ List<TransactionCommand> testCommands = new ArrayList<>();
+ testCommands.addAll(resubmitCommands);
+
+ assertEquals(testCommands, Whitebox.invokeMethod(transactionInvokerImpl, "extractCommands"));
+ }
+
+ @Test
+ public void testExtractCommandsFromQueue() throws Exception {
+ TransactionCommand command = mock(TransactionCommand.class);
+ inputQueue.add(command);
+ MemberModifier.field(TransactionInvokerImpl.class, "inputQueue").set(transactionInvokerImpl, inputQueue);
+ List<TransactionCommand> testResult = new ArrayList<TransactionCommand>();
+ testResult.add(command);
+ assertEquals(testResult, Whitebox.invokeMethod(transactionInvokerImpl, "extractCommandsFromQueue"));
+ }
+
+ @Test
+ public void testForgetSuccessfulTransactions() throws Exception {
+ ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+ successfulTransactionQueue.add(transaction);
+ pendingTransactions.add(transaction);
+ transactionToCommand.put(transaction, mock(TransactionCommand.class));
+ MemberModifier.field(TransactionInvokerImpl.class, "successfulTransactionQueue").set(transactionInvokerImpl, successfulTransactionQueue);
+ MemberModifier.field(TransactionInvokerImpl.class, "pendingTransactions").set(transactionInvokerImpl, pendingTransactions);
+ MemberModifier.field(TransactionInvokerImpl.class, "transactionToCommand").set(transactionInvokerImpl, transactionToCommand);
+
+ Whitebox.invokeMethod(transactionInvokerImpl, "forgetSuccessfulTransactions");
+
+ List<ReadWriteTransaction> testPendingTransactions = Whitebox.getInternalState(transactionInvokerImpl, "pendingTransactions");
+ Map<ReadWriteTransaction, TransactionCommand> testTransactionToCommand = Whitebox.getInternalState(transactionInvokerImpl, "transactionToCommand");
+ assertTrue(testPendingTransactions.isEmpty());
+ assertTrue(testTransactionToCommand.isEmpty());
+ }
+
+ @Test
+ public void testClose() throws Exception {
+ MemberModifier.field(TransactionInvokerImpl.class, "executor").set(transactionInvokerImpl, executor);
+ doNothing().when(executor).shutdown();
+ transactionInvokerImpl.close();
+ verify(executor).shutdown();
+ }
+}
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.io.File;
+import java.lang.reflect.Array;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ExecutionException;
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.TerminationPointBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.concepts.Builder;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class SouthboundIT extends AbstractMdsalTestBase {
- private static final String EXPECTED_VALUES_KEY = "ExpectedValuesKey";
- private static final String INPUT_VALUES_KEY = "InputValuesKey";
private static final String NETDEV_DP_TYPE = "netdev";
private static final Logger LOG = LoggerFactory.getLogger(SouthboundIT.class);
private static final int OVSDB_UPDATE_TIMEOUT = 1000;
+ private static final String FORMAT_STR = "%s_%s_%d";
public static final int NUM_THREADS = 4;
private static String addressStr;
private static String portStr;
.create(NetworkTopology.class)
.child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
.child(Node.class,
- createNodeKey(connectionInfo.getRemoteIp(),connectionInfo.getRemotePort()));
+ createNodeKey(connectionInfo.getRemoteIp(), connectionInfo.getRemotePort()));
}
private Node getOvsdbNode(final ConnectionInfo connectionInfo) {
Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
}
- /*
- * Generates the test cases involved in testing PortExternalIds. See inline comments for descriptions of
- * the particular cases considered.
- *
- * The return value is a Map in the form (K,V)=(testCaseName,testCase).
- * - testCaseName is a String
- * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
- * either corresponding INPUT port external_ids, or EXPECTED port external_ids
- * INPUT is the List we use when calling
- * <code>TerminationPointAugmentationBuilder.setPortExternalIds()</code>
- * EXPECTED is the List we expect to receive after calling
- * <code>TerminationPointAugmentationBuilder.getPortExternalIds()</code>
- */
- private Map<String, Map<String, List<PortExternalIds>>> generatePortExternalIdsTestCases() {
- Map<String, Map<String, List<PortExternalIds>>> testMap = new HashMap<>();
+ private interface KeyValueBuilder<T> {
+ T build(String testName, String key, String value);
+ T[] build(String testName, int count, String key, String value);
+ void reset();
+ }
- final String PORT_EXTERNAL_ID_KEY = "PortExternalIdKey";
- final String PORT_EXTERNAL_ID_VALUE = "PortExternalIdValue";
- final String FORMAT_STR = "%s_%s_%d";
- final String GOOD_KEY = "GoodKey";
- final String GOOD_VALUE = "GoodValue";
- final String NO_VALUE_FOR_KEY = "NoValueForKey";
- final String NO_KEY_FOR_VALUE = "NoKeyForValue";
+ private abstract static class BaseKeyValueBuilder<T> implements KeyValueBuilder<T> {
+ private static final int COUNTER_START = 0;
+ private int counter = COUNTER_START;
+ private final Class<T> builtClass;
- // Test Case 1: TestOneExternalId
- // Test Type: Positive
- // Description: Create a termination point with one PortExternalIds
- // Expected: A port is created with the single external_ids specified below
- final String testOneExternalIdName = "TestOneExternalId";
- int externalIdCounter = 0;
- List<PortExternalIds> oneExternalId = Lists.newArrayList(
- (new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testOneExternalIdName,
- PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testOneExternalIdName,
- PORT_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()));
- Map<String,List<PortExternalIds>> testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, oneExternalId);
- testCase.put(INPUT_VALUES_KEY, oneExternalId);
- testMap.put(testOneExternalIdName, testCase);
-
- // Test Case 2: TestFiveExternalId
- // Test Type: Positive
- // Description: Create a termination point with multiple (five) PortExternalIds
- // Expected: A port is created with the five external_ids specified below
- final String testFiveExternalIdName = "TestFiveExternalId";
- externalIdCounter = 0;
- List<PortExternalIds> fiveExternalId = Lists.newArrayList(
- (new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- PORT_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()));
- testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, fiveExternalId);
- testCase.put(INPUT_VALUES_KEY, fiveExternalId);
- testMap.put(testFiveExternalIdName, testCase);
-
- // Test Case 3: TestOneGoodExternalIdOneMalformedExternalIdValue
- // Test Type: Negative
- // Description:
- // One perfectly fine PortExternalId
- // (TestOneGoodExternalIdOneMalformedExternalIdValue_PortExternalIdKey_1,
- // TestOneGoodExternalIdOneMalformedExternalId_PortExternalIdValue_1)
- // and one malformed PortExternalId which only has key specified
- // (TestOneGoodExternalIdOneMalformedExternalIdValue_NoValueForKey_2,
- // UNSPECIFIED)
- // Expected: A port is created without any external_ids
- final String testOneGoodExternalIdOneMalformedExternalIdValueName =
- "TestOneGoodExternalIdOneMalformedExternalIdValue";
- externalIdCounter = 0;
- PortExternalIds oneGood = new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdValueName,
- GOOD_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdValueName,
- GOOD_VALUE, externalIdCounter))
- .build();
- PortExternalIds oneBad = new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdValueName, NO_VALUE_FOR_KEY, ++externalIdCounter))
- .build();
- List<PortExternalIds> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- List<PortExternalIds> oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodExternalIdOneMalformedExternalIdValueName, testCase);
-
- // Test Case 4: TestOneGoodExternalIdOneMalformedExternalIdKey
- // Test Type: Negative
- // Description:
- // One perfectly fine PortExternalId
- // (TestOneGoodExternalIdOneMalformedExternalIdValue_PortExternalIdKey_1,
- // TestOneGoodExternalIdOneMalformedExternalId_PortExternalIdValue_1)
- // and one malformed PortExternalId which only has key specified
- // (UNSPECIFIED,
- // TestOneGoodExternalIdOneMalformedExternalIdKey_NoKeyForValue_2)
- // Expected: A port is created without any external_ids
- final String testOneGoodExternalIdOneMalformedExternalIdKeyName =
- "TestOneGoodExternalIdOneMalformedExternalIdKey";
- externalIdCounter = 0;
- oneGood = new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdKeyName,
- GOOD_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdKeyName,
- GOOD_VALUE, externalIdCounter))
- .build();
- oneBad = new PortExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdKeyName, NO_KEY_FOR_VALUE, ++externalIdCounter))
- .build();
- oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodExternalIdOneMalformedExternalIdKeyName, testCase);
+ protected abstract Builder<T> builder();
- return testMap;
- }
+ protected abstract void setKey(Builder<T> builder, String key);
- /*
- * @see <code>SouthboundIT.testCRUDPortExternalIds()</code>
- * This is helper test method to compare a test "set" of BridgeExternalIds against an expected "set"
- */
- private void assertExpectedPortExternalIdsExist( List<PortExternalIds> expected,
- List<PortExternalIds> test ) {
+ protected abstract void setValue(Builder<T> builder, String value);
- if (expected != null) {
- for (PortExternalIds expectedExternalId : expected) {
- Assert.assertTrue(test.contains(expectedExternalId));
+ @SuppressWarnings("unchecked")
+ private BaseKeyValueBuilder() {
+ builtClass = (Class<T>) this.getClass().getSuperclass().getTypeParameters()[0].getClass();
+ }
+
+ @Override
+ public final T build(final String testName, final String key, final String value) {
+ final Builder<T> builder = builder();
+ this.counter++;
+ if (key != null) {
+ setKey(builder, String.format(FORMAT_STR, testName, key, this.counter));
+ }
+ if (value != null) {
+ setValue(builder, String.format(FORMAT_STR, testName, value, this.counter));
}
+ return builder.build();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final T[] build(final String testName, final int count, final String key, final String value) {
+ final T[] instances = (T[]) Array.newInstance(builtClass, count);
+ for (int idx = 0; idx < count; idx++) {
+ instances[idx] = build(testName, key, value);
+ }
+ return instances;
+ }
+
+ @Override
+ public final void reset() {
+ this.counter = COUNTER_START;
}
}
- /*
- * Tests the CRUD operations for <code>Port</code>
- * <code>external_ids</code>.
- *
- * @see <code>SouthboundIT.generatePortExternalIdsTestCases()</code> for
- * specific test case information
- */
- @Test
- public void testCRUDTerminationPointPortExternalIds()
- throws InterruptedException, ExecutionException {
+ private static final class SouthboundPortExternalIdsBuilder extends BaseKeyValueBuilder<PortExternalIds> {
+ @Override
+ protected Builder<PortExternalIds> builder() {
+ return new PortExternalIdsBuilder();
+ }
- final String TEST_PREFIX = "CRUDTPPortExternalIds";
+ @Override
+ protected void setKey(Builder<PortExternalIds> builder, String key) {
+ ((PortExternalIdsBuilder) builder).setExternalIdKey(key);
+ }
- ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
- connectOvsdbNode(connectionInfo);
+ @Override
+ protected void setValue(Builder<PortExternalIds> builder, String value) {
+ ((PortExternalIdsBuilder) builder).setExternalIdValue(value);
+ }
+ }
- // updateFromTestCases represent the original test case value.
- // updateToTestCases represent the new value after the update has been
- // performed.
- Map<String, Map<String, List<PortExternalIds>>> updateFromTestCases =
- generatePortExternalIdsTestCases();
- Map<String, Map<String, List<PortExternalIds>>> updateToTestCases =
- generatePortExternalIdsTestCases();
- Map<String, List<PortExternalIds>> updateFromTestCase;
- List<PortExternalIds> updateFromInputExternalIds;
- List<PortExternalIds> updateFromExpectedExternalIds;
- Map<String, List<PortExternalIds>> updateToTestCase;
- List<PortExternalIds> updateToInputExternalIds;
- List<PortExternalIds> updateToExpectedExternalIds;
- String testBridgeName;
- String testPortName;
+ private static final class SouthboundInterfaceExternalIdsBuilder extends BaseKeyValueBuilder<InterfaceExternalIds> {
+ @Override
+ protected Builder<InterfaceExternalIds> builder() {
+ return new InterfaceExternalIdsBuilder();
+ }
- int counter = 1;
- // multihreads the test using NUM_THREADS
- ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
- for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
- updateFromTestCase = updateFromTestCases.get(
- updateFromTestCaseKey);
- updateFromInputExternalIds = updateFromTestCase.get(
- INPUT_VALUES_KEY);
- updateFromExpectedExternalIds = updateFromTestCase.get(
- EXPECTED_VALUES_KEY);
- for (String testCaseKey : updateToTestCases.keySet()) {
- testPortName = testBridgeName = String.format("%s_%s_%d",
- TEST_PREFIX, testCaseKey, counter);
- counter += 1;
- updateToTestCase = updateToTestCases.get(testCaseKey);
- updateToInputExternalIds = updateToTestCase.get(
- INPUT_VALUES_KEY);
- updateToExpectedExternalIds = updateToTestCase.get(
- EXPECTED_VALUES_KEY);
- TestCRUDTerminationPointPortExternalIdsRunnable testRunnable =
- new TestCRUDTerminationPointPortExternalIdsRunnable(
- connectionInfo, testBridgeName, testPortName,
- updateFromInputExternalIds,
- updateFromExpectedExternalIds,
- updateToInputExternalIds,
- updateToExpectedExternalIds);
- executor.submit(testRunnable);
- }
+ @Override
+ protected void setKey(Builder<InterfaceExternalIds> builder, String key) {
+ ((InterfaceExternalIdsBuilder) builder).setExternalIdKey(key);
+ }
+
+ @Override
+ protected void setValue(Builder<InterfaceExternalIds> builder, String value) {
+ ((InterfaceExternalIdsBuilder) builder).setExternalIdValue(value);
}
- executor.shutdown();
- executor.awaitTermination(5, TimeUnit.MINUTES);
- Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
}
- class TestCRUDTerminationPointPortExternalIdsRunnable implements Runnable {
- ConnectionInfo connectionInfo;
- String testBridgeName;
- String testPortName;
- List<PortExternalIds> updateFromInputExternalIds;
- List<PortExternalIds> updateFromExpectedExternalIds;
- List<PortExternalIds> updateToInputExternalIds;
- List<PortExternalIds> updateToExpectedExternalIds;
-
- public TestCRUDTerminationPointPortExternalIdsRunnable(
- ConnectionInfo connectionInfo,
- String testBridgeName, String testPortName,
- List<PortExternalIds> updateFromInputExternalIds,
- List<PortExternalIds> updateFromExpectedExternalIds,
- List<PortExternalIds> updateToInputExternalIds,
- List<PortExternalIds> updateToExpectedExternalIds) {
+ private static final class SouthboundOptionsBuilder extends BaseKeyValueBuilder<Options> {
+ @Override
+ protected Builder<Options> builder() {
+ return new OptionsBuilder();
+ }
- this.connectionInfo = connectionInfo;
- this.testBridgeName = testBridgeName;
- this.testPortName = testPortName;
- this.updateFromInputExternalIds = updateFromInputExternalIds;
- this.updateFromExpectedExternalIds = updateFromExpectedExternalIds;
- this.updateToInputExternalIds = updateToInputExternalIds;
- this.updateToExpectedExternalIds = updateToExpectedExternalIds;
+ @Override
+ protected void setKey(Builder<Options> builder, String key) {
+ ((OptionsBuilder) builder).setOption(key);
}
@Override
- public void run() {
- try {
- test();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ protected void setValue(Builder<Options> builder, String value) {
+ ((OptionsBuilder) builder).setValue(value);
}
+ }
- private void test() throws InterruptedException {
+ private static final class SouthboundInterfaceOtherConfigsBuilder extends BaseKeyValueBuilder<InterfaceOtherConfigs> {
+ @Override
+ protected Builder<InterfaceOtherConfigs> builder() {
+ return new InterfaceOtherConfigsBuilder();
+ }
- final int TERMINATION_POINT_TEST_INDEX = 0;
- // CREATE: Create the test bridge
- Assert.assertTrue(addBridge(connectionInfo, null,
- testBridgeName, null, true,
- SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
- true, null, null, null, null));
- NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
- connectionInfo, new OvsdbBridgeName(testBridgeName)));
- OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
- createGenericOvsdbTerminationPointAugmentationBuilder();
- tpCreateAugmentationBuilder.setName(testPortName);
- tpCreateAugmentationBuilder.setPortExternalIds(updateFromInputExternalIds);
- Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
+ @Override
+ protected void setKey(Builder<InterfaceOtherConfigs> builder, String key) {
+ ((InterfaceOtherConfigsBuilder) builder).setOtherConfigKey(key);
+ }
- // READ: Read the test port and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<PortExternalIds> updateFromConfigurationExternalIds =
- updateFromConfigurationTerminationPointAugmentation
- .getPortExternalIds();
- assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateFromConfigurationExternalIds);
- OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmenation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<PortExternalIds> updateFromOperationalExternalIds = updateFromOperationalTerminationPointAugmenation
- .getPortExternalIds();
- assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateFromOperationalExternalIds);
+ @Override
+ protected void setValue(Builder<InterfaceOtherConfigs> builder, String value) {
+ ((InterfaceOtherConfigsBuilder) builder).setOtherConfigValue(value);
+ }
+ }
- // UPDATE: update the external_ids
- testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
- OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
- new OvsdbTerminationPointAugmentationBuilder();
- tpUpdateAugmentationBuilder.setPortExternalIds(updateToInputExternalIds);
- InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
- NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
- NodeId portUpdateNodeId = createManagedNodeId(portIid);
- portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
- TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
- tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
- tpUpdateBuilder.addAugmentation(
- OvsdbTerminationPointAugmentation.class,
- tpUpdateAugmentationBuilder.build());
- portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
- boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
- portIid, portUpdateNodeBuilder.build());
- Thread.sleep(OVSDB_UPDATE_TIMEOUT);
- Assert.assertTrue(result);
+ private static final class SouthboundPortOtherConfigsBuilder extends BaseKeyValueBuilder<PortOtherConfigs> {
+ @Override
+ protected Builder<PortOtherConfigs> builder() {
+ return new PortOtherConfigsBuilder();
+ }
- // READ: the test port and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<PortExternalIds> updateToConfigurationExternalIds = updateToConfigurationTerminationPointAugmentation
- .getPortExternalIds();
- assertExpectedPortExternalIdsExist(updateToExpectedExternalIds, updateToConfigurationExternalIds);
- assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateToConfigurationExternalIds);
- OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<PortExternalIds> updateToOperationalExternalIds =
- updateToOperationalTerminationPointAugmentation.getPortExternalIds();
- if (updateFromExpectedExternalIds != null) {
- assertExpectedPortExternalIdsExist(updateToExpectedExternalIds, updateToOperationalExternalIds);
- assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateToOperationalExternalIds);
- }
+ @Override
+ protected void setKey(Builder<PortOtherConfigs> builder, String key) {
+ ((PortOtherConfigsBuilder) builder).setOtherConfigKey(key);
+ }
- // DELETE
- Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
+ @Override
+ protected void setValue(Builder<PortOtherConfigs> builder, String value) {
+ ((PortOtherConfigsBuilder) builder).setOtherConfigValue(value);
}
}
+ private static final class SouthboundBridgeOtherConfigsBuilder extends BaseKeyValueBuilder<BridgeOtherConfigs> {
+ @Override
+ protected Builder<BridgeOtherConfigs> builder() {
+ return new BridgeOtherConfigsBuilder();
+ }
+ @Override
+ protected void setKey(Builder<BridgeOtherConfigs> builder, String key) {
+ ((BridgeOtherConfigsBuilder) builder).setBridgeOtherConfigKey(key);
+ }
+
+ @Override
+ protected void setValue(Builder<BridgeOtherConfigs> builder, String value) {
+ ((BridgeOtherConfigsBuilder) builder).setBridgeOtherConfigValue(value);
+ }
+ }
+
+ private static final class SouthboundBridgeExternalIdsBuilder extends BaseKeyValueBuilder<BridgeExternalIds> {
+ @Override
+ protected Builder<BridgeExternalIds> builder() {
+ return new BridgeExternalIdsBuilder();
+ }
+
+ @Override
+ protected void setKey(Builder<BridgeExternalIds> builder, String key) {
+ ((BridgeExternalIdsBuilder) builder).setBridgeExternalIdKey(key);
+ }
+
+ @Override
+ protected void setValue(Builder<BridgeExternalIds> builder, String value) {
+ ((BridgeExternalIdsBuilder) builder).setBridgeExternalIdValue(value);
+ }
+ }
/*
- * Generates the test cases involved in testing InterfaceExternalIds. See inline comments for descriptions of
+ * Generates the test cases involved in testing key-value-based data. See inline comments for descriptions of
* the particular cases considered.
- *
- * The return value is a Map in the form (K,V)=(testCaseName,testCase).
- * - testCaseName is a String
- * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
- * either corresponding INPUT interface external_ids, or EXPECTED interface external_ids
- * INPUT is the List we use when calling
- * <code>TerminationPointAugmentationBuilder.setInterfaceExternalIds()</code>
- * EXPECTED is the List we expect to receive after calling
- * <code>TerminationPointAugmentationBuilder.getInterfaceExternalIds()</code>
*/
- private Map<String, Map<String, List<InterfaceExternalIds>>> generateInterfaceExternalIdsTestCases() {
- Map<String, Map<String, List<InterfaceExternalIds>>> testMap = new HashMap<>();
+ private static <T> List<SouthboundTestCase<T>> generateKeyValueTestCases(
+ KeyValueBuilder<T> builder, String idKey, String idValue) {
+ List<SouthboundTestCase<T>> testCases = new ArrayList<>();
- final String INTERFACE_EXTERNAL_ID_KEY = "IntExternalIdKey";
- final String INTERFACE_EXTERNAL_ID_VALUE = "IntExternalIdValue";
- final String FORMAT_STR = "%s_%s_%d";
final String GOOD_KEY = "GoodKey";
final String GOOD_VALUE = "GoodValue";
final String NO_VALUE_FOR_KEY = "NoValueForKey";
final String NO_KEY_FOR_VALUE = "NoKeyForValue";
- // Test Case 1: TestOneExternalId
+ // Test Case 1: TestOne
// Test Type: Positive
- // Description: Create a termination point with one InterfaceExternalIds
- // Expected: A termination point is created with the single external_ids specified below
- final String testOneExternalIdName = "TestOneExternalId";
- int externalIdCounter = 0;
- List<InterfaceExternalIds> oneExternalId = Lists.newArrayList(
- (new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testOneExternalIdName,
- INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testOneExternalIdName,
- INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()));
- Map<String,List<InterfaceExternalIds>> testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, oneExternalId);
- testCase.put(INPUT_VALUES_KEY, oneExternalId);
- testMap.put(testOneExternalIdName, testCase);
-
- // Test Case 2: TestFiveExternalId
+ // Description: Create a termination point with one value
+ // Expected: A port is created with the single value specified below
+ final String testOneName = "TestOne";
+ testCases.add(new SouthboundTestCaseBuilder<T>()
+ .name(testOneName)
+ .input(builder.build(testOneName, idKey, idValue))
+ .expectInputAsOutput()
+ .build());
+ builder.reset();
+
+ // Test Case 2: TestFive
// Test Type: Positive
- // Description: Create a termination point with multiple (five) InterfaceExternalIds
- // Expected: A termination point is created with the five external_ids specified below
- final String testFiveExternalIdName = "TestFiveExternalId";
- externalIdCounter = 0;
- List<InterfaceExternalIds> fiveExternalId = Lists.newArrayList(
- (new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()));
- testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, fiveExternalId);
- testCase.put(INPUT_VALUES_KEY, fiveExternalId);
- testMap.put(testFiveExternalIdName, testCase);
-
- // Test Case 3: TestOneGoodExternalIdOneMalformedExternalIdValue
+ // Description: Create a termination point with multiple (five) values
+ // Expected: A port is created with the five values specified below
+ final String testFiveName = "TestFive";
+ testCases.add(new SouthboundTestCaseBuilder<T>()
+ .name(testFiveName)
+ .input(builder.build(testFiveName, 5, idKey, idValue))
+ .expectInputAsOutput()
+ .build());
+ builder.reset();
+
+ // Test Case 3: TestOneGoodOneMalformedValue
// Test Type: Negative
// Description:
- // One perfectly fine InterfaceExternalId
- // (TestOneGoodExternalIdOneMalformedExternalIdValue_IntExternalIdKey_1,
- // TestOneGoodExternalIdOneMalformedExternalId_IntExternalIdValue_1)
- // and one malformed PortExternalId which only has key specified
- // (TestOneGoodExternalIdOneMalformedExternalIdValue_NoValueForKey_2,
+ // One perfectly fine input
+ // (TestOneGoodOneMalformedValue_GoodKey_1,
+ // TestOneGoodOneMalformedValue_GoodValue_1)
+ // and one malformed input which only has key specified
+ // (TestOneGoodOneMalformedValue_NoValueForKey_2,
// UNSPECIFIED)
- // Expected: A termination point is created without any external_ids
- final String testOneGoodExternalIdOneMalformedExternalIdValueName =
- "TestOneGoodExternalIdOneMalformedExternalIdValue";
- externalIdCounter = 0;
- InterfaceExternalIds oneGood = new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdValueName,
- GOOD_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdValueName,
- GOOD_VALUE, externalIdCounter))
- .build();
- InterfaceExternalIds oneBad = new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdValueName, NO_VALUE_FOR_KEY, ++externalIdCounter))
- .build();
- List<InterfaceExternalIds> oneGoodOneBadInput = Lists.newArrayList(
- oneGood, oneBad);
- List<InterfaceExternalIds> oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodExternalIdOneMalformedExternalIdValueName, testCase);
-
- // Test Case 4: TestOneGoodExternalIdOneMalformedExternalIdKey
+ // Expected: A port is created without any values
+ final String testOneGoodOneMalformedValueName = "TestOneGoodOneMalformedValue";
+ testCases.add(new SouthboundTestCaseBuilder<T>()
+ .name(testOneGoodOneMalformedValueName)
+ .input(
+ builder.build(testOneGoodOneMalformedValueName, GOOD_KEY, GOOD_VALUE),
+ builder.build(testOneGoodOneMalformedValueName, NO_VALUE_FOR_KEY, null)
+ )
+ .expect()
+ .build());
+ builder.reset();
+
+ // Test Case 4: TestOneGoodOneMalformedKey
// Test Type: Negative
// Description:
- // One perfectly fine InterfaceExternalId
- // (TestOneGoodExternalIdOneMalformedExternalIdValue_IntExternalIdKey_1,
- // TestOneGoodExternalIdOneMalformedExternalId_IntExternalIdValue_1)
- // and one malformed BridgeExternalId which only has key specified
+ // One perfectly fine input
+ // (TestOneGoodOneMalformedKey_GoodKey_1,
+ // TestOneGoodOneMalformedKey_GoodValue_1)
+ // and one malformed input which only has value specified
// (UNSPECIFIED,
- // TestOneGoodExternalIdOneMalformedExternalIdKey_NoKeyForValue_2)
- // Expected: A termination point is created without any external_ids
- final String testOneGoodExternalIdOneMalformedExternalIdKeyName =
- "TestOneGoodExternalIdOneMalformedExternalIdKey";
- externalIdCounter = 0;
- oneGood = new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdKeyName,
- GOOD_KEY, ++externalIdCounter))
- .setExternalIdValue(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdKeyName,
- GOOD_VALUE, externalIdCounter))
- .build();
- oneBad = new InterfaceExternalIdsBuilder()
- .setExternalIdKey(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdKeyName, NO_KEY_FOR_VALUE, ++externalIdCounter))
- .build();
- oneGoodOneBadInput = Lists.newArrayList(
- oneGood, oneBad);
- oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodExternalIdOneMalformedExternalIdKeyName, testCase);
+ // TestOneGoodOneMalformedKey_NoKeyForValue_2)
+ // Expected: A port is created without any values
+ final String testOneGoodOneMalformedKeyName = "TestOneGoodOneMalformedKey";
+ testCases.add(new SouthboundTestCaseBuilder<T>()
+ .name(testOneGoodOneMalformedKeyName)
+ .input(
+ builder.build(testOneGoodOneMalformedKeyName, GOOD_KEY, GOOD_VALUE),
+ builder.build(testOneGoodOneMalformedKeyName, null, NO_KEY_FOR_VALUE)
+ )
+ .expect()
+ .build());
+ builder.reset();
- return testMap;
+ return testCases;
}
/*
- * @see <code>SouthboundIT.testCRUDInterfaceExternalIds()</code>
- * This is helper test method to compare a test "set" of InterfaceExternalIds against an expected "set"
+ * Generates the test cases involved in testing PortExternalIds. See inline comments for descriptions of
+ * the particular cases considered.
*/
- private void assertExpectedInterfaceExternalIdsExist( List<InterfaceExternalIds> expected,
- List<InterfaceExternalIds> test ) {
-
- if (expected != null) {
- for (InterfaceExternalIds expectedExternalId : expected) {
- Assert.assertTrue(test.contains(expectedExternalId));
- }
- }
+ private List<SouthboundTestCase<PortExternalIds>> generatePortExternalIdsTestCases() {
+ return generateKeyValueTestCases(new SouthboundPortExternalIdsBuilder(), "PortExternalIdKey",
+ "PortExternalIdValue");
}
/*
- * Tests the CRUD operations for <code>Interface</code> <code>external_ids</code>.
+ * Tests the CRUD operations for <code>Port</code>
+ * <code>external_ids</code>.
*
- * @see <code>SouthboundIT.generateInterfaceExternalIdsTestCases()</code> for specific test case information
+ * @see <code>SouthboundIT.generatePortExternalIdsTestCases()</code> for
+ * specific test case information
*/
@Test
- public void testCRUDTerminationPointInterfaceExternalIds() throws InterruptedException, ExecutionException {
- final String TEST_PREFIX = "CRUDTPInterfaceExternalIds";
+ public void testCRUDTerminationPointPortExternalIds()
+ throws InterruptedException, ExecutionException {
+
+ final String TEST_PREFIX = "CRUDTPPortExternalIds";
ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
connectOvsdbNode(connectionInfo);
- // updateFromTestCases represent the original test case value. updateToTestCases represent the new value after
- // the update has been performed.
- Map<String, Map<String, List<InterfaceExternalIds>>> updateFromTestCases =
- generateInterfaceExternalIdsTestCases();
- Map<String, Map<String, List<InterfaceExternalIds>>> updateToTestCases =
- generateInterfaceExternalIdsTestCases();
- Map<String, List<InterfaceExternalIds>> updateFromTestCase;
- List<InterfaceExternalIds> updateFromInputExternalIds;
- List<InterfaceExternalIds> updateFromExpectedExternalIds;
- Map<String, List<InterfaceExternalIds>> updateToTestCase;
- List<InterfaceExternalIds> updateToInputExternalIds;
- List<InterfaceExternalIds> updateToExpectedExternalIds;
+ // updateFromTestCases represent the original test case value.
+ // updateToTestCases represent the new value after the update has been
+ // performed.
+ List<SouthboundTestCase<PortExternalIds>> updateFromTestCases = generatePortExternalIdsTestCases();
+ List<SouthboundTestCase<PortExternalIds>> updateToTestCases = generatePortExternalIdsTestCases();
String testBridgeName;
String testPortName;
int counter = 1;
// multihreads the test using NUM_THREADS
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
- for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
- updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
- updateFromInputExternalIds = updateFromTestCase.get(INPUT_VALUES_KEY);
- updateFromExpectedExternalIds = updateFromTestCase.get(EXPECTED_VALUES_KEY);
- for (String testCaseKey : updateToTestCases.keySet()) {
- testPortName = testBridgeName = String.format("%s_%s_%d", TEST_PREFIX, testCaseKey, counter);
+ for (SouthboundTestCase<PortExternalIds> fromTestCase : updateFromTestCases) {
+ for (SouthboundTestCase<PortExternalIds> toTestCase : updateToTestCases) {
+ testPortName = testBridgeName = String.format(FORMAT_STR,
+ TEST_PREFIX, toTestCase.name, counter);
counter += 1;
- updateToTestCase = updateToTestCases.get(testCaseKey);
- updateToInputExternalIds = updateToTestCase.get(INPUT_VALUES_KEY);
- updateToExpectedExternalIds = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
- TestCRUDTerminationPointInterfaceExternalIdsRunnable testRunnable =
- new TestCRUDTerminationPointInterfaceExternalIdsRunnable(
- connectionInfo, testBridgeName, testPortName,
- updateFromInputExternalIds,
- updateFromExpectedExternalIds,
- updateToInputExternalIds,
- updateToExpectedExternalIds);
- executor.submit(testRunnable);
+ executor.submit(new TestCRUDTerminationPointRunnable<>(
+ new SouthboundTestHelper<PortExternalIds>() {
+ @Override
+ public List<PortExternalIds> readValues(
+ OvsdbTerminationPointAugmentation augmentation) {
+ return augmentation.getPortExternalIds();
+ }
+
+ @Override
+ public void writeValues(
+ OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+ List<PortExternalIds> updateFromInput) {
+ augmentationBuilder.setPortExternalIds(updateFromInput);
+ }
+ },
+ connectionInfo, testBridgeName, testPortName,
+ fromTestCase.inputValues,
+ fromTestCase.expectedValues,
+ toTestCase.inputValues,
+ toTestCase.expectedValues));
}
}
executor.shutdown();
Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
}
- class TestCRUDTerminationPointInterfaceExternalIdsRunnable implements Runnable {
-
- ConnectionInfo connectionInfo;
- String testBridgeName;
- String testPortName;
- List<InterfaceExternalIds> updateFromInputExternalIds;
- List<InterfaceExternalIds> updateFromExpectedExternalIds;
- List<InterfaceExternalIds> updateToInputExternalIds;
- List<InterfaceExternalIds> updateToExpectedExternalIds;
-
- TestCRUDTerminationPointInterfaceExternalIdsRunnable(
- ConnectionInfo connectionInfo, String testBridgeName,
- String testPortName,
- List<InterfaceExternalIds> updateFromInputExternalIds,
- List<InterfaceExternalIds> updateFromExpectedExternalIds,
- List<InterfaceExternalIds> updateToInputExternalIds,
- List<InterfaceExternalIds> updateToExpectedExternalIds) {
+ /**
+ * Southbound test helper. Classes implementing this interface are used to provide concrete access to the input and
+ * output of the underlying augmentation for the type being managed.
+ *
+ * @param <T> The type of data used for the test case.
+ */
+ private interface SouthboundTestHelper<T> {
+ /**
+ * Read the values from the augmentation. These would usually be checked against the expected values provided
+ * for the test case.
+ *
+ * @param augmentation The augmentation to read from.
+ * @return The values read.
+ */
+ List<T> readValues(OvsdbTerminationPointAugmentation augmentation);
+
+ /**
+ * Write the values to the augmentation (via its builder). This would usually be used to apply the input values
+ * provided for the test case.
+ *
+ * @param augmentationBuilder The augmentation builder.
+ * @param values The values to write.
+ */
+ void writeValues(OvsdbTerminationPointAugmentationBuilder augmentationBuilder, List<T> values);
+ }
+ /**
+ * <p>
+ * Test runner used to apply a suite of create/read/update/delete tests. Each instance of a runner expects:
+ * </p>
+ * <ul>
+ * <li>a helper used to manipulate the appropriate data structures in the termination point augmentation (see
+ * {@link SouthboundTestHelper});</li>
+ * <li>connection information for the southbound;</li>
+ * <li>a name to use for the test bridge (this allows multiple tests to be conducted in parallel against different
+ * bridges);</li>
+ * <li>a name to use for the test port;</li>
+ * <li>the initial input values to use for the termination point augmentation;</li>
+ * <li>the initial expected values to check the augmentation against;</li>
+ * <li>the target input values to update the terminal point to;</li>
+ * <li>the target expected values to check the augmentation point against.</li>
+ * </ul>
+ * <p>The following tests are performed:</p>
+ * <ol>
+ * <li>the bridge is added;</li>
+ * <li>the termination point is added, with the provided initial input values;</li>
+ * <li>the termination point is read from the <em>configuration</em> data store, and checked against the provided
+ * initial expected values;</li>
+ * <li>the termination point is read from the <em>operational</em> data store, and checked against the provided
+ * initial expected values;</li>
+ * <li>the termination point is updated by merging the provided target input values;</li>
+ * <li>the termination point is read from the <em>configuration</em> data store, and checked against the provided
+ * initial <b>and</b> target expected values;</li>
+ * <li>the termination point is read from the <em>operational</em> data store, and checked against the provided
+ * initial <b>and</b> target expected values;</li>
+ * <li>the bridge is deleted.</li>
+ * </ol>
+ *
+ * @param <T> The type of data used for the test case.
+ */
+ private final class TestCRUDTerminationPointRunnable<T> implements Runnable {
+ private final SouthboundTestHelper<T> helper;
+ private final ConnectionInfo connectionInfo;
+ private final String testBridgeName;
+ private final String testPortName;
+ private final List<T> updateFromInput;
+ private final List<T> updateFromExpected;
+ private final List<T> updateToInput;
+ private final List<T> updateToExpected;
+
+ private TestCRUDTerminationPointRunnable(
+ SouthboundTestHelper<T> helper, ConnectionInfo connectionInfo, String testBridgeName,
+ String testPortName, List<T> updateFromInput, List<T> updateFromExpected, List<T> updateToInput,
+ List<T> updateToExpected) {
+ this.helper = helper;
this.connectionInfo = connectionInfo;
this.testBridgeName = testBridgeName;
this.testPortName = testPortName;
- this.updateFromInputExternalIds = updateFromInputExternalIds;
- this.updateFromExpectedExternalIds = updateFromExpectedExternalIds;
- this.updateToInputExternalIds = updateToInputExternalIds;
- this.updateToExpectedExternalIds = updateToExpectedExternalIds;
+ this.updateFromInput = updateFromInput;
+ this.updateFromExpected = updateFromExpected;
+ this.updateToInput = updateToInput;
+ this.updateToExpected = updateToExpected;
}
@Override
public void run() {
try {
- test();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- public void test() throws InterruptedException {
-
- final int TERMINATION_POINT_TEST_INDEX = 0;
- // CREATE: Create the test interface
- Assert.assertTrue(addBridge(connectionInfo, null,
- testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
- true, null, null, null, null));
- NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
- connectionInfo, new OvsdbBridgeName(testBridgeName)));
- OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
- createGenericOvsdbTerminationPointAugmentationBuilder();
- tpCreateAugmentationBuilder.setName(testPortName);
- tpCreateAugmentationBuilder.setInterfaceExternalIds(updateFromInputExternalIds);
- Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
-
- // READ: Read the test interface and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<InterfaceExternalIds> updateFromConfigurationExternalIds =
- updateFromConfigurationTerminationPointAugmentation
- .getInterfaceExternalIds();
- assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
- updateFromConfigurationExternalIds);
- OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmenation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<InterfaceExternalIds> updateFromOperationalExternalIds =
- updateFromOperationalTerminationPointAugmenation
- .getInterfaceExternalIds();
- assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
- updateFromOperationalExternalIds);
-
- // UPDATE: update the external_ids
- testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
- OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
- new OvsdbTerminationPointAugmentationBuilder();
- tpUpdateAugmentationBuilder.setInterfaceExternalIds(updateToInputExternalIds);
- InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
- NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
- NodeId portUpdateNodeId = createManagedNodeId(portIid);
- portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
- TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
- tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
- tpUpdateBuilder.addAugmentation(
- OvsdbTerminationPointAugmentation.class,
- tpUpdateAugmentationBuilder.build());
- portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
- boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
- portIid, portUpdateNodeBuilder.build());
- Thread.sleep(OVSDB_UPDATE_TIMEOUT);
- Assert.assertTrue(result);
+ final int TERMINATION_POINT_TEST_INDEX = 0;
+ // CREATE: Create the test bridge
+ Assert.assertTrue(addBridge(connectionInfo, null,
+ testBridgeName, null, true,
+ SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
+ true, null, null, null, null));
+ NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
+ connectionInfo, new OvsdbBridgeName(testBridgeName)));
+ OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
+ createGenericOvsdbTerminationPointAugmentationBuilder();
+ tpCreateAugmentationBuilder.setName(testPortName);
+ helper.writeValues(tpCreateAugmentationBuilder, updateFromInput);
+ Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
+
+ // READ: Read the test port and ensure changes are propagated to the CONFIGURATION data store,
+ // then repeat for OPERATIONAL data store
+ OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
+ getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
+ LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
+ List<T> updateFromConfiguration = null;
+ if (updateFromConfigurationTerminationPointAugmentation != null) {
+ updateFromConfiguration =
+ helper.readValues(updateFromConfigurationTerminationPointAugmentation);
+ }
+ if (updateFromConfiguration != null) {
+ Assert.assertTrue(updateFromConfiguration.containsAll(updateFromExpected));
+ }
+ OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
+ getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
+ LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
+ List<T> updateFromOperational = null;
+ if (updateFromOperationalTerminationPointAugmentation != null) {
+ updateFromOperational = helper.readValues(updateFromOperationalTerminationPointAugmentation);
+ }
+ if (updateFromOperational != null) {
+ Assert.assertTrue(updateFromOperational.containsAll(updateFromExpected));
+ }
- // READ: the test interface and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<InterfaceExternalIds> updateToConfigurationExternalIds =
- updateToConfigurationTerminationPointAugmentation
- .getInterfaceExternalIds();
- assertExpectedInterfaceExternalIdsExist(updateToExpectedExternalIds, updateToConfigurationExternalIds);
- assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
- updateToConfigurationExternalIds);
- OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<InterfaceExternalIds> updateToOperationalExternalIds = updateToOperationalTerminationPointAugmentation
- .getInterfaceExternalIds();
- if (updateFromExpectedExternalIds != null) {
- assertExpectedInterfaceExternalIdsExist(updateToExpectedExternalIds,
- updateToOperationalExternalIds);
- assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
- updateToOperationalExternalIds);
- } else {
- Assert.assertNull(updateToOperationalExternalIds);
+ // UPDATE: update the external_ids
+ testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
+ OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
+ new OvsdbTerminationPointAugmentationBuilder();
+ helper.writeValues(tpUpdateAugmentationBuilder, updateToInput);
+ InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
+ NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
+ NodeId portUpdateNodeId = createManagedNodeId(portIid);
+ portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
+ TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
+ tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
+ tpUpdateBuilder.addAugmentation(
+ OvsdbTerminationPointAugmentation.class,
+ tpUpdateAugmentationBuilder.build());
+ portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
+ boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
+ portIid, portUpdateNodeBuilder.build());
+ Thread.sleep(OVSDB_UPDATE_TIMEOUT);
+ Assert.assertTrue(result);
+
+ // READ: the test port and ensure changes are propagated to the CONFIGURATION data store,
+ // then repeat for OPERATIONAL data store
+ OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
+ getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
+ LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
+ List<T> updateToConfiguration = helper.readValues(updateToConfigurationTerminationPointAugmentation);
+ Assert.assertTrue(updateToConfiguration.containsAll(updateToExpected));
+ Assert.assertTrue(updateToConfiguration.containsAll(updateFromExpected));
+ OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
+ getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
+ LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
+ List<T> updateToOperational = helper.readValues(updateToOperationalTerminationPointAugmentation);
+ Assert.assertTrue(updateToOperational.containsAll(updateToExpected));
+ Assert.assertTrue(updateToOperational.containsAll(updateFromExpected));
+
+ // DELETE
+ Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
+ } catch (InterruptedException e) {
+ LOG.error("Test interrupted", e);
}
-
- // DELETE
- Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
}
}
- /*
- * Generates the test cases involved in testing TP Options. See inline comments for descriptions of
- * the particular cases considered.
- *
- * The return value is a Map in the form (K,V)=(testCaseName,testCase).
- * - testCaseName is a String
- * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
- * either corresponding INPUT TP Options, or EXPECTED TP Options
- * INPUT is the List we use when calling
- * <code>TerminationPointAugmentationBuilder.setOptions()</code>
- * EXPECTED is the List we expect to receive after calling
- * <code>TerminationPointAugmentationBuilder.getOptions()</code>
- */
- private Map<String, Map<String, List<Options>>> generateTerminationPointOptionsTestCases() {
- Map<String, Map<String, List<Options>>> testMap = new HashMap<>();
-
- final String TP_OPTIONS_KEY = "TPOptionsKey";
- final String TP_OPTIONS_VALUE = "TPOptionsValue";
- final String FORMAT_STR = "%s_%s_%d";
- final String GOOD_KEY = "GoodKey";
- final String GOOD_VALUE = "GoodValue";
- final String NO_VALUE_FOR_KEY = "NoValueForKey";
- final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
- // Test Case 1: TestOneOptions
- // Test Type: Positive
- // Description: Create a termination point with one Options
- // Expected: A termination point is created with the single Options specified below
- final String testOneOptionsName = "TestOneOptions";
- int optionsCounter = 0;
- List<Options> oneOptions = Lists.newArrayList(
- (new OptionsBuilder()
- .setOption(String.format(FORMAT_STR, testOneOptionsName,
- TP_OPTIONS_KEY, ++optionsCounter))
- .setValue(String.format(FORMAT_STR, testOneOptionsName,
- TP_OPTIONS_VALUE, optionsCounter))
- .build()));
- Map<String,List<Options>> testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, oneOptions);
- testCase.put(INPUT_VALUES_KEY, oneOptions);
- testMap.put(testOneOptionsName, testCase);
-
- // Test Case 2: TestFiveOptions
- // Test Type: Positive
- // Description: Create a termination point with multiple (five) Options
- // Expected: A termination point is created with the five options specified below
- final String testFiveOptionsName = "TestFiveOptions";
- optionsCounter = 0;
- List<Options> fiveOptions = Lists.newArrayList(
- (new OptionsBuilder()
- .setOption(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_KEY, ++optionsCounter))
- .setValue(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_VALUE, optionsCounter))
- .build()),
- (new OptionsBuilder()
- .setOption(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_KEY, ++optionsCounter))
- .setValue(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_VALUE, optionsCounter))
- .build()),
- (new OptionsBuilder()
- .setOption(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_KEY, ++optionsCounter))
- .setValue(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_VALUE, optionsCounter))
- .build()),
- (new OptionsBuilder()
- .setOption(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_KEY, ++optionsCounter))
- .setValue(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_VALUE, optionsCounter))
- .build()),
- (new OptionsBuilder()
- .setOption(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_KEY, ++optionsCounter))
- .setValue(String.format(FORMAT_STR, testFiveOptionsName,
- TP_OPTIONS_VALUE, optionsCounter))
- .build()));
- testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, fiveOptions);
- testCase.put(INPUT_VALUES_KEY, fiveOptions);
- testMap.put(testFiveOptionsName, testCase);
-
- // Test Case 3: TestOneGoodOptionsOneMalformedOptionsValue
- // Test Type: Negative
- // Description:
- // One perfectly fine Options
- // (TestOneGoodOptionsOneMalformedOptionsValue_OptionsKey_1,
- // TestOneGoodOptionsOneMalformedOptions_OptionsValue_1)
- // and one malformed Options which only has key specified
- // (TestOneGoodOptionsOneMalformedOptionsValue_NoValueForKey_2,
- // UNSPECIFIED)
- // Expected: A termination point is created without any options
- final String testOneGoodOptionsOneMalformedOptionsValueName =
- "TestOneGoodOptionsOneMalformedOptionsValue";
- optionsCounter = 0;
- Options oneGood = new OptionsBuilder()
- .setOption(String.format(FORMAT_STR, testOneGoodOptionsOneMalformedOptionsValueName,
- GOOD_KEY, ++optionsCounter))
- .setValue(String.format(FORMAT_STR,
- testOneGoodOptionsOneMalformedOptionsValueName,
- GOOD_VALUE, optionsCounter))
- .build();
- Options oneBad = new OptionsBuilder()
- .setOption(String.format(FORMAT_STR,
- testOneGoodOptionsOneMalformedOptionsValueName, NO_VALUE_FOR_KEY, ++optionsCounter))
- .build();
- List<Options> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- List<Options> oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodOptionsOneMalformedOptionsValueName, testCase);
-
- // Test Case 4: TestOneGoodOptionsOneMalformedOptionsKey
- // Test Type: Negative
- // Description:
- // One perfectly fine Options
- // (TestOneGoodOptionsOneMalformedOptionsValue_OptionsKey_1,
- // TestOneGoodOptionsOneMalformedOptions_OptionsValue_1)
- // and one malformed Options which only has key specified
- // (UNSPECIFIED,
- // TestOneGoodOptionsOneMalformedOptionsKey_NoKeyForValue_2)
- // Expected: A termination point is created without any options
- final String testOneGoodOptionsOneMalformedOptionsKeyName =
- "TestOneGoodOptionsOneMalformedOptionsKey";
- optionsCounter = 0;
- oneGood = new OptionsBuilder()
- .setOption(String.format(FORMAT_STR, testOneGoodOptionsOneMalformedOptionsKeyName,
- GOOD_KEY, ++optionsCounter))
- .setValue(String.format(FORMAT_STR,
- testOneGoodOptionsOneMalformedOptionsKeyName,
- GOOD_VALUE, optionsCounter))
- .build();
- oneBad = new OptionsBuilder()
- .setOption(String.format(FORMAT_STR,
- testOneGoodOptionsOneMalformedOptionsKeyName, NO_KEY_FOR_VALUE, ++optionsCounter))
- .build();
- oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodOptionsOneMalformedOptionsKeyName, testCase);
-
- return testMap;
- }
/*
- * @see <code>SouthboundIT.testCRUDTerminationPointOptions()</code>
- * This is helper test method to compare a test "set" of Options against an expected "set"
+ * Generates the test cases involved in testing InterfaceExternalIds. See inline comments for descriptions of
+ * the particular cases considered.
*/
- private void assertExpectedOptionsExist( List<Options> expected,
- List<Options> test ) {
-
- if (expected != null) {
- for (Options expectedOption : expected) {
- Assert.assertTrue(test.contains(expectedOption));
- }
- }
+ private static List<SouthboundTestCase<InterfaceExternalIds>> generateInterfaceExternalIdsTestCases() {
+ return generateKeyValueTestCases(new SouthboundInterfaceExternalIdsBuilder(), "IntExternalIdKey",
+ "IntExternalIdValue");
}
/*
- * Tests the CRUD operations for <code>TerminationPoint</code> <code>options</code>.
+ * Tests the CRUD operations for <code>Interface</code> <code>external_ids</code>.
*
- * @see <code>SouthboundIT.generateTerminationPointOptions()</code> for specific test case information
+ * @see <code>SouthboundIT.generateInterfaceExternalIdsTestCases()</code> for specific test case information
*/
@Test
- public void testCRUDTerminationPointOptions() throws InterruptedException {
- final String TEST_PREFIX = "CRUDTPOptions";
+ public void testCRUDTerminationPointInterfaceExternalIds() throws InterruptedException, ExecutionException {
+ final String TEST_PREFIX = "CRUDTPInterfaceExternalIds";
ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
connectOvsdbNode(connectionInfo);
// updateFromTestCases represent the original test case value. updateToTestCases represent the new value after
// the update has been performed.
- Map<String, Map<String, List<Options>>> updateFromTestCases =
- generateTerminationPointOptionsTestCases();
- Map<String, Map<String, List<Options>>> updateToTestCases =
- generateTerminationPointOptionsTestCases();
- Map<String, List<Options>> updateFromTestCase;
- List<Options> updateFromInputOptions;
- List<Options> updateFromExpectedOptions;
- Map<String, List<Options>> updateToTestCase;
- List<Options> updateToInputOptions;
- List<Options> updateToExpectedOptions;
+ List<SouthboundTestCase<InterfaceExternalIds>> updateFromTestCases = generateInterfaceExternalIdsTestCases();
+ List<SouthboundTestCase<InterfaceExternalIds>> updateToTestCases = generateInterfaceExternalIdsTestCases();
String testBridgeName;
String testPortName;
int counter = 1;
+ // multithreads the test using NUM_THREADS
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
- for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
- updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
- updateFromInputOptions = updateFromTestCase.get(INPUT_VALUES_KEY);
- updateFromExpectedOptions = updateFromTestCase.get(EXPECTED_VALUES_KEY);
- for (String testCaseKey : updateToTestCases.keySet()) {
- testPortName = testBridgeName = String.format("%s_%s_%d", TEST_PREFIX, testCaseKey, counter);
+ for (SouthboundTestCase<InterfaceExternalIds> fromTestCase : updateFromTestCases) {
+ for (SouthboundTestCase<InterfaceExternalIds> toTestCase : updateToTestCases) {
+ testPortName = testBridgeName = String.format(FORMAT_STR,
+ TEST_PREFIX, toTestCase.name, counter);
counter += 1;
- updateToTestCase = updateToTestCases.get(testCaseKey);
- updateToInputOptions = updateToTestCase.get(INPUT_VALUES_KEY);
- updateToExpectedOptions = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
- TestCRUDTerminationPointOptionsRunnable testRunnable =
- new TestCRUDTerminationPointOptionsRunnable(
- connectionInfo, testBridgeName, testPortName,
- updateFromInputOptions,
- updateFromExpectedOptions,
- updateToInputOptions,
- updateToExpectedOptions);
- executor.submit(testRunnable);
+ executor.submit(new TestCRUDTerminationPointRunnable<>(
+ new SouthboundTestHelper<InterfaceExternalIds>() {
+ @Override
+ public List<InterfaceExternalIds> readValues(
+ OvsdbTerminationPointAugmentation augmentation) {
+ return augmentation.getInterfaceExternalIds();
+ }
+
+ @Override
+ public void writeValues(
+ OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+ List<InterfaceExternalIds> values) {
+ augmentationBuilder.setInterfaceExternalIds(values);
+ }
+ },
+ connectionInfo, testBridgeName, testPortName,
+ fromTestCase.inputValues,
+ fromTestCase.expectedValues,
+ toTestCase.inputValues,
+ toTestCase.expectedValues));
}
}
executor.shutdown();
Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
}
- class TestCRUDTerminationPointOptionsRunnable implements Runnable {
-
- ConnectionInfo connectionInfo;
- String testBridgeName;
- String testPortName;
- List<Options> updateFromInputOptions;
- List<Options> updateFromExpectedOptions;
- List<Options> updateToInputOptions;
- List<Options> updateToExpectedOptions;
-
- TestCRUDTerminationPointOptionsRunnable(
- ConnectionInfo connectionInfo, String testBridgeName,
- String testPortName,
- List<Options> updateFromInputOptions,
- List<Options> updateFromExpectedOptions,
- List<Options> updateToInputOptions,
- List<Options> updateToExpectedOptions) {
-
- this.connectionInfo = connectionInfo;
- this.testBridgeName = testBridgeName;
- this.testPortName = testPortName;
- this.updateFromInputOptions = updateFromInputOptions;
- this.updateFromExpectedOptions = updateFromExpectedOptions;
- this.updateToInputOptions = updateToInputOptions;
- this.updateToExpectedOptions = updateToExpectedOptions;
- }
-
- @Override
- public void run() {
- try {
- test();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- public void test() throws InterruptedException {
- final int TERMINATION_POINT_TEST_INDEX = 0;
- // CREATE: Create the test interface
- Assert.assertTrue(addBridge(connectionInfo, null,
- testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
- true, null, null, null, null));
- NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
- connectionInfo, new OvsdbBridgeName(testBridgeName)));
- OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
- createGenericOvsdbTerminationPointAugmentationBuilder();
- tpCreateAugmentationBuilder.setName(testPortName);
- tpCreateAugmentationBuilder.setOptions(updateFromInputOptions);
- Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
-
- // READ: Read the test interface and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<Options> updateFromConfigurationOptions = updateFromConfigurationTerminationPointAugmentation
- .getOptions();
- assertExpectedOptionsExist(updateFromExpectedOptions,
- updateFromConfigurationOptions);
- OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<Options> updateFromOperationalOptions = updateFromOperationalTerminationPointAugmentation
- .getOptions();
- assertExpectedOptionsExist(updateFromExpectedOptions,
- updateFromOperationalOptions);
-
- // UPDATE: update the external_ids
- testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
- OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
- new OvsdbTerminationPointAugmentationBuilder();
- tpUpdateAugmentationBuilder.setOptions(updateToInputOptions);
- InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
- NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
- NodeId portUpdateNodeId = createManagedNodeId(portIid);
- portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
- TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
- tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
- tpUpdateBuilder.addAugmentation(
- OvsdbTerminationPointAugmentation.class,
- tpUpdateAugmentationBuilder.build());
- portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
- boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
- portIid, portUpdateNodeBuilder.build());
- Thread.sleep(OVSDB_UPDATE_TIMEOUT);
- Assert.assertTrue(result);
-
- // READ: the test interface and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<Options> updateToConfigurationOptions = updateToConfigurationTerminationPointAugmentation
- .getOptions();
- assertExpectedOptionsExist(updateToExpectedOptions, updateToConfigurationOptions);
- assertExpectedOptionsExist(updateFromExpectedOptions, updateToConfigurationOptions);
- OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<Options> updateToOperationalOptions = updateToOperationalTerminationPointAugmentation
- .getOptions();
- if (updateFromExpectedOptions != null) {
- assertExpectedOptionsExist(updateToExpectedOptions, updateToOperationalOptions);
- assertExpectedOptionsExist(updateFromExpectedOptions, updateToOperationalOptions);
- }
-
- // DELETE
- Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
- }
- }
-
/*
- * Generates the test cases involved in testing Interface other_configs. See inline comments for descriptions of
- * the particular cases considered.
- *
- * The return value is a Map in the form (K,V)=(testCaseName,testCase).
- * - testCaseName is a String
- * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
- * either corresponding INPUT interface other_configs, or EXPECTED interface other_configs
- * INPUT is the List we use when calling
- * <code>TerminationPointAugmentationBuilder.setInterfaceOtherConfigs()</code>
- * EXPECTED is the List we expect to receive after calling
- * <code>TerminationPointAugmentationBuilder.getInterfaceOtherConfigs()</code>
- */
- private Map<String, Map<String, List<InterfaceOtherConfigs>>> generateInterfaceOtherConfigsTestCases() {
- Map<String, Map<String, List<InterfaceOtherConfigs>>> testMap = new HashMap<>();
-
- final String INT_OTHER_CONFIGS_KEY = "IntOtherConfigsKey";
- final String INT_OTHER_CONFIGS_VALUE = "IntOtherConfigsValue";
- final String FORMAT_STR = "%s_%s_%d";
- final String GOOD_KEY = "GoodKey";
- final String GOOD_VALUE = "GoodValue";
- final String NO_VALUE_FOR_KEY = "NoValueForKey";
- final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
- // Test Case 1: TestOneOtherConfigs
- // Test Type: Positive
- // Description: Create an interface with one other_Configs
- // Expected: An interface is created with the single other_configs specified below
- final String testOneOtherConfigsName = "TestOneInterfaceOtherConfigs";
- int otherConfigsCounter = 0;
- List<InterfaceOtherConfigs> oneOtherConfigs = Lists.newArrayList(
- (new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testOneOtherConfigsName,
- INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testOneOtherConfigsName,
- INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()));
- Map<String,List<InterfaceOtherConfigs>> testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, oneOtherConfigs);
- testCase.put(INPUT_VALUES_KEY, oneOtherConfigs);
- testMap.put(testOneOtherConfigsName, testCase);
-
- // Test Case 2: TestFiveInterfaceOtherConfigs
- // Test Type: Positive
- // Description: Create a termination point with multiple (five) InterfaceOtherConfigs
- // Expected: A termination point is created with the five InterfaceOtherConfigs specified below
- final String testFiveInterfaceOtherConfigsName = "TestFiveInterfaceOtherConfigs";
- otherConfigsCounter = 0;
- List<InterfaceOtherConfigs> fiveInterfaceOtherConfigs = Lists.newArrayList(
- (new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()),
- (new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()),
- (new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()),
- (new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()),
- (new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
- INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()));
- testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, fiveInterfaceOtherConfigs);
- testCase.put(INPUT_VALUES_KEY, fiveInterfaceOtherConfigs);
- testMap.put(testFiveInterfaceOtherConfigsName, testCase);
-
- // Test Case 3: TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue
- // Test Type: Negative
- // Description:
- // One perfectly fine InterfaceOtherConfigs
- // (TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue_InterfaceOtherConfigsKey_1,
- // TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigs_InterfaceOtherConfigsValue_1)
- // and one malformed InterfaceOtherConfigs which only has key specified
- // (TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue_NoValueForKey_2,
- // UNSPECIFIED)
- // Expected: A termination point is created without any InterfaceOtherConfigs
- final String testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName =
- "TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue";
- otherConfigsCounter = 0;
- InterfaceOtherConfigs oneGood = new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName,
- GOOD_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR,
- testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName,
- GOOD_VALUE, otherConfigsCounter))
- .build();
- InterfaceOtherConfigs oneBad = new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName, NO_VALUE_FOR_KEY,
- ++otherConfigsCounter))
- .build();
- List<InterfaceOtherConfigs> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- List<InterfaceOtherConfigs> oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName, testCase);
-
- // Test Case 4: TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKey
- // Test Type: Negative
- // Description:
- // One perfectly fine InterfaceOtherConfigs
- // (TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue_InterfaceOtherConfigsKey_1,
- // TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigs_InterfaceOtherConfigsValue_1)
- // and one malformed InterfaceOtherConfigs which only has key specified
- // (UNSPECIFIED,
- // TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKey_NoKeyForValue_2)
- // Expected: A termination point is created without any InterfaceOtherConfigs
- final String testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName =
- "TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKey";
- otherConfigsCounter = 0;
- oneGood = new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName,
- GOOD_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR,
- testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName,
- GOOD_VALUE, otherConfigsCounter))
- .build();
- oneBad = new InterfaceOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName, NO_KEY_FOR_VALUE,
- ++otherConfigsCounter))
- .build();
- oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName, testCase);
-
- return testMap;
+ * Generates the test cases involved in testing TP Options. See inline comments for descriptions of
+ * the particular cases considered.
+ */
+ private List<SouthboundTestCase<Options>> generateTerminationPointOptionsTestCases() {
+ return generateKeyValueTestCases(new SouthboundOptionsBuilder(), "TOPOptionsKey", "TPOptionsValue");
}
/*
- * @see <code>SouthboundIT.testCRUDInterfaceOtherConfigs()</code>
- * This is helper test method to compare a test "set" of Options against an expected "set"
+ * Tests the CRUD operations for <code>TerminationPoint</code> <code>options</code>.
+ *
+ * @see <code>SouthboundIT.generateTerminationPointOptions()</code> for specific test case information
*/
- private void assertExpectedInterfaceOtherConfigsExist( List<InterfaceOtherConfigs> expected,
- List<InterfaceOtherConfigs> test ) {
+ @Test
+ public void testCRUDTerminationPointOptions() throws InterruptedException {
+ final String TEST_PREFIX = "CRUDTPOptions";
+
+ ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
+ connectOvsdbNode(connectionInfo);
+
+ // updateFromTestCases represent the original test case value. updateToTestCases represent the new value after
+ // the update has been performed.
+ List<SouthboundTestCase<Options>> updateFromTestCases = generateTerminationPointOptionsTestCases();
+ List<SouthboundTestCase<Options>> updateToTestCases = generateTerminationPointOptionsTestCases();
+ String testBridgeName;
+ String testPortName;
- if (expected != null && test != null) {
- for (InterfaceOtherConfigs expectedOtherConfigs : expected) {
- Assert.assertTrue(test.contains(expectedOtherConfigs));
+ int counter = 1;
+ ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
+ for (SouthboundTestCase<Options> fromTestCase : updateFromTestCases) {
+ for (SouthboundTestCase<Options> toTestCase : updateToTestCases) {
+ testPortName = testBridgeName = String.format(FORMAT_STR,
+ TEST_PREFIX, toTestCase.name, counter);
+ counter += 1;
+ executor.submit(new TestCRUDTerminationPointRunnable<>(
+ new SouthboundTestHelper<Options>() {
+ @Override
+ public List<Options> readValues(
+ OvsdbTerminationPointAugmentation augmentation) {
+ return augmentation.getOptions();
+ }
+
+ @Override
+ public void writeValues(
+ OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+ List<Options> values) {
+ augmentationBuilder.setOptions(values);
+ }
+ },
+ connectionInfo, testBridgeName, testPortName,
+ fromTestCase.inputValues,
+ fromTestCase.expectedValues,
+ toTestCase.inputValues,
+ toTestCase.expectedValues));
}
}
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.MINUTES);
+ Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+ }
+
+ /*
+ * Generates the test cases involved in testing Interface other_configs. See inline comments for descriptions of
+ * the particular cases considered.
+ */
+ private List<SouthboundTestCase<InterfaceOtherConfigs>> generateInterfaceOtherConfigsTestCases() {
+ return generateKeyValueTestCases(new SouthboundInterfaceOtherConfigsBuilder(), "IntOtherConfigsKey",
+ "IntOtherConfigsValue");
}
/*
// updateFromTestCases represent the original test case value. updateToTestCases represent the new value after
// the update has been performed.
- Map<String, Map<String, List<InterfaceOtherConfigs>>> updateFromTestCases =
- generateInterfaceOtherConfigsTestCases();
- Map<String, Map<String, List<InterfaceOtherConfigs>>> updateToTestCases =
- generateInterfaceOtherConfigsTestCases();
- Map<String, List<InterfaceOtherConfigs>> updateFromTestCase;
- List<InterfaceOtherConfigs> updateFromInputOtherConfigs;
- List<InterfaceOtherConfigs> updateFromExpectedOtherConfigs;
- Map<String, List<InterfaceOtherConfigs>> updateToTestCase;
- List<InterfaceOtherConfigs> updateToInputOtherConfigs;
- List<InterfaceOtherConfigs> updateToExpectedOtherConfigs;
+ List<SouthboundTestCase<InterfaceOtherConfigs>> updateFromTestCases = generateInterfaceOtherConfigsTestCases();
+ List<SouthboundTestCase<InterfaceOtherConfigs>> updateToTestCases = generateInterfaceOtherConfigsTestCases();
String testBridgeName;
String testPortName;
int counter = 1;
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
- for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
- updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
- updateFromInputOtherConfigs = updateFromTestCase.get(INPUT_VALUES_KEY);
- updateFromExpectedOtherConfigs = updateFromTestCase.get(EXPECTED_VALUES_KEY);
- for (String testCaseKey : updateToTestCases.keySet()) {
- testPortName = testBridgeName = String.format("%s_%s_%d", TEST_PREFIX, testCaseKey, counter);
+ for (SouthboundTestCase<InterfaceOtherConfigs> fromTestCase : updateFromTestCases) {
+ for (SouthboundTestCase<InterfaceOtherConfigs> toTestCase : updateToTestCases) {
+ testPortName = testBridgeName = String.format(FORMAT_STR,
+ TEST_PREFIX, toTestCase.name, counter);
counter += 1;
- updateToTestCase = updateToTestCases.get(testCaseKey);
- updateToInputOtherConfigs = updateToTestCase.get(INPUT_VALUES_KEY);
- updateToExpectedOtherConfigs = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
- TestCRUDTerminationPointInterfaceOtherConfigsRunnable testRunnable =
- new TestCRUDTerminationPointInterfaceOtherConfigsRunnable(
- connectionInfo, testBridgeName, testPortName,
- updateFromInputOtherConfigs,
- updateFromExpectedOtherConfigs,
- updateToInputOtherConfigs,
- updateToExpectedOtherConfigs);
- executor.submit(testRunnable);
+ executor.submit(new TestCRUDTerminationPointRunnable<>(
+ new SouthboundTestHelper<InterfaceOtherConfigs>() {
+ @Override
+ public List<InterfaceOtherConfigs> readValues(
+ OvsdbTerminationPointAugmentation augmentation) {
+ return augmentation.getInterfaceOtherConfigs();
+ }
+
+ @Override
+ public void writeValues(
+ OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+ List<InterfaceOtherConfigs> values) {
+ augmentationBuilder.setInterfaceOtherConfigs(values);
+ }
+ },
+ connectionInfo, testBridgeName, testPortName,
+ fromTestCase.inputValues,
+ fromTestCase.expectedValues,
+ toTestCase.inputValues,
+ toTestCase.expectedValues));
}
}
executor.shutdown();
Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
}
- class TestCRUDTerminationPointInterfaceOtherConfigsRunnable implements Runnable {
-
- ConnectionInfo connectionInfo;
- String testBridgeName;
- String testPortName;
- List<InterfaceOtherConfigs> updateFromInputOtherConfigs;
- List<InterfaceOtherConfigs> updateFromExpectedOtherConfigs;
- List<InterfaceOtherConfigs> updateToInputOtherConfigs;
- List<InterfaceOtherConfigs> updateToExpectedOtherConfigs;
-
- TestCRUDTerminationPointInterfaceOtherConfigsRunnable(
- ConnectionInfo connectionInfo, String testBridgeName,
- String testPortName,
- List<InterfaceOtherConfigs> updateFromInputOtherConfigs,
- List<InterfaceOtherConfigs> updateFromExpectedOtherConfigs,
- List<InterfaceOtherConfigs> updateToInputOtherConfigs,
- List<InterfaceOtherConfigs> updateToExpectedOtherConfigs) {
-
- this.connectionInfo = connectionInfo;
- this.testBridgeName = testBridgeName;
- this.testPortName = testPortName;
- this.updateFromInputOtherConfigs = updateFromInputOtherConfigs;
- this.updateFromExpectedOtherConfigs = updateFromExpectedOtherConfigs;
- this.updateToInputOtherConfigs = updateToInputOtherConfigs;
- this.updateToExpectedOtherConfigs = updateToExpectedOtherConfigs;
- }
-
- @Override
- public void run() {
- try {
- test();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- public void test() throws InterruptedException {
- final int TERMINATION_POINT_TEST_INDEX = 0;
-
- // CREATE: Create the test interface
- Assert.assertTrue(addBridge(connectionInfo, null,
- testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
- true, null, null, null, null));
- NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
- connectionInfo, new OvsdbBridgeName(testBridgeName)));
- OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
- createGenericOvsdbTerminationPointAugmentationBuilder();
- tpCreateAugmentationBuilder.setName(testPortName);
- tpCreateAugmentationBuilder.setInterfaceOtherConfigs(updateFromInputOtherConfigs);
- Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
-
- // READ: Read the test interface and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<InterfaceOtherConfigs> updateFromConfigurationOtherConfigs;
- if (updateFromConfigurationTerminationPointAugmentation != null) {
- updateFromConfigurationOtherConfigs = updateFromConfigurationTerminationPointAugmentation
- .getInterfaceOtherConfigs();
- } else {
- updateFromConfigurationOtherConfigs = null;
- }
- assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
- updateFromConfigurationOtherConfigs);
- OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmenation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<InterfaceOtherConfigs> updateFromOperationalOtherConfigs =
- updateFromOperationalTerminationPointAugmenation.getInterfaceOtherConfigs();
- if (updateFromOperationalOtherConfigs != null) {
- updateFromOperationalOtherConfigs = updateFromOperationalTerminationPointAugmenation
- .getInterfaceOtherConfigs();
- } else {
- updateFromOperationalOtherConfigs = null;
- }
- assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
- updateFromOperationalOtherConfigs);
-
- // UPDATE: update the other_configs
- testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
- OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
- new OvsdbTerminationPointAugmentationBuilder();
- tpUpdateAugmentationBuilder.setInterfaceOtherConfigs(updateToInputOtherConfigs);
- InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
- NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
- NodeId portUpdateNodeId = createManagedNodeId(portIid);
- portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
- TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
- tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
- tpUpdateBuilder.addAugmentation(
- OvsdbTerminationPointAugmentation.class,
- tpUpdateAugmentationBuilder.build());
- portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
- boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
- portIid, portUpdateNodeBuilder.build());
- Thread.sleep(OVSDB_UPDATE_TIMEOUT);
- Assert.assertTrue(result);
-
- // READ: the test interface and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<InterfaceOtherConfigs> updateToConfigurationOtherConfigs =
- updateToConfigurationTerminationPointAugmentation
- .getInterfaceOtherConfigs();
- assertExpectedInterfaceOtherConfigsExist(updateToExpectedOtherConfigs,
- updateToConfigurationOtherConfigs);
- assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
- updateToConfigurationOtherConfigs);
- OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<InterfaceOtherConfigs> updateToOperationalOtherConfigs =
- updateToOperationalTerminationPointAugmentation
- .getInterfaceOtherConfigs();
- if (updateFromExpectedOtherConfigs != null) {
- assertExpectedInterfaceOtherConfigsExist(updateToExpectedOtherConfigs,
- updateToOperationalOtherConfigs);
- assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
- updateToOperationalOtherConfigs);
- }
-
- // DELETE
- Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
- }
- }
-
/*
* Generates the test cases involved in testing Port other_configs. See inline comments for descriptions of
* the particular cases considered.
- *
- * The return value is a Map in the form (K,V)=(testCaseName,testCase).
- * - testCaseName is a String
- * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
- * either corresponding INPUT port other_configs, or EXPECTED port other_configs
- * INPUT is the List we use when calling
- * <code>TerminationPointAugmentationBuilder.setPortOtherConfigs()</code>
- * EXPECTED is the List we expect to receive after calling
- * <code>TerminationPointAugmentationBuilder.getPortOtherConfigs()</code>
- */
- private Map<String, Map<String, List<PortOtherConfigs>>> generatePortOtherConfigsTestCases() {
- Map<String, Map<String, List<PortOtherConfigs>>> testMap = new HashMap<>();
-
- final String PORT_OTHER_CONFIGS_KEY = "PortOtherConfigsKey";
- final String PORT_OTHER_CONFIGS_VALUE = "PortOtherConfigsValue";
- final String FORMAT_STR = "%s_%s_%d";
- final String GOOD_KEY = "GoodKey";
- final String GOOD_VALUE = "GoodValue";
- final String NO_VALUE_FOR_KEY = "NoValueForKey";
- final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
- // Test Case 1: TestOneOtherConfigs
- // Test Type: Positive
- // Description: Create an port with one other_Configs
- // Expected: A port is created with the single other_configs specified below
- final String testOneOtherConfigsName = "TestOnePortOtherConfigs";
- int otherConfigsCounter = 0;
- List<PortOtherConfigs> oneOtherConfigs = Lists.newArrayList(
- (new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testOneOtherConfigsName,
- PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testOneOtherConfigsName,
- PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()));
- Map<String,List<PortOtherConfigs>> testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, oneOtherConfigs);
- testCase.put(INPUT_VALUES_KEY, oneOtherConfigs);
- testMap.put(testOneOtherConfigsName, testCase);
-
- // Test Case 2: TestFivePortOtherConfigs
- // Test Type: Positive
- // Description: Create a termination point with multiple (five) PortOtherConfigs
- // Expected: A termination point is created with the five PortOtherConfigs specified below
- final String testFivePortOtherConfigsName = "TestFivePortOtherConfigs";
- otherConfigsCounter = 0;
- List<PortOtherConfigs> fivePortOtherConfigs = Lists.newArrayList(
- (new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()),
- (new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()),
- (new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()),
- (new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()),
- (new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
- PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
- .build()));
- testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, fivePortOtherConfigs);
- testCase.put(INPUT_VALUES_KEY, fivePortOtherConfigs);
- testMap.put(testFivePortOtherConfigsName, testCase);
-
- // Test Case 3: TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue
- // Test Type: Negative
- // Description:
- // One perfectly fine PortOtherConfigs
- // (TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue_PortOtherConfigsKey_1,
- // TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigs_PortOtherConfigsValue_1)
- // and one malformed PortOtherConfigs which only has key specified
- // (TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue_NoValueForKey_2,
- // UNSPECIFIED)
- // Expected: A termination point is created without any PortOtherConfigs
- final String testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName =
- "TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue";
- otherConfigsCounter = 0;
- PortOtherConfigs oneGood = new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName,
- GOOD_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR,
- testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName,
- GOOD_VALUE, otherConfigsCounter))
- .build();
- PortOtherConfigs oneBad = new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName, NO_VALUE_FOR_KEY,
- ++otherConfigsCounter))
- .build();
- List<PortOtherConfigs> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- List<PortOtherConfigs> oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName, testCase);
-
- // Test Case 4: TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKey
- // Test Type: Negative
- // Description:
- // One perfectly fine PortOtherConfigs
- // (TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue_PortOtherConfigsKey_1,
- // TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigs_PortOtherConfigsValue_1)
- // and one malformed PortOtherConfigs which only has key specified
- // (UNSPECIFIED,
- // TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKey_NoKeyForValue_2)
- // Expected: A termination point is created without any PortOtherConfigs
- final String testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName =
- "TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKey";
- otherConfigsCounter = 0;
- oneGood = new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName,
- GOOD_KEY, ++otherConfigsCounter))
- .setOtherConfigValue(String.format(FORMAT_STR,
- testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName,
- GOOD_VALUE, otherConfigsCounter))
- .build();
- oneBad = new PortOtherConfigsBuilder()
- .setOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName, NO_KEY_FOR_VALUE,
- ++otherConfigsCounter))
- .build();
- oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName, testCase);
-
- return testMap;
- }
-
- /*
- * @see <code>SouthboundIT.testCRUDPortOtherConfigs()</code>
- * This is helper test method to compare a test "set" of Options against an expected "set"
*/
- private void assertExpectedPortOtherConfigsExist( List<PortOtherConfigs> expected,
- List<PortOtherConfigs> test ) {
-
- if (expected != null && test != null) {
- for (PortOtherConfigs expectedOtherConfigs : expected) {
- Assert.assertTrue(test.contains(expectedOtherConfigs));
- }
- }
+ private List<SouthboundTestCase<PortOtherConfigs>> generatePortOtherConfigsTestCases() {
+ return generateKeyValueTestCases(new SouthboundPortOtherConfigsBuilder(), "PortOtherConfigsKey",
+ "PortOtherConfigsValue");
}
/*
// updateFromTestCases represent the original test case value. updateToTestCases represent the new value after
// the update has been performed.
- Map<String, Map<String, List<PortOtherConfigs>>> updateFromTestCases =
- generatePortOtherConfigsTestCases();
- Map<String, Map<String, List<PortOtherConfigs>>> updateToTestCases =
- generatePortOtherConfigsTestCases();
- Map<String, List<PortOtherConfigs>> updateFromTestCase;
- List<PortOtherConfigs> updateFromInputOtherConfigs;
- List<PortOtherConfigs> updateFromExpectedOtherConfigs;
- Map<String, List<PortOtherConfigs>> updateToTestCase;
- List<PortOtherConfigs> updateToInputOtherConfigs;
- List<PortOtherConfigs> updateToExpectedOtherConfigs;
+ List<SouthboundTestCase<PortOtherConfigs>> updateFromTestCases = generatePortOtherConfigsTestCases();
+ List<SouthboundTestCase<PortOtherConfigs>> updateToTestCases = generatePortOtherConfigsTestCases();
String testBridgeName;
String testPortName;
int counter = 1;
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
- for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
- updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
- updateFromInputOtherConfigs = updateFromTestCase.get(INPUT_VALUES_KEY);
- updateFromExpectedOtherConfigs = updateFromTestCase.get(EXPECTED_VALUES_KEY);
- for (String testCaseKey : updateToTestCases.keySet()) {
- testPortName = testBridgeName = String.format("%s_%s_%d", TEST_PREFIX, testCaseKey, counter);
+ for (SouthboundTestCase<PortOtherConfigs> fromTestCase : updateFromTestCases) {
+ for (SouthboundTestCase<PortOtherConfigs> toTestCase : updateToTestCases) {
+ testPortName = testBridgeName = String.format(FORMAT_STR,
+ TEST_PREFIX, toTestCase.name, counter);
counter += 1;
- updateToTestCase = updateToTestCases.get(testCaseKey);
- updateToInputOtherConfigs = updateToTestCase.get(INPUT_VALUES_KEY);
- updateToExpectedOtherConfigs = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
- TestCRUDTerminationPointPortOtherConfigsRunnable testRunnable =
- new TestCRUDTerminationPointPortOtherConfigsRunnable(
- connectionInfo, testBridgeName, testPortName,
- updateFromInputOtherConfigs,
- updateFromExpectedOtherConfigs,
- updateToInputOtherConfigs,
- updateToExpectedOtherConfigs);
- executor.submit(testRunnable);
+ executor.submit(new TestCRUDTerminationPointRunnable<>(
+ new SouthboundTestHelper<PortOtherConfigs>() {
+ @Override
+ public List<PortOtherConfigs> readValues(
+ OvsdbTerminationPointAugmentation augmentation) {
+ return augmentation.getPortOtherConfigs();
+ }
+
+ @Override
+ public void writeValues(
+ OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+ List<PortOtherConfigs> values) {
+ augmentationBuilder.setPortOtherConfigs(values);
+ }
+ },
+ connectionInfo, testBridgeName, testPortName,
+ fromTestCase.inputValues,
+ fromTestCase.expectedValues,
+ toTestCase.inputValues,
+ toTestCase.expectedValues));
}
}
executor.shutdown();
Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
}
- class TestCRUDTerminationPointPortOtherConfigsRunnable implements Runnable {
- ConnectionInfo connectionInfo;
- String testBridgeName;
- String testPortName;
- List<PortOtherConfigs> updateFromInputOtherConfigs;
- List<PortOtherConfigs> updateFromExpectedOtherConfigs;
- List<PortOtherConfigs> updateToInputOtherConfigs;
- List<PortOtherConfigs> updateToExpectedOtherConfigs;
-
- TestCRUDTerminationPointPortOtherConfigsRunnable(
- ConnectionInfo connectionInfo, String testBridgeName,
- String testPortName,
- List<PortOtherConfigs> updateFromInputOtherConfigs,
- List<PortOtherConfigs> updateFromExpectedOtherConfigs,
- List<PortOtherConfigs> updateToInputOtherConfigs,
- List<PortOtherConfigs> updateToExpectedOtherConfigs) {
-
- this.connectionInfo = connectionInfo;
- this.testBridgeName = testBridgeName;
- this.testPortName = testPortName;
- this.updateFromInputOtherConfigs = updateFromInputOtherConfigs;
- this.updateFromExpectedOtherConfigs = updateFromExpectedOtherConfigs;
- this.updateToInputOtherConfigs = updateToInputOtherConfigs;
- this.updateToExpectedOtherConfigs = updateToExpectedOtherConfigs;
- }
-
- @Override
- public void run() {
- try {
- test();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- public void test() throws InterruptedException {
- final int TERMINATION_POINT_TEST_INDEX = 0;
- // CREATE: Create the test port
- Assert.assertTrue(addBridge(connectionInfo, null,
- testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
- true, null, null, null, null));
- NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
- connectionInfo, new OvsdbBridgeName(testBridgeName)));
- OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
- createGenericOvsdbTerminationPointAugmentationBuilder();
- tpCreateAugmentationBuilder.setName(testPortName);
- tpCreateAugmentationBuilder.setPortOtherConfigs(updateFromInputOtherConfigs);
- Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
-
- // READ: Read the test port and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<PortOtherConfigs> updateFromConfigurationOtherConfigs;
- if (updateFromConfigurationTerminationPointAugmentation != null) {
- updateFromConfigurationOtherConfigs = updateFromConfigurationTerminationPointAugmentation
- .getPortOtherConfigs();
- } else {
- updateFromConfigurationOtherConfigs = null;
- }
- assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
- updateFromConfigurationOtherConfigs);
- OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmenation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<PortOtherConfigs> updateFromOperationalOtherConfigs =
- updateFromOperationalTerminationPointAugmenation.getPortOtherConfigs();
- if (updateFromOperationalOtherConfigs != null) {
- updateFromOperationalOtherConfigs = updateFromOperationalTerminationPointAugmenation
- .getPortOtherConfigs();
- } else {
- updateFromOperationalOtherConfigs = null;
- }
- assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
- updateFromOperationalOtherConfigs);
-
- // UPDATE: update the other_configs
- testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
- OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
- new OvsdbTerminationPointAugmentationBuilder();
- tpUpdateAugmentationBuilder.setPortOtherConfigs(updateToInputOtherConfigs);
- InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
- NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
- NodeId portUpdateNodeId = createManagedNodeId(portIid);
- portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
- TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
- tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
- tpUpdateBuilder.addAugmentation(
- OvsdbTerminationPointAugmentation.class,
- tpUpdateAugmentationBuilder.build());
- portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
- boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
- portIid, portUpdateNodeBuilder.build());
- Thread.sleep(OVSDB_UPDATE_TIMEOUT);
- Assert.assertTrue(result);
-
- // READ: the test port and ensure changes are propagated to the CONFIGURATION data store,
- // then repeat for OPERATIONAL data store
- OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
- List<PortOtherConfigs> updateToConfigurationOtherConfigs = updateToConfigurationTerminationPointAugmentation
- .getPortOtherConfigs();
- assertExpectedPortOtherConfigsExist(updateToExpectedOtherConfigs,
- updateToConfigurationOtherConfigs);
- assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
- updateToConfigurationOtherConfigs);
- OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
- getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
- LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
- List<PortOtherConfigs> updateToOperationalOtherConfigs = updateToOperationalTerminationPointAugmentation
- .getPortOtherConfigs();
- if (updateFromExpectedOtherConfigs != null) {
- assertExpectedPortOtherConfigsExist(updateToExpectedOtherConfigs,
- updateToOperationalOtherConfigs);
- assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
- updateToOperationalOtherConfigs);
- }
-
- // DELETE
- Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
- }
- }
-
@Test
public void testCRUDTerminationPointVlan() throws InterruptedException {
final Integer CREATED_VLAN_ID = 4000;
/*
* Generates the test cases involved in testing BridgeOtherConfigs. See inline comments for descriptions of
* the particular cases considered.
- *
- * The return value is a Map in the form (K,V)=(testCaseName,testCase).
- * - testCaseName is a String
- * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
- * either corresponding INPUT bridge other_configs, or EXPECTED bridge other_configs
- * INPUT is the List we use when calling BridgeAugmentationBuilder.setBridgeOtherConfigs()
- * EXPECTED is the List we expect to receive after calling BridgeAugmentationBuilder.getBridgeOtherConfigs()
*/
- private Map<String, Map<String, List<BridgeOtherConfigs>>> generateBridgeOtherConfigsTestCases() {
- Map<String, Map<String, List<BridgeOtherConfigs>>> testMap = new HashMap<>();
-
- final String BRIDGE_OTHER_CONFIGS_KEY = "BridgeOtherConfigKey";
- final String BRIDGE_OTHER_CONFIGS_VALUE = "BridgeOtherConfigValue";
- final String FORMAT_STR = "%s_%s_%d";
- final String GOOD_KEY = "GoodKey";
- final String GOOD_VALUE = "GoodValue";
- final String NO_VALUE_FOR_KEY = "NoValueForKey";
- final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
- // Test Case 1: TestOneOtherConfig
- // Test Type: Positive
- // Description: Create a bridge with one other_config
- // Expected: A bridge is created with the single other_config specified below
- final String testOneOtherConfigName = "TestOneOtherConfig";
- int otherConfigCounter = 0;
- List<BridgeOtherConfigs> oneOtherConfig = Lists.newArrayList(
- (new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR, testOneOtherConfigName,
- BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
- .setBridgeOtherConfigValue(String.format(FORMAT_STR, testOneOtherConfigName,
- BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
- .build()));
- Map<String,List<BridgeOtherConfigs>> testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, oneOtherConfig);
- testCase.put(INPUT_VALUES_KEY, oneOtherConfig);
- testMap.put(testOneOtherConfigName, testCase);
-
- // Test Case 2: TestFiveOtherConfig
- // Test Type: Positive
- // Description: Create a bridge with multiple (five) other_configs
- // Expected: A bridge is created with the five other_configs specified below
- final String testFiveOtherConfigName = "TestFiveOtherConfig";
- otherConfigCounter = 0;
- List<BridgeOtherConfigs> fiveOtherConfig = Lists.newArrayList(
- (new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
- .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
- .build()),
- (new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
- .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
- .build()),
- (new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
- .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
- .build()),
- (new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
- .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
- .build()),
- (new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
- .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
- BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
- .build()));
- testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, fiveOtherConfig);
- testCase.put(INPUT_VALUES_KEY, fiveOtherConfig);
- testMap.put(testFiveOtherConfigName, testCase);
-
- // Test Case 3: TestOneGoodOtherConfigOneMalformedOtherConfigValue
- // Test Type: Negative
- // Description:
- // One perfectly fine BridgeOtherConfig
- // (TestOneGoodOtherConfigOneMalformedOtherConfigValue_BridgeOtherConfigKey_1,
- // TestOneGoodOtherConfigOneMalformedOtherConfig_BridgeOtherConfigValue_1)
- // and one malformed BridgeOtherConfig which only has key specified
- // (TestOneGoodOtherConfigOneMalformedOtherConfigValue_NoValueForKey_2,
- // UNSPECIFIED)
- // Expected: A bridge is created without any other_config
- final String testOneGoodOtherConfigOneMalformedOtherConfigValueName =
- "TestOneGoodOtherConfigOneMalformedOtherConfigValue";
- otherConfigCounter = 0;
- BridgeOtherConfigs oneGood = new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodOtherConfigOneMalformedOtherConfigValueName, GOOD_KEY, ++otherConfigCounter))
- .setBridgeOtherConfigValue(String.format(FORMAT_STR,
- testOneGoodOtherConfigOneMalformedOtherConfigValueName,
- GOOD_VALUE, otherConfigCounter))
- .build();
- BridgeOtherConfigs oneBad = new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodOtherConfigOneMalformedOtherConfigValueName, NO_VALUE_FOR_KEY, ++otherConfigCounter))
- .build();
- List<BridgeOtherConfigs> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- List<BridgeOtherConfigs> oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodOtherConfigOneMalformedOtherConfigValueName, testCase);
-
- // Test Case 4: TestOneGoodOtherConfigOneMalformedOtherConfigKey
- // Test Type: Negative
- // Description:
- // One perfectly fine BridgeOtherConfig
- // (TestOneGoodOtherConfigOneMalformedOtherConfigValue_BridgeOtherConfigKey_1,
- // TestOneGoodOtherConfigOneMalformedOtherConfig_BridgeOtherConfigValue_1)
- // and one malformed BridgeOtherConfig which only has key specified
- // (UNSPECIFIED,
- // TestOneGoodOtherConfigOneMalformedOtherConfigKey_NoKeyForValue_2)
- // Expected: A bridge is created without any other_config
- final String testOneGoodOtherConfigOneMalformedOtherConfigKeyName =
- "TestOneGoodOtherConfigOneMalformedOtherConfigIdKey";
- otherConfigCounter = 0;
- oneGood = new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR, testOneGoodOtherConfigOneMalformedOtherConfigKeyName,
- GOOD_KEY, ++otherConfigCounter))
- .setBridgeOtherConfigValue(String.format(FORMAT_STR,
- testOneGoodOtherConfigOneMalformedOtherConfigKeyName,
- GOOD_VALUE, otherConfigCounter))
- .build();
- oneBad = new BridgeOtherConfigsBuilder()
- .setBridgeOtherConfigKey(String.format(FORMAT_STR,
- testOneGoodOtherConfigOneMalformedOtherConfigKeyName, NO_KEY_FOR_VALUE, ++otherConfigCounter))
- .build();
- oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodOtherConfigOneMalformedOtherConfigKeyName, testCase);
-
- return testMap;
+ private List<SouthboundTestCase<BridgeOtherConfigs>> generateBridgeOtherConfigsTestCases() {
+ return generateKeyValueTestCases(new SouthboundBridgeOtherConfigsBuilder(), "BridgeOtherConfigsKey",
+ "BridgeOtherConfigsValue");
}
/*
connectOvsdbNode(connectionInfo);
// updateFromTestCases represent the original test case value. updateToTestCases represent the new value after
// the update has been performed.
- Map<String, Map<String, List<BridgeOtherConfigs>>> updateFromTestCases = generateBridgeOtherConfigsTestCases();
- Map<String, Map<String, List<BridgeOtherConfigs>>> updateToTestCases = generateBridgeOtherConfigsTestCases();
- Map<String, List<BridgeOtherConfigs>> updateFromTestCase;
- Map<String, List<BridgeOtherConfigs>> updateToTestCase;
- List<BridgeOtherConfigs> updateFromInputOtherConfigs;
- List<BridgeOtherConfigs> updateFromExpectedOtherConfigs;
- List<BridgeOtherConfigs> updateToInputOtherConfigs;
- List<BridgeOtherConfigs> updateToExpectedOtherConfigs;
+ List<SouthboundTestCase<BridgeOtherConfigs>> updateFromTestCases = generateBridgeOtherConfigsTestCases();
+ List<SouthboundTestCase<BridgeOtherConfigs>> updateToTestCases = generateBridgeOtherConfigsTestCases();
String testBridgeName;
int counter = 1;
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
- for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
- updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
- updateFromInputOtherConfigs = updateFromTestCase.get(INPUT_VALUES_KEY);
- updateFromExpectedOtherConfigs = updateFromTestCase.get(EXPECTED_VALUES_KEY);
- for (String testCaseKey : updateToTestCases.keySet()) {
- testBridgeName = String.format("%s_%s_%d", TEST_BRIDGE_PREFIX, testCaseKey, counter);
+ for (SouthboundTestCase<BridgeOtherConfigs> fromTestCase : updateFromTestCases) {
+ for (SouthboundTestCase<BridgeOtherConfigs> toTestCase : updateToTestCases) {
+ testBridgeName = String.format(FORMAT_STR, TEST_BRIDGE_PREFIX, toTestCase.name, counter);
counter += 1;
- updateToTestCase = updateToTestCases.get(testCaseKey);
- updateToInputOtherConfigs = updateToTestCase.get(INPUT_VALUES_KEY);
- updateToExpectedOtherConfigs = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
TestCRUDBridgeOtherConfigsRunnable testRunnable =
new TestCRUDBridgeOtherConfigsRunnable(
connectionInfo, testBridgeName,
- updateFromInputOtherConfigs,
- updateFromExpectedOtherConfigs,
- updateToInputOtherConfigs,
- updateToExpectedOtherConfigs);
+ fromTestCase.inputValues,
+ fromTestCase.expectedValues,
+ toTestCase.inputValues,
+ toTestCase.expectedValues);
executor.submit(testRunnable);
}
}
/*
* Generates the test cases involved in testing BridgeExternalIds. See inline comments for descriptions of
* the particular cases considered.
- *
- * The return value is a Map in the form (K,V)=(testCaseName,testCase).
- * - testCaseName is a String
- * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
- * either corresponding INPUT bridge external ids, or EXPECTED bridge external ids
- * INPUT is the List we use when calling BridgeAugmentationBuilder.setBridgeExternalIds()
- * EXPECTED is the List we expect to receive after calling BridgeAugmentationBuilder.getBridgeExternalIds()
*/
- private Map<String, Map<String, List<BridgeExternalIds>>> generateBridgeExternalIdsTestCases() {
- Map<String, Map<String, List<BridgeExternalIds>>> testMap = new HashMap<>();
-
- final String BRIDGE_EXTERNAL_ID_KEY = "BridgeExternalIdKey";
- final String BRIDGE_EXTERNAL_ID_VALUE = "BridgeExternalIdValue";
- final String FORMAT_STR = "%s_%s_%d";
- final String GOOD_KEY = "GoodKey";
- final String GOOD_VALUE = "GoodValue";
- final String NO_VALUE_FOR_KEY = "NoValueForKey";
- final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
- // Test Case 1: TestOneExternalId
- // Test Type: Positive
- // Description: Create a bridge with one BridgeExternalIds
- // Expected: A bridge is created with the single external_ids specified below
- final String testOneExternalIdName = "TestOneExternalId";
- int externalIdCounter = 0;
- List<BridgeExternalIds> oneExternalId = Lists.newArrayList(
- (new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR, testOneExternalIdName,
- BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setBridgeExternalIdValue(String.format(FORMAT_STR, testOneExternalIdName,
- BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()));
- Map<String,List<BridgeExternalIds>> testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, oneExternalId);
- testCase.put(INPUT_VALUES_KEY, oneExternalId);
- testMap.put(testOneExternalIdName, testCase);
-
- // Test Case 2: TestFiveExternalId
- // Test Type: Positive
- // Description: Create a bridge with multiple (five) BridgeExternalIds
- // Expected: A bridge is created with the five external_ids specified below
- final String testFiveExternalIdName = "TestFiveExternalId";
- externalIdCounter = 0;
- List<BridgeExternalIds> fiveExternalId = Lists.newArrayList(
- (new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()),
- (new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
- .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
- BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
- .build()));
- testCase = Maps.newHashMap();
- testCase.put(EXPECTED_VALUES_KEY, fiveExternalId);
- testCase.put(INPUT_VALUES_KEY, fiveExternalId);
- testMap.put(testFiveExternalIdName, testCase);
-
- // Test Case 3: TestOneGoodExternalIdOneMalformedExternalIdValue
- // Test Type: Negative
- // Description:
- // One perfectly fine BridgeExternalId
- // (TestOneGoodExternalIdOneMalformedExternalIdValue_BridgeExternalIdKey_1,
- // TestOneGoodExternalIdOneMalformedExternalId_BridgeExternalIdValue_1)
- // and one malformed BridgeExternalId which only has key specified
- // (TestOneGoodExternalIdOneMalformedExternalIdValue_NoValueForKey_2,
- // UNSPECIFIED)
- // Expected: A bridge is created without any external_ids
- final String testOneGoodExternalIdOneMalformedExternalIdValueName =
- "TestOneGoodExternalIdOneMalformedExternalIdValue";
- externalIdCounter = 0;
- BridgeExternalIds oneGood = new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdValueName,
- GOOD_KEY, ++externalIdCounter))
- .setBridgeExternalIdValue(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdValueName,
- GOOD_VALUE, externalIdCounter))
- .build();
- BridgeExternalIds oneBad = new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdValueName, NO_VALUE_FOR_KEY, ++externalIdCounter))
- .build();
- List<BridgeExternalIds> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- List<BridgeExternalIds> oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodExternalIdOneMalformedExternalIdValueName, testCase);
-
- // Test Case 4: TestOneGoodExternalIdOneMalformedExternalIdKey
- // Test Type: Negative
- // Description:
- // One perfectly fine BridgeExternalId
- // (TestOneGoodExternalIdOneMalformedExternalIdValue_BridgeExternalIdKey_1,
- // TestOneGoodExternalIdOneMalformedExternalId_BridgeExternalIdValue_1)
- // and one malformed BridgeExternalId which only has key specified
- // (UNSPECIFIED,
- // TestOneGoodExternalIdOneMalformedExternalIdKey_NoKeyForValue_2)
- // Expected: A bridge is created without any external_ids
- final String testOneGoodExternalIdOneMalformedExternalIdKeyName =
- "TestOneGoodExternalIdOneMalformedExternalIdKey";
- externalIdCounter = 0;
- oneGood = new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdKeyName,
- GOOD_KEY, ++externalIdCounter))
- .setBridgeExternalIdValue(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdKeyName,
- GOOD_VALUE, externalIdCounter))
- .build();
- oneBad = new BridgeExternalIdsBuilder()
- .setBridgeExternalIdKey(String.format(FORMAT_STR,
- testOneGoodExternalIdOneMalformedExternalIdKeyName, NO_KEY_FOR_VALUE, ++externalIdCounter))
- .build();
- oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
- oneGoodOneBadExpected = null;
- testCase = Maps.newHashMap();
- testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
- testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
- testMap.put(testOneGoodExternalIdOneMalformedExternalIdKeyName, testCase);
- return testMap;
+ private List<SouthboundTestCase<BridgeExternalIds>> generateBridgeExternalIdsTestCases() {
+ return generateKeyValueTestCases(new SouthboundBridgeExternalIdsBuilder(), "BridgeExternalIdsKey",
+ "BridgeExternalIdsValue");
}
/*
connectOvsdbNode(connectionInfo);
// updateFromTestCases represent the original test case value. updateToTestCases represent the new value after
// the update has been performed.
- Map<String, Map<String, List<BridgeExternalIds>>> updateFromTestCases = generateBridgeExternalIdsTestCases();
- Map<String, Map<String, List<BridgeExternalIds>>> updateToTestCases = generateBridgeExternalIdsTestCases();
- Map<String, List<BridgeExternalIds>> updateFromTestCase;
- List<BridgeExternalIds> updateFromInputExternalIds;
- List<BridgeExternalIds> updateFromExpectedExternalIds;
- Map<String, List<BridgeExternalIds>> updateToTestCase;
- List<BridgeExternalIds> updateToInputExternalIds;
- List<BridgeExternalIds> updateToExpectedExternalIds;
+ List<SouthboundTestCase<BridgeExternalIds>> updateFromTestCases = generateBridgeExternalIdsTestCases();
+ List<SouthboundTestCase<BridgeExternalIds>> updateToTestCases = generateBridgeExternalIdsTestCases();
String testBridgeName;
int counter = 1;
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
- for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
- updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
- updateFromInputExternalIds = updateFromTestCase.get(INPUT_VALUES_KEY);
- updateFromExpectedExternalIds = updateFromTestCase.get(EXPECTED_VALUES_KEY);
- for (String testCaseKey : updateToTestCases.keySet()) {
- testBridgeName = String.format("%s_%s_%d", TEST_BRIDGE_PREFIX, testCaseKey, counter);
+ for (SouthboundTestCase<BridgeExternalIds> fromTestCase : updateFromTestCases) {
+ for (SouthboundTestCase<BridgeExternalIds> toTestCase : updateToTestCases) {
+ testBridgeName = String.format(FORMAT_STR, TEST_BRIDGE_PREFIX, toTestCase.name, counter);
counter += 1;
- updateToTestCase = updateToTestCases.get(testCaseKey);
- updateToInputExternalIds = updateToTestCase.get(INPUT_VALUES_KEY);
- updateToExpectedExternalIds = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
TestCRUDBridgeExternalIdsRunnable testRunnable =
new TestCRUDBridgeExternalIdsRunnable(
connectionInfo, testBridgeName,
- updateFromInputExternalIds,
- updateFromExpectedExternalIds,
- updateToInputExternalIds,
- updateToExpectedExternalIds);
+ fromTestCase.inputValues,
+ fromTestCase.expectedValues,
+ toTestCase.inputValues,
+ toTestCase.expectedValues);
executor.submit(testRunnable);
}
}
}
public static NodeId createManagedNodeId(ConnectionInfo key, OvsdbBridgeName bridgeName) {
- return createManagedNodeId(key.getRemoteIp(),key.getRemotePort(),bridgeName);
+ return createManagedNodeId(key.getRemoteIp(), key.getRemotePort(), bridgeName);
}
public static NodeId createManagedNodeId(IpAddress ip, PortNumber port, OvsdbBridgeName bridgeName) {
NodeKey nodeKey = iid.firstKeyOf(Node.class, NodeKey.class);
return nodeKey.getNodeId();
}
+
+ /**
+ * <p>
+ * Representation of a southbound test case. Each test case has a name, a list of input values and a list of
+ * expected values. The input values are provided to the augmentation builder, and the expected values are checked
+ * against the output of the resulting augmentation.
+ * </p>
+ * <p>
+ * Instances of this class are immutable.
+ * </p>
+ *
+ * @param <T> The type of data used for the test case.
+ */
+ private static final class SouthboundTestCase<T> {
+ private final String name;
+ private final List<T> inputValues;
+ private final List<T> expectedValues;
+
+ /**
+ * Creates an instance of a southbound test case.
+ *
+ * @param name The test case's name.
+ * @param inputValues The input values (provided as input to the underlying augmentation builder).
+ * @param expectedValues The expected values (checked against the output of the underlying augmentation).
+ */
+ public SouthboundTestCase(
+ final String name, final List<T> inputValues, final List<T> expectedValues) {
+ this.name = name;
+ this.inputValues = inputValues;
+ this.expectedValues = expectedValues;
+ }
+ }
+
+ /**
+ * Southbound test case builder.
+ *
+ * @param <T> The type of data used for the test case.
+ */
+ private static final class SouthboundTestCaseBuilder<T> {
+ private String name;
+ private List<T> inputValues;
+ private List<T> expectedValues;
+
+ /**
+ * Creates a builder. Builders may be reused, the generated immutable instances are independent of the
+ * builders. There are no default values.
+ */
+ public SouthboundTestCaseBuilder() {
+ // Nothing to do
+ }
+
+ /**
+ * Sets the test case's name.
+ *
+ * @param name The test case's name.
+ * @return The builder.
+ */
+ public SouthboundTestCaseBuilder<T> name(final String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Sets the input values.
+ *
+ * @param inputValues The input values.
+ * @return The builder.
+ */
+ @SafeVarargs
+ public final SouthboundTestCaseBuilder<T> input(final T... inputValues) {
+ this.inputValues = Lists.newArrayList(inputValues);
+ return this;
+ }
+
+ /**
+ * Sets the expected output values.
+ *
+ * @param expectedValues The expected output values.
+ * @return The builder.
+ */
+ @SafeVarargs
+ public final SouthboundTestCaseBuilder<T> expect(final T... expectedValues) {
+ this.expectedValues = Lists.newArrayList(expectedValues);
+ return this;
+ }
+
+ /**
+ * Indicates that the provided input values should be expected as output values.
+ *
+ * @return The builder.
+ */
+ public SouthboundTestCaseBuilder<T> expectInputAsOutput() {
+ this.expectedValues = this.inputValues;
+ return this;
+ }
+
+ /**
+ * Builds an immutable instance representing the test case.
+ *
+ * @return The test case.
+ */
+ @SuppressWarnings("unchecked")
+ public SouthboundTestCase<T> build() {
+ return new SouthboundTestCase<>(name, inputValues, expectedValues);
+ }
+ }
}
/*
-* Copyright (C) 2014 Red Hat, Inc.
+* Copyright (C) 2014 Red Hat, 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,
/*
- * Copyright (C) 2015 Red Hat, Inc.
+ * Copyright (C) 2015 Red Hat, 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,
/*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
/*
- * Copyright (C) 2015 Red Hat, Inc.
+ * Copyright (C) 2015 Red Hat, 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,