Add AffinityConfig and AffinityLink objects, integrate into AffinityManager. 38/1038/1
authorSuchi Raman <suchi.raman@plexxi.com>
Wed, 28 Aug 2013 19:47:54 +0000 (15:47 -0400)
committerSuchi Raman <suchi.raman@plexxi.com>
Wed, 28 Aug 2013 19:47:54 +0000 (15:47 -0400)
Signed-off-by: Suchi Raman <suchi.raman@plexxi.com>
14 files changed:
affinity/affinity-api.txt [new file with mode: 0644]
affinity/api/META-INF/MANIFEST.MF
affinity/api/pom.xml
affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityConfig.java [deleted file]
affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityGroup.java [new file with mode: 0644]
affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityIdentifier.java [new file with mode: 0644]
affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityLink.java [new file with mode: 0644]
affinity/api/src/main/java/org/opendaylight/controller/affinity/IAffinityManager.java
affinity/api/src/main/java/org/opendaylight/controller/affinity/IAffinityManagerAware.java
affinity/implementation/META-INF/MANIFEST.MF
affinity/implementation/src/main/java/org/opendaylight/controller/affinity/internal/AffinityManagerImpl.java
affinity/implementation/src/test/java/org/opendaylight/controller/affinity/internal/AffinityManagerImplTest.java
affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/AffinityNorthbound.java
affinity/northbound/src/main/resources/META-INF/MANIFEST.MF

diff --git a/affinity/affinity-api.txt b/affinity/affinity-api.txt
new file mode 100644 (file)
index 0000000..b13ab0c
--- /dev/null
@@ -0,0 +1,32 @@
+Create an affinity group: 
+ /affinity/nb/v2/{container}/create/group/{name}
+
+Fetch an affinity group given its name: 
+/affinity/nb/v2/{container}/group/{name}
+
+Add affinity element to affinity group: 
+/affinity/nb/v2/{container}/add/{groupname}/mac/{address}
+ /affinity/nb/v2/{container}/add/{groupname}/ip/{address}
+/affinity/nb/v2/{container}/add/{groupname}/host/{address}
+
+Delete element from an affinity group.
+/affinity/nb/v2/{container}/delete/{groupname}/mac/{address}
+ /affinity/nb/v2/{container}/delete/{groupname}/ip/{address}
+/affinity/nb/v2/{container}/delete/{groupname}/host/{address}
+
+Add affinity link from one group to another: 
+/affinity/nb/v2/{container}/create/link/{name}
+/affinity/nb/v2/{container}/from/{linkname}/{affinitygroup}
+/affinity/nb/v2/{container}/to/{linkname}/{affinitygroup}
+
+Create an affinity element: 
+# For now, these are simple unary objects. Future implementations to include multiple attributes. 
+/affinity/nb/v2/{container}/create/identifier/{name}/mac/{address}
+/affinity/nb/v2/{container}/create/identifier/{name}/ip/{address}
+/affinity/nb/v2/{container}/create/identifier/{hostname}/host/{address} 
+
+List all affinities: 
+/affinity/nb/v2/{container}/affinities
+
+List stats for affinities: 
+...
index 668433e382fac7e0dc4df1d4d71a0cc2e0773a70..1caed0717d2e79bc0ff0211175bb28bb46378596 100644 (file)
@@ -1,5 +1,5 @@
 Manifest-Version: 1.0\r
-Bnd-LastModified: 1376940266146\r
+Bnd-LastModified: 1377719211376\r
 Build-Jdk: 1.6.0_37\r
 Built-By: sraman\r
 Bundle-ManifestVersion: 2\r
@@ -10,13 +10,15 @@ Created-By: Apache Maven Bundle Plugin
 Export-Package: org.opendaylight.controller.affinity;uses:="javax.xml.bi\r
  nd.annotation,org.opendaylight.controller.sal.utils";version="0.4.0.SNA\r
  PSHOT"\r
-Import-Package: javax.xml.bind.annotation,org.apache.commons.lang3.build\r
- er;version="[3.1,4)",org.apache.felix.dm;version="[3.0,4)",org.eclipse.\r
- osgi.framework.console;version="[1.1,2)",org.opendaylight.controller.cl\r
- ustering.services;version="[0.4,1)",org.opendaylight.controller.configu\r
- ration;version="[0.4,1)",org.opendaylight.controller.sal.core;version="\r
- [0.5,1)",org.opendaylight.controller.sal.inventory;version="[0.5,1)",or\r
- g.opendaylight.controller.sal.packet;version="[0.5,1)",org.opendaylight\r
- .controller.sal.utils;version="[0.5,1)",org.osgi.framework;version="[1.\r
- 7,2)",org.slf4j;version="[1.7,2)"\r
+Import-Package: javax.ws.rs;version="[1.1,2)",javax.ws.rs.core;version="\r
+ [1.1,2)",javax.xml.bind,javax.xml.bind.annotation,javax.xml.bind.annota\r
+ tion,org.apache.commons.lang3.builder;version="[3.1,4)",org.apache.feli\r
+ x.dm;version="[3.0,4)",org.eclipse.osgi.framework.console;version="[1.1\r
+ ,2)",org.opendaylight.controller.clustering.services;version="[0.4,1)",\r
+ org.opendaylight.controller.configuration;version="[0.4,1)",org.openday\r
+ light.controller.sal.core;version="[0.5,1)",org.opendaylight.controller\r
+ .sal.inventory;version="[0.5,1)",org.opendaylight.controller.sal.packet\r
+ ;version="[0.5,1)",org.opendaylight.controller.sal.utils;version="[0.5,\r
+ 1)",org.osgi.framework;version="[1.7,2)",org.slf4j;version="[1.7,2)",or\r
+ g.slf4j\r
 Tool: Bnd-1.50.0\r
index c0ea7e035348e667718519e077f28668b240bd39..4c311fb3148d2e9a54a54eea0a8a2caf91fc95ac 100644 (file)
@@ -20,6 +20,8 @@
     <sonar.jacoco.Reportpath>target/jacoco.exec</sonar.jacoco.Reportpath>
     <sonar.jacoco.itReportPath>target/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sonar.language>java</sonar.language>
+    <junit.version>4.10</junit.version>
+    <enunciate.version>1.26.2</enunciate.version>
   </properties>
   <build>
     <pluginManagement>
               org.eclipse.osgi.framework.console,
               org.osgi.framework,
               javax.xml.bind.annotation,
-              org.apache.commons.lang3.builder
+              org.apache.commons.lang3.builder,
+              javax.ws.rs,
+              javax.ws.rs.core,
+              javax.xml.bind.annotation,
+              javax.xml.bind,
+              org.slf4j,
+              !org.codehaus.enunciate.jaxrs
             </Import-Package>
           </instructions>
           <manifestLocation>${project.basedir}/META-INF</manifestLocation>
     </plugins>
   </build>
   <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>${junit.version}</version>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>clustering.services</artifactId>
       <artifactId>sal</artifactId>
       <version>0.5.0-SNAPSHOT</version>
     </dependency>
+
+    <dependency>
+      <groupId>org.codehaus.enunciate</groupId>
+      <artifactId>enunciate-core-annotations</artifactId>
+      <version>${enunciate.version}</version>
+    </dependency>
+
   </dependencies>
 </project>
diff --git a/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityConfig.java b/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityConfig.java
deleted file mode 100644 (file)
index 26e1e00..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-
-/*
- * Copyright (c) 2013 Plexxi, 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.controller.affinity;
-
-import java.io.Serializable;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-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.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-
-//import org.opendaylight.controller.sal.utils;
-
-/**
- * The class represents an affinity configuration.
- */
-@XmlRootElement
-@XmlAccessorType(XmlAccessType.NONE)
-public class AffinityConfig implements Cloneable, Serializable {
-    //static fields are by default excluded by Gson parser
-    private static final long serialVersionUID = 1L;
-
-    /*    private static final String affinityFields[] = { GUIField.NAME.toString(),
-                                                    GUIField.AFFINITYFROM.toString(), 
-                                                    GUIField.AFFINITYTO.toString(), 
-                                                    GUIField.AFFINITYTYPE.toString() };
-    */
-
-    // Order matters: JSP file expects following fields in the
-    // following order
-    @XmlAttribute
-    private String name;
-    @XmlAttribute
-    private String fromIp; // A.B.C.D
-    private String toIp; // A.B.C.D
-    private String affinityType;
-
-    public AffinityConfig() {
-    }
-
-    public AffinityConfig(String desc, String from, String to, String aType) {
-        name = desc;
-        fromIp = from;
-        toIp = to;
-        affinityType = aType;
-    }
-
-    public AffinityConfig(AffinityConfig ac) {
-        name = ac.name;
-        fromIp = ac.fromIp;
-        toIp = ac.toIp;
-        affinityType = ac.affinityType;
-    }
-
-    public String getName() {
-        return name;
-    }
-    public InetAddress getFromIP() {
-        InetAddress ip = null;
-        try {
-            ip = InetAddress.getByName(fromIp);
-        } catch (UnknownHostException e1) {
-            return null;
-        }
-        return ip;
-    }
-
-    public InetAddress getToIP() {
-        InetAddress ip = null;
-        try {
-            ip = InetAddress.getByName(toIp);
-        } catch (UnknownHostException e1) {
-            return null;
-        }
-        return ip;
-    }
-
-    @Override
-    public int hashCode() {
-        return name.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        /*
-         * Configuration will be stored in collection only if it is valid
-         * Hence we don't check here for uninitialized fields
-         */
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        AffinityConfig that = (AffinityConfig) obj;
-        if (this.fromIp.equals(that.fromIp) && this.toIp.equals(that.toIp) && (this.affinityType.equals(that.affinityType))) {
-            return true;
-        }
-        return false;
-    }
-    /*
-    public static List<String> getGuiFieldsNames() {
-        List<String> fieldList = new ArrayList<String>();
-        for (String str : affinityFields) {
-            fieldList.add(str);
-        }
-        return fieldList;
-    }
-    */
-    @Override
-    public String toString() {
-        return ("AffinityConfig [Description=" + name + ", From=" + fromIp
-                + ", To=" + toIp + ", Type=" + affinityType + "]");
-    }
-
-    /**
-     * Implement clonable interface
-     */
-    @Override
-    public AffinityConfig clone() {
-        return new AffinityConfig(this);
-    }
-
-}
diff --git a/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityGroup.java b/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityGroup.java
new file mode 100644 (file)
index 0000000..ffbdbbf
--- /dev/null
@@ -0,0 +1,89 @@
+package org.opendaylight.controller.affinity;
+
+import org.opendaylight.controller.sal.utils.NetUtils;
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Map;
+import java.util.HashMap;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class AffinityGroup implements Cloneable, Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlAttribute
+    private String name;
+    @XmlElement
+    private final Map<String, AffinityIdentifier> elements;
+
+    public AffinityGroup(String name) {
+       this.name = name;
+       elements = new HashMap<String, AffinityIdentifier>();
+    }
+    public AffinityGroup(String name, HashMap<String, AffinityIdentifier> elements) {
+       this.name = name;
+       this.elements = elements;
+    }
+
+    // Basic affinity element, IP address
+    public Status add(String ipaddress) {
+       AffinityIdentifier<InetAddress> elem = new AffinityIdentifier();
+
+       elem.setName(ipaddress);
+       if (NetUtils.isIPAddressValid(ipaddress)) {
+           elem.set(NetUtils.parseInetAddress(ipaddress));
+           elements.put(ipaddress, elem);
+           return new Status(StatusCode.SUCCESS);
+       } else {
+           return new Status(StatusCode.BADREQUEST);
+       }
+    }
+
+    // Remove an affinity element given its IP address.
+    public void remove(String ipaddress) {
+       if (elements != null) {
+           elements.remove(ipaddress);
+       }
+    }
+    public Integer size() {
+       return (elements.size());
+    }
+    public void print() {
+       for (AffinityIdentifier value : elements.values()) {
+           value.print();
+       }
+    }
+    public String getName() {
+       return name;
+    }
+}
+
diff --git a/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityIdentifier.java b/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityIdentifier.java
new file mode 100644 (file)
index 0000000..97ef931
--- /dev/null
@@ -0,0 +1,24 @@
+package org.opendaylight.controller.affinity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/* Affinity identifier */
+public class AffinityIdentifier<T> {
+    private T value;
+    private String name;
+
+    public T get() {
+        return value;
+    }
+    public void set(T t) {
+       value = t;
+    }
+    public void setName(String name) {
+       this.name = name;
+    }
+    public void print() {
+       System.out.println(value);
+    }
+}
+
diff --git a/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityLink.java b/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityLink.java
new file mode 100644 (file)
index 0000000..9eb58ca
--- /dev/null
@@ -0,0 +1,85 @@
+package org.opendaylight.controller.affinity;
+
+import org.opendaylight.controller.sal.utils.NetUtils;
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Map;
+import java.util.HashMap;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class AffinityLink implements Cloneable, Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlAttribute
+    private String name;
+    @XmlElement
+    AffinityGroup fromGroup;
+    @XmlElement
+    AffinityGroup toGroup;
+    @XmlElement 
+    String affinityAttribute;
+
+    public AffinityLink() {
+    }
+    public AffinityLink(String name, AffinityGroup fromGroup, AffinityGroup toGroup) {
+       this.name = name;
+       this.fromGroup = fromGroup;
+       this.toGroup = toGroup;
+    }
+    public String getName() {
+       return this.name;
+    }
+    public void setName(String name) {
+       this.name = name;
+    }
+    public void setFromGroup(AffinityGroup fromGroup) {
+       this.fromGroup = fromGroup;
+    }
+    public void setToGroup(AffinityGroup toGroup) {
+       this.toGroup = toGroup;
+    }
+    public void setAttribute(String attribute) {
+       this.affinityAttribute = attribute;
+    }
+
+    public String getAttribute() {
+       return this.affinityAttribute;
+    }
+    public AffinityGroup getFromGroup() {
+       return this.fromGroup;
+    }
+    public AffinityGroup getToGroup() {
+       return this.toGroup;
+    }
+}
+
index 15fc195a927c472343d693822b31422758e6a1b8..bf5228b0a76e7a5ac29a46698c61a406e01d28dd 100644 (file)
@@ -12,6 +12,7 @@ package org.opendaylight.controller.affinity;
 import java.net.InetAddress;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
 import java.util.Set;
 
 import org.opendaylight.controller.sal.core.Node;
@@ -19,7 +20,7 @@ import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.utils.Status;
 
-import org.opendaylight.controller.affinity.AffinityConfig;
+import org.opendaylight.controller.affinity.AffinityLink;
 
 /**
  * Primary purpose of this interface is to provide methods for
@@ -27,36 +28,19 @@ import org.opendaylight.controller.affinity.AffinityConfig;
  */
 public interface IAffinityManager {
 
-    /**
-     * Remove an affinity configuration
-     *
-     * @param  configObject refer to {@link Open Declaration org.opendaylight.controller.affinitymanager.AffinityConfig}
-     * @return "Success" or failure reason
-     */
-    public Status removeAffinityConfigObject(AffinityConfig configObject);
-
-    /**
-     * Remove an affinity configuration given the name
-     *
-     * @param   name      affinity name
-     * @return  "Success" or failure reason
-     */
-    public Status removeAffinityConfig(String name);
-
-    /**
-     * Save the current affinity configurations
-     *
-     * @return the status code
-     */
-    public Status saveAffinityConfig();
+    public Status addAffinityLink(AffinityLink al);
+    public Status removeAffinityLink(AffinityLink al);
+    public Status removeAffinityLink(String linkName);
+
+    public AffinityLink getAffinityLink(String name);    
+    public List<AffinityLink> getAllAffinityLinks();
 
-    /**
-     * Update Switch specific configuration such as Affinity name and type. Add if absent.
-     *
-     * @param cfgConfig refer to {@link Open Declaration org.opendaylight.controller.affinity.AffinityConfig}
-     */
-    public Status updateAffinityConfig(AffinityConfig cfgObject);
+    public Status addAffinityGroup(AffinityGroup ag);
+    public Status removeAffinityGroup(String name);
+    
+    public AffinityGroup getAffinityGroup(String name);
+    public List<AffinityGroup> getAllAffinityGroups();
 
-    public List<AffinityConfig> getAffinityConfigList();
-    public AffinityConfig getAffinityConfig(String affinity);
+    /* Save all configs to their respective files. */
+    public Status saveAffinityConfig();
 }
index 87d2b295a2513a08c7f2c19a5513508383cfece6..1dad4ffe6726d2bebe1e9b906c5362bd228ea7ae 100644 (file)
@@ -21,7 +21,8 @@ public interface IAffinityManagerAware {
      *            the affinity config that was added or removed
      * @param add true if add; false otherwise
      */
-    public void affinityNotify(AffinityConfig aff, boolean add);
+    public void affinityLinkNotify(AffinityLink aff, boolean add);
+    public void affinityGroupNotify(AffinityGroup aff, boolean add);
 
     /**
      * Inform listeners that the network node has notified us about a failure in
index 8ab6578ca8c38f0e67057fa17db0a50f511dd489..2498a063acb81f15c3c7325b0910c8914025cdab 100644 (file)
@@ -1,5 +1,5 @@
 Manifest-Version: 1.0\r
-Bnd-LastModified: 1376940268439\r
+Bnd-LastModified: 1377719213514\r
 Build-Jdk: 1.6.0_37\r
 Built-By: sraman\r
 Bundle-Activator: org.opendaylight.controller.affinity.internal.Activato\r
index 1246d3755647d94cd2a5cfdeb737c999690fb9e5..711c6190a988deacda522f6273ccfdc8534d7235 100644 (file)
@@ -56,7 +56,6 @@ import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.core.UpdateType;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
-import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.IReadService;
 import org.opendaylight.controller.sal.reader.IReadServiceListener;
@@ -65,14 +64,12 @@ import org.opendaylight.controller.sal.utils.IObjectReader;
 import org.opendaylight.controller.sal.utils.ObjectReader;
 import org.opendaylight.controller.sal.utils.ObjectWriter;
 
-import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
-import org.opendaylight.controller.sal.reader.NodeDescription;
-import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 import org.opendaylight.controller.sal.utils.ServiceHelper;
-import org.opendaylight.controller.affinity.AffinityConfig;
+import org.opendaylight.controller.affinity.AffinityGroup;
+import org.opendaylight.controller.affinity.AffinityLink;
 import org.opendaylight.controller.affinity.IAffinityManager;
 import org.opendaylight.controller.affinity.IAffinityManagerAware;
 import org.slf4j.Logger;
@@ -85,13 +82,15 @@ import org.slf4j.LoggerFactory;
 public class AffinityManagerImpl implements IAffinityManager, IConfigurationContainerAware, IObjectReader, ICacheUpdateAware<Long, String> {
     private static final Logger log = LoggerFactory.getLogger(AffinityManagerImpl.class);
 
-
     private static String ROOT = GlobalConstants.STARTUPHOME.toString();
     private static final String SAVE = "Save";
-    private String affinityConfigFileName = null;
-    private ConcurrentMap<String, AffinityConfig> affinityConfigList;
+    private String affinityLinkFileName = null;
+    private String affinityGroupFileName = null;
 
+    private ConcurrentMap<String, AffinityGroup> affinityGroupList;
+    private ConcurrentMap<String, AffinityLink> affinityLinkList;
     private ConcurrentMap<Long, String> configSaveEvent;
+
     private final Set<IAffinityManagerAware> affinityManagerAware = Collections
             .synchronizedSet(new HashSet<IAffinityManagerAware>());
 
@@ -127,7 +126,9 @@ public class AffinityManagerImpl implements IAffinityManager, IConfigurationCont
 
     public void startUp() {
         // Initialize configuration file names
-        affinityConfigFileName = ROOT + "affinityConfig_" + this.getContainerName()
+        affinityLinkFileName = ROOT + "affinityConfig_link" + this.getContainerName()
+            + ".conf";
+        affinityGroupFileName = ROOT + "affinityConfig_group" + this.getContainerName()
             + ".conf";
 
         // Instantiate cluster synced variables
@@ -138,7 +139,7 @@ public class AffinityManagerImpl implements IAffinityManager, IConfigurationCont
          * Read startup and build database if we have not already gotten the
          * configurations synced from another node
          */
-        if (affinityConfigList.isEmpty()) {
+        if (affinityGroupList.isEmpty() || affinityLinkList.isEmpty()) {
             loadAffinityConfiguration();
         }
     }
@@ -153,10 +154,12 @@ public class AffinityManagerImpl implements IAffinityManager, IConfigurationCont
             log.warn("un-initialized clusterContainerService, can't create cache");
             return;
         }
-
         try {
             clusterContainerService.createCache(
-                    "affinity.affinityConfigList",
+                    "affinity.affinityGroupList",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+            clusterContainerService.createCache(
+                    "affinity.affinityLinkList",
                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
             clusterContainerService.createCache(
                     "affinity.configSaveEvent",
@@ -171,14 +174,20 @@ public class AffinityManagerImpl implements IAffinityManager, IConfigurationCont
     @SuppressWarnings({ "unchecked", "deprecation" })
     private void retrieveCaches() {
         if (this.clusterContainerService == null) {
-            log.info("un-initialized clusterContainerService, can't create cache");
+            log.info("un-initialized clusterContainerService, can't retrieve cache");
             return;
         }
-        affinityConfigList = (ConcurrentMap<String, AffinityConfig>) clusterContainerService
-            .getCache("affinity.affinityConfigList");
-        if (affinityConfigList == null) {
-            log.error("\nFailed to get cache for affinityConfigList");
+        affinityGroupList = (ConcurrentMap<String, AffinityGroup>) clusterContainerService
+            .getCache("affinity.affinityGroupList");
+        if (affinityGroupList == null) {
+            log.error("\nFailed to get cache for affinityGroupList");
+        }
+        affinityLinkList = (ConcurrentMap<String, AffinityLink>) clusterContainerService
+            .getCache("affinity.affinityLinkList");
+        if (affinityLinkList == null) {
+            log.error("\nFailed to get cache for affinityLinkList");
         }
+
         configSaveEvent = (ConcurrentMap<Long, String>) clusterContainerService
             .getCache("affinity.configSaveEvent");
         if (configSaveEvent == null) {
@@ -187,97 +196,134 @@ public class AffinityManagerImpl implements IAffinityManager, IConfigurationCont
     }
 
     private void nonClusterObjectCreate() {
-        affinityConfigList = new ConcurrentHashMap<String, AffinityConfig>();
+        affinityLinkList = new ConcurrentHashMap<String, AffinityLink>();
+        affinityGroupList = new ConcurrentHashMap<String, AffinityGroup>();
         configSaveEvent = new ConcurrentHashMap<Long, String>();
     }
 
-    @Override
-    public List<AffinityConfig> getAffinityConfigList() {
-        return new ArrayList<AffinityConfig>(affinityConfigList.values());
-    }
 
-    @Override
-    public AffinityConfig getAffinityConfig(String affinity) {
-        return affinityConfigList.get(affinity);
+    public Status addAffinityLink(AffinityLink al) {
+       boolean putNewLink = false;
+
+       if (affinityLinkList.containsKey(al.getName())) {
+           return new Status(StatusCode.CONFLICT,
+                             "AffinityLink with the specified name already configured.");
+       }
+
+       
+       AffinityLink alCurr = affinityLinkList.get(al.getName());
+       if (alCurr == null) {
+           if (affinityLinkList.putIfAbsent(al.getName(), al) == null) {
+               putNewLink = true;
+           } 
+       } else {
+           putNewLink = affinityLinkList.replace(al.getName(), alCurr, al);
+       }
+
+       if (!putNewLink) {
+           String msg = "Cluster conflict: Conflict while adding the subnet " + al.getName();
+           return new Status(StatusCode.CONFLICT, msg);
+       }
+       
+        return new Status(StatusCode.SUCCESS);
     }
 
+    public Status removeAffinityLink(String name) {
+       affinityLinkList.remove(name);
+       return new Status(StatusCode.SUCCESS);
+    }
 
+    public Status removeAffinityLink(AffinityLink al) {
+       AffinityLink alCurr = affinityLinkList.get(al.getName());
+       if (alCurr != null) {
+           affinityLinkList.remove(alCurr);
+           return new Status(StatusCode.SUCCESS);
+       } else {
+           String msg = "Affinity Link with specified name does not exist." + al.getName();
+           return new Status(StatusCode.INTERNALERROR, msg);
+       }
+    }
+    
     @Override
-    public Object readObject(ObjectInputStream ois)
-            throws FileNotFoundException, IOException, ClassNotFoundException {
-        // Perform the class deserialization locally, from inside the package
-        // where the class is defined
-        return ois.readObject();
+    public AffinityLink getAffinityLink(String linkName) {
+        return affinityLinkList.get(linkName);
     }
 
-    @SuppressWarnings("unchecked")
-    private void loadAffinityConfiguration() {
-        ObjectReader objReader = new ObjectReader();
-        ConcurrentMap<String, AffinityConfig> confList = (ConcurrentMap<String, AffinityConfig>) objReader
-                .read(this, affinityConfigFileName);
-
-        if (confList == null) {
-            return;
-        }
-
-        for (AffinityConfig conf : confList.values()) {
-            updateAffinityConfig(conf);
-        }
+    @Override
+    public List<AffinityLink> getAllAffinityLinks() {
+       return new ArrayList<AffinityLink>(affinityLinkList.values());
     }
 
-    /* Add if absent. */
     @Override
-    public Status updateAffinityConfig(AffinityConfig cfgObject) {
-        // update default container only
-        if (!isDefaultContainer) {
-            return new Status(StatusCode.INTERNALERROR, "Not default container");
-        }
+    public Status addAffinityGroup(AffinityGroup ag) {
+       boolean putNewGroup = false;
+       String name = ag.getName();
+       if (affinityGroupList.containsKey(name)) {
+           return new Status(StatusCode.CONFLICT,
+                             "AffinityGroup with the specified name already configured.");
+       } 
+       AffinityGroup agCurr = affinityGroupList.get(name);
+       if (agCurr == null) {
+           if (affinityGroupList.putIfAbsent(name, ag) == null) {
+               putNewGroup = true;
+           } 
+       } else {
+           putNewGroup = affinityGroupList.replace(name, agCurr, ag);
+       }
+
+       if (!putNewGroup) {
+           String msg = "Cluster conflict: Conflict while adding the subnet " + name;
+           return new Status(StatusCode.CONFLICT, msg);
+       }
+       
+        return new Status(StatusCode.SUCCESS);
+    }
 
-        AffinityConfig ac = affinityConfigList.get(cfgObject.getName());
-        if (ac == null) {
-            if (affinityConfigList.putIfAbsent(cfgObject.getName(), cfgObject) != null) {
-                return new Status(StatusCode.CONFLICT, "affinity configuration already exists" + cfgObject.getName());
-            }
-        } else {
-            if (!affinityConfigList.replace(cfgObject.getName(), ac, cfgObject)) {
-                return new Status(StatusCode.INTERNALERROR, "Failed to add affinity configuration.");
-            }
-        }
-        return new Status(StatusCode.SUCCESS, "Updated affinity configuration " + cfgObject.getName());
+    /* Check for errors. */
+    @Override
+    public Status removeAffinityGroup(String name) {
+       affinityGroupList.remove(name);
+       return new Status(StatusCode.SUCCESS);
     }
 
+    @Override
+    public AffinityGroup getAffinityGroup(String groupName) {
+        return affinityGroupList.get(groupName);
+    }
 
-    /* Remove affinity config */
     @Override
-    public Status removeAffinityConfig(String cfgName) {
-        // update default container only
-        if (!isDefaultContainer) {
-            return new Status(StatusCode.INTERNALERROR, "Not default container");
-        }
-        AffinityConfig ac = affinityConfigList.get(cfgName);
-        if (ac != null) {
-            return removeAffinityConfigObject(ac);
-        }
-        return new Status(StatusCode.INTERNALERROR, "Missing affinity config" + cfgName);
+    public List<AffinityGroup> getAllAffinityGroups() {
+        return new ArrayList<AffinityGroup>(affinityGroupList.values());
     }
-    /* Remove affinity config */
+
+    /* Find where this is used. */
     @Override
-    public Status removeAffinityConfigObject(AffinityConfig cfgObject) {
-        // update default container only
-        if (!isDefaultContainer) {
-            return new Status(StatusCode.INTERNALERROR, "Not default container");
-        }
+    public Object readObject(ObjectInputStream ois)
+            throws FileNotFoundException, IOException, ClassNotFoundException {
+        // Perform the class deserialization locally, from inside the package
+        // where the class is defined
+        return ois.readObject();
+    }
 
-        AffinityConfig ac = affinityConfigList.get(cfgObject.getName());
-        if (ac != null) {
-            if (affinityConfigList.remove(cfgObject.getName(), ac)) {
-                return new Status(StatusCode.SUCCESS, "Configuration removed: " + cfgObject.getName());
-            } else {
-                String msg = "Remove failed " + cfgObject.getName();
-                return new Status(StatusCode.INTERNALERROR, msg);
-            }
+    @SuppressWarnings("unchecked")
+    private void loadAffinityConfiguration() {
+        ObjectReader objReader = new ObjectReader();
+        ConcurrentMap<String, AffinityGroup> groupList = (ConcurrentMap<String, AffinityGroup>) objReader.read(this, affinityGroupFileName);
+        ConcurrentMap<String, AffinityLink> linkList = (ConcurrentMap<String, AffinityLink>) objReader.read(this, affinityLinkFileName);
+       
+       /* group list */
+        if (groupList != null) {
+           for (AffinityGroup ag : groupList.values()) {
+               addAffinityGroup(ag);
+           }
+       }
+
+       /* link list */
+       if (linkList != null) {
+           for (AffinityLink al : linkList.values()) {
+               addAffinityLink(al);
+           }
         }
-        return new Status(StatusCode.INTERNALERROR, "Remove failed: " + cfgObject.getName());
     }
     @Override
     public Status saveConfiguration() {
@@ -295,18 +341,17 @@ public class AffinityManagerImpl implements IAffinityManager, IConfigurationCont
         Status retS = null, retP = null;
         ObjectWriter objWriter = new ObjectWriter();
 
-        retS = objWriter.write(new ConcurrentHashMap<String, AffinityConfig>(
-                affinityConfigList), affinityConfigFileName);
-
-        if (retS.equals(retP)) {
-            if (retS.isSuccess()) {
-                return retS;
-            } else {
-                return new Status(StatusCode.INTERNALERROR, "Save failed");
-            }
-        } else {
-            return new Status(StatusCode.INTERNALERROR, "Partial save failure");
-        }
+        retS = objWriter.write(new ConcurrentHashMap<String, AffinityLink>(
+                affinityLinkList), affinityLinkFileName);
+
+        retP = objWriter.write(new ConcurrentHashMap<String, AffinityGroup>(
+                affinityGroupList), affinityGroupFileName);
+
+        if (retS.isSuccess() && retP.isSuccess()) {
+           return new Status(StatusCode.SUCCESS, "Configuration saved.");
+       } else {
+           return new Status(StatusCode.INTERNALERROR, "Save failed");
+       }
     }
 
     @Override
@@ -377,13 +422,13 @@ public class AffinityManagerImpl implements IAffinityManager, IConfigurationCont
     }
 
     void setClusterContainerService(IClusterContainerServices s) {
-        log.debug("Cluster Service set for Statistics Mgr");
+        log.debug("Cluster Service set for affinity mgr");
         this.clusterContainerService = s;
     }
 
     void unsetClusterContainerService(IClusterContainerServices s) {
         if (this.clusterContainerService == s) {
-            log.debug("Cluster Service removed for Statistics Mgr!");
+            log.debug("Cluster Service removed for affinity mgr!");
             this.clusterContainerService = null;
         }
     }
index f1eed7494a45fee6d9fbc0d072966e62e4135dd1..36ec5d712d201076cd06dbed5916875e597bf42b 100644 (file)
@@ -20,7 +20,8 @@ import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.core.State;
 import org.opendaylight.controller.sal.core.UpdateType;
 import org.opendaylight.controller.sal.utils.Status;
-import org.opendaylight.controller.affinity.AffinityConfig;
+import org.opendaylight.controller.affinity.AffinityGroup;
+import org.opendaylight.controller.affinity.AffinityLink;
 
 public class AffinityManagerImplTest {
 
@@ -29,17 +30,60 @@ public class AffinityManagerImplTest {
         AffinityManagerImpl affinitymgr = new AffinityManagerImpl();
         affinitymgr.startUp();
 
-        AffinityConfig ac = new AffinityConfig("test_affinity1", "10.0.0.1", "10.0.0.2", "Isolate");
+       AffinityGroup ag1 = new AffinityGroup("group1");
 
-        // Add status to update/add
-        Status addResult = affinitymgr.updateAffinityConfig(ac);
-        Assert.assertTrue(addResult.isSuccess());
+       // Add a valid IP and confirm. 
+       Status ret1 = ag1.add("10.0.0.10");
+       Assert.assertTrue(ret1.isSuccess());
 
-        Status removeResult = (affinitymgr.removeAffinityConfig(ac.getName()));
-        Assert.assertTrue(removeResult.isSuccess());
+       Status ret2 = ag1.add("10.0.0.20");
+       Assert.assertTrue(ret2.isSuccess());
 
-        AffinityConfig affinityConfigResult = affinitymgr.getAffinityConfig(ac.getName());
-        Assert.assertTrue(affinityConfigResult == null);
-        // System.out.println("*" + switchmgr.addSubnet(subnet) + "*");
+       // Add an invalid element. 
+       Status ret3 = ag1.add("10");
+       System.out.println(ret3);
+       Assert.assertTrue(!ret3.isSuccess());
+
+       // Second affinity group.
+       AffinityGroup ag2 = new AffinityGroup("group2");
+       ag2.add("20.0.0.10");
+       ag2.add("20.0.0.20");
+
+       // Add an affinity link from ag1 to ag2. 
+       AffinityLink al1 = new AffinityLink();
+       al1.setFromGroup(ag1);
+       al1.setToGroup(ag2);
+       al1.setName("link1");
+       al1.setAttribute("isolate");
+
+       // Add a self loop for ag2.
+       AffinityLink al2 = new AffinityLink("link2", ag2, ag2);
+       al2.setFromGroup(ag2);
+       al2.setToGroup(ag2);
+       al2.setName("link2");
+       al2.setAttribute("hopcount");
+
+       System.out.println("Affinity group size is " + ag1.size());
+        Assert.assertTrue(ag1.size() == 2);
+       ag1.print();
+
+        Status result;
+       result = affinitymgr.addAffinityGroup(ag1);
+        Assert.assertTrue(result.isSuccess());
+
+        result = affinitymgr.addAffinityGroup(ag2);
+        Assert.assertTrue(result.isSuccess());
+       
+        result = affinitymgr.addAffinityLink(al1);
+        Assert.assertTrue(result.isSuccess());
+
+        result = affinitymgr.addAffinityLink(al2);
+        Assert.assertTrue(result.isSuccess());
+       
+       /* Constraint checking? */
+        result = (affinitymgr.removeAffinityGroup(ag1.getName()));
+        Assert.assertTrue(result.isSuccess());
+
+       affinitymgr.saveConfiguration();
     }
 }
index 375dfb9166ff12f96d65aa5de41fdb4f4d382b1b..9510b4411963e82f8024c40449c77120c71539ee 100644 (file)
@@ -44,6 +44,8 @@ import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.affinity.IAffinityManager;
 import org.opendaylight.controller.affinity.AffinityConfig;
+import org.opendaylight.controller.affinity.AffinityGroup;
+import org.opendaylight.controller.affinity.AffinityLink;
 
 /**
  * The class provides Northbound REST APIs to access affinity configuration.
@@ -262,4 +264,178 @@ public class AffinityNorthbound {
         }
         throw new InternalServerErrorException(ret.getDescription());
     }
+
+
+    /**
+     * Add an affinity group to the configuration database
+     *
+     * @param containerName
+     *            Name of the Container
+     * @param affinityGroup
+     *            Name of the new affinity being added
+     * @return Response as dictated by the HTTP Response Status code
+     */
+
+    @Path("/{containerName}/create/group/{name}")
+    @PUT
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(Response.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
+    public Response addAffinityGroup(
+            @PathParam("containerName") String containerName,
+            @PathParam("groupName") String groupName) {
+       
+        if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException("User is not authorized to perform this operation on container "
+                                            + containerName);
+        }
+
+        IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
+        if (affinityManager == null) {
+            throw new ServiceUnavailableException("Affinity Manager "
+                                                  + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        AffinityGroup ag = new AffinityGroup(groupName);
+        Status ret = affinityManager.addAffinityGroup(ag);
+        if (ret.isSuccess()) {
+            return Response.status(Response.Status.CREATED).build();
+        }
+        throw new InternalServerErrorException(ret.getDescription());
+    }
+
+    /**
+     * Add an element to an affinity group.
+     *
+     * @param containerName
+     *            Name of the Container
+     * @param affinityGroup
+     *            Name of the group
+     * @param address
+     *            IP or Mac address of the 
+     * @return Response as dictated by the HTTP Response Status code
+     */
+
+    @Path("/{containerName}/{groupname}/add/ip/{address}")
+    @PUT
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(Response.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
+    public Response addIpAddress(
+            @PathParam("containerName") String containerName,
+            @PathParam("groupName") String groupName,
+            @PathParam("address") String ipaddress) {
+       
+        IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
+        if (affinityManager == null) {
+            throw new ServiceUnavailableException("Affinity Manager "
+                                                  + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        AffinityGroup ag = affinityManager.getGroup(groupName);
+        Status ret = ag.addAffinityElement(ipaddress);
+
+        if (ret.isSuccess()) {
+            return Response.status(Response.Status.CREATED).build();
+        }
+        throw new InternalServerErrorException(ret.getDescription());
+    }
+
+
+    /**
+     * Delete an element from an affinity group.
+     *
+     * @param containerName
+     *            Name of the Container
+     * @param affinityGroup
+     *            Name of the group
+     * @param address
+     *            IP or Mac address of the 
+     * @return Response as dictated by the HTTP Response Status code
+     */
+
+    @Path("/{containerName}/{groupname}/delete/ip/{address}")
+    @PUT
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(Response.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
+    public Response deleteIpAddress(
+            @PathParam("containerName") String containerName,
+            @PathParam("groupName") String groupName,
+            @PathParam("address") String ipaddress) {
+       
+        IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
+        if (affinityManager == null) {
+            throw new ServiceUnavailableException("Affinity Manager "
+                                                  + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        AffinityGroup ag = affinityManager.getGroup(groupName);
+        Status ret = ag.removeAffinityElement(ipaddress);
+
+        if (ret.isSuccess()) {
+            return Response.status(Response.Status.CREATED).build();
+        }
+        throw new InternalServerErrorException(ret.getDescription());
+    }
+
+
+
+    /**
+     * Add an affinity link to the database and set its from/to groups.
+     *
+     * @param containerName
+     *            Name of the Container
+     * @param affinityLink
+     *            Name of the affinity link
+     * @param group1
+     *            Name of the affinity group
+     * @param group2
+     *            Name of the affinity group
+     * @return Response as dictated by the HTTP Response Status code
+     */
+
+    @Path("/{containerName}/create/link/{linkName}/from/{group1}/to/{group2}")
+    @PUT
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(Response.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
+    public Response addAffinityLink(
+            @PathParam("containerName") String containerName,
+            @PathParam("linkName") String linkName,
+            @PathParam("group1") String group1,
+            @PathParam("group2") String group2) {
+        IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
+        if (affinityManager == null) {
+            throw new ServiceUnavailableException("Affinity Manager "
+                                                  + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+       /* Add the new link object. */
+        AffinityLink al = new AffinityLink(linkName);
+        Status ret = affinityManager.addAffinityLink(al);
+        if (!ret.isSuccess()) {
+           throw new InternalServerErrorException(ret.getDescription());
+        } 
+       AffinityGroup ag1 = affinityManager.getAffinityGroup(ag1);
+       AffinityGroup ag2 = affinityManager.getAffinityGroup(ag2);
+       
+       al.setFromGroup(ag1);
+       al.setToGroup(ag2);
+       
+       return Response.status(Response.Status.CREATED).build();
+    }
 }
+
index 325f59a70cf2b0ea168d6d6e48031a222fbb9cc4..effe66ad2a47f588cbd264e4574af1746d23c538 100644 (file)
@@ -1,5 +1,5 @@
 Manifest-Version: 1.0\r
-Bnd-LastModified: 1376940269425\r
+Bnd-LastModified: 1377097334954\r
 Build-Jdk: 1.6.0_37\r
 Built-By: sraman\r
 Bundle-ManifestVersion: 2\r