You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by pr...@apache.org on 2013/04/05 07:47:50 UTC

[2/2] git commit: updated refs/heads/affinity_groups to 1b60135

Added AffinityGroup View in order to include VM details while listing AffinityGroups.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/1b60135f
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/1b60135f
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/1b60135f

Branch: refs/heads/affinity_groups
Commit: 1b60135fbca6a4c1ce39ad1717411777a812c1ad
Parents: 68b74a1
Author: Prachi Damle <pr...@cloud.com>
Authored: Thu Apr 4 22:46:11 2013 -0700
Committer: Prachi Damle <pr...@cloud.com>
Committed: Thu Apr 4 22:46:11 2013 -0700

----------------------------------------------------------------------
 .../cloudstack/affinity/AffinityGroupResponse.java |   16 +-
 .../user/affinitygroup/ListAffinityGroupsCmd.java  |   26 +--
 .../affinitygroup/UpdateVMAffinityGroupCmd.java    |    8 +-
 .../org/apache/cloudstack/query/QueryService.java  |    4 +
 client/tomcatconf/applicationContext.xml.in        |   10 +
 client/tomcatconf/componentContext.xml.in          |    3 -
 .../affinity/HostAntiAffinityProcessor.java        |    9 +-
 server/src/com/cloud/api/ApiDBUtils.java           |   14 +
 .../src/com/cloud/api/query/QueryManagerImpl.java  |  108 +++++++
 .../com/cloud/api/query/ViewResponseHelper.java    |   18 +
 .../cloud/api/query/dao/AffinityGroupJoinDao.java  |   37 +++
 .../api/query/dao/AffinityGroupJoinDaoImpl.java    |  155 +++++++++
 .../cloud/api/query/vo/AffinityGroupJoinVO.java    |  248 +++++++++++++++
 .../affinity/dao/AffinityGroupDaoImpl.java         |    1 -
 .../affinity/dao/AffinityGroupVMMapDaoImpl.java    |    1 -
 setup/db/db/schema-410to420.sql                    |   34 ++-
 16 files changed, 660 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java
index 073a82c..1ae7c59 100644
--- a/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java
+++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupResponse.java
@@ -17,6 +17,7 @@
 package org.apache.cloudstack.affinity;
 
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.Set;
 
 import org.apache.cloudstack.api.ApiConstants;
@@ -24,6 +25,7 @@ import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.EntityReference;
 import org.apache.cloudstack.api.response.ControlledEntityResponse;
 import org.apache.cloudstack.api.response.ControlledViewEntityResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
 
 import com.cloud.network.security.SecurityGroup;
 import com.cloud.serializer.Param;
@@ -31,7 +33,7 @@ import com.google.gson.annotations.SerializedName;
 
 @SuppressWarnings("unused")
 @EntityReference(value = AffinityGroup.class)
-public class AffinityGroupResponse extends BaseResponse implements ControlledEntityResponse {
+public class AffinityGroupResponse extends BaseResponse implements ControlledViewEntityResponse {
 
     @SerializedName(ApiConstants.ID) @Param(description="the ID of the affinity group")
     private String id;
@@ -55,8 +57,12 @@ public class AffinityGroupResponse extends BaseResponse implements ControlledEnt
     @Param(description = "the type of the affinity group")
     private String type;
 
+    @SerializedName("virtualmachine")
+    @Param(description = "virtual machines associated with this affinity group ", responseObject = UserVmResponse.class)
+    private Set<UserVmResponse> vmList;
 
     public AffinityGroupResponse() {
+        this.vmList = new LinkedHashSet<UserVmResponse>();
     }
 
     @Override
@@ -136,4 +142,12 @@ public class AffinityGroupResponse extends BaseResponse implements ControlledEnt
 
     }
 
+    public void setVMList(Set<UserVmResponse> vmList) {
+        this.vmList = vmList;
+    }
+
+    public void addVM(UserVmResponse vm) {
+        this.vmList.add(vm);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java
index effbd86..9310fb9 100644
--- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/ListAffinityGroupsCmd.java
@@ -16,23 +16,16 @@
 // under the License.
 package org.apache.cloudstack.api.command.user.affinitygroup;
 
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.cloudstack.affinity.AffinityGroup;
 import org.apache.cloudstack.affinity.AffinityGroupResponse;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.ApiErrorCode;
 import org.apache.cloudstack.api.BaseListCmd;
 import org.apache.cloudstack.api.Parameter;
-import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.log4j.Logger;
 
 import com.cloud.async.AsyncJob;
-import com.cloud.utils.Pair;
 
 @APICommand(name = "listAffinityGroups", description = "Lists affinity groups", responseObject = AffinityGroupResponse.class)
 public class ListAffinityGroupsCmd extends BaseListCmd {
@@ -83,22 +76,11 @@ public class ListAffinityGroupsCmd extends BaseListCmd {
     @Override
     public void execute(){
 
-        Pair<List<? extends AffinityGroup>, Integer> result = _affinityGroupService.listAffinityGroups(id,
-                affinityGroupName,
+        ListResponse<AffinityGroupResponse> response = _queryService.listAffinityGroups(id, affinityGroupName,
                 affinityGroupType, virtualMachineId, this.getStartIndex(), this.getPageSizeVal());
-        if (result != null) {
-            ListResponse<AffinityGroupResponse> response = new ListResponse<AffinityGroupResponse>();
-            List<AffinityGroupResponse> groupResponses = new ArrayList<AffinityGroupResponse>();
-            for (AffinityGroup group : result.first()) {
-                AffinityGroupResponse groupResponse = _responseGenerator.createAffinityGroupResponse(group);
-                groupResponses.add(groupResponse);
-            }
-            response.setResponses(groupResponses, result.second());
-            response.setResponseName(getCommandName());
-            this.setResponseObject(response);
-        } else {
-            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to search for affinity groups");
-        }
+        response.setResponseName(getCommandName());
+        this.setResponseObject(response);
+
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java
index 94f8446..44d017b 100644
--- a/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java
@@ -17,6 +17,7 @@
 package org.apache.cloudstack.api.command.user.affinitygroup;
 
 import java.util.ArrayList;
+import java.util.EnumSet;
 import java.util.List;
 
 import org.apache.cloudstack.affinity.AffinityGroupResponse;
@@ -27,6 +28,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
 import org.apache.cloudstack.api.BaseAsyncCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.ApiConstants.VMDetails;
 import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.log4j.Logger;
 
@@ -131,8 +133,12 @@ public class UpdateVMAffinityGroupCmd extends BaseAsyncCmd {
             InsufficientCapacityException, ServerApiException {
         UserContext.current().setEventDetails("Vm Id: "+getId());
         UserVm result = _affinityGroupService.updateVMAffinityGroups(getId(), getAffinityGroupIdList());
+        ArrayList<VMDetails> dc = new ArrayList<VMDetails>();
+        dc.add(VMDetails.valueOf("affgrp"));
+        EnumSet<VMDetails> details = EnumSet.copyOf(dc);
+
         if (result != null){
-            UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", result).get(0);
+            UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", details, result).get(0);
             response.setResponseName(getCommandName());
             this.setResponseObject(response);
         } else {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/api/src/org/apache/cloudstack/query/QueryService.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/query/QueryService.java b/api/src/org/apache/cloudstack/query/QueryService.java
index c3f86aa..443c5df 100644
--- a/api/src/org/apache/cloudstack/query/QueryService.java
+++ b/api/src/org/apache/cloudstack/query/QueryService.java
@@ -16,6 +16,7 @@
 // under the License.
 package org.apache.cloudstack.query;
 
+import org.apache.cloudstack.affinity.AffinityGroupResponse;
 import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
 import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd;
 import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd;
@@ -97,4 +98,7 @@ public interface QueryService {
     public ListResponse<ServiceOfferingResponse>  searchForServiceOfferings(ListServiceOfferingsCmd cmd);
 
     public ListResponse<ZoneResponse>  listDataCenters(ListZonesByCmd cmd);
+
+    public ListResponse<AffinityGroupResponse> listAffinityGroups(Long affinityGroupId, String affinityGroupName,
+            String affinityGroupType, Long vmId, Long startIndex, Long pageSize);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/client/tomcatconf/applicationContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in
index 6cec8b3..ebce0e3 100644
--- a/client/tomcatconf/applicationContext.xml.in
+++ b/client/tomcatconf/applicationContext.xml.in
@@ -166,4 +166,14 @@
     </property>  
   </bean>
  
+  <bean id="AffinityGroupServiceImpl" class="org.apache.cloudstack.affinity.AffinityGroupServiceImpl"/>
+  <bean id="DeploymentPlanningManager" class="com.cloud.deploy.DeploymentPlanningManagerImpl" />
+  
+  <bean id="AffinityGroupJoinDaoImpl" class="com.cloud.api.query.dao.AffinityGroupJoinDaoImpl">
+  </bean>
+  <bean id="AffinityGroupDaoImpl" class="org.apache.cloudstack.affinity.dao.AffinityGroupDaoImpl">
+  </bean>
+  <bean id="AffinityGroupVMMapDaoImpl" class="org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDaoImpl">
+  </bean>
+  
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/client/tomcatconf/componentContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in
index 2cfdada..fac17f0 100644
--- a/client/tomcatconf/componentContext.xml.in
+++ b/client/tomcatconf/componentContext.xml.in
@@ -77,9 +77,6 @@
   <bean id="UcsBladeDao" class="com.cloud.ucs.database.UcsBladeDaoImpl" />
   <bean id="UcsManagerDao" class="com.cloud.ucs.database.UcsManagerDaoImpl" />
 
-  <bean id="affinityGroupServiceImpl" class="org.apache.cloudstack.affinity.AffinityGroupServiceImpl"/>
-  <bean id="DeploymentPlanningManager" class="com.cloud.deploy.DeploymentPlanningManagerImpl" />
-   
   <!--
       Network Elements
   -->

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
index 88030f2..4049571 100644
--- a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
+++ b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
@@ -65,8 +65,13 @@ public class HostAntiAffinityProcessor extends AffinityProcessorBase implements
 
             for (Long groupVMId : groupVMIds) {
                 VMInstanceVO groupVM = _vmInstanceDao.findById(groupVMId);
-                if (groupVM != null && !groupVM.isRemoved() && groupVM.getHostId() != null) {
-                    avoid.addHost(groupVM.getHostId());
+                if (groupVM != null && !groupVM.isRemoved()) {
+                    if (groupVM.getHostId() != null) {
+                        avoid.addHost(groupVM.getHostId());
+                    } else if (VirtualMachine.State.Stopped.equals(groupVM.getState())
+                            && groupVM.getLastHostId() != null) {
+                        avoid.addHost(groupVM.getLastHostId());
+                    }
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/server/src/com/cloud/api/ApiDBUtils.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java
index 2823c61..332157a 100755
--- a/server/src/com/cloud/api/ApiDBUtils.java
+++ b/server/src/com/cloud/api/ApiDBUtils.java
@@ -26,6 +26,7 @@ import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 
 import org.apache.cloudstack.affinity.AffinityGroup;
+import org.apache.cloudstack.affinity.AffinityGroupResponse;
 import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
 import org.apache.cloudstack.api.ApiConstants.HostDetails;
 import org.apache.cloudstack.api.ApiConstants.VMDetails;
@@ -52,6 +53,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.springframework.stereotype.Component;
 
 import com.cloud.api.query.dao.AccountJoinDao;
+import com.cloud.api.query.dao.AffinityGroupJoinDao;
 import com.cloud.api.query.dao.AsyncJobJoinDao;
 import com.cloud.api.query.dao.DataCenterJoinDao;
 import com.cloud.api.query.dao.DiskOfferingJoinDao;
@@ -69,6 +71,7 @@ import com.cloud.api.query.dao.UserAccountJoinDao;
 import com.cloud.api.query.dao.UserVmJoinDao;
 import com.cloud.api.query.dao.VolumeJoinDao;
 import com.cloud.api.query.vo.AccountJoinVO;
+import com.cloud.api.query.vo.AffinityGroupJoinVO;
 import com.cloud.api.query.vo.AsyncJobJoinVO;
 import com.cloud.api.query.vo.DataCenterJoinVO;
 import com.cloud.api.query.vo.DiskOfferingJoinVO;
@@ -327,6 +330,7 @@ public class ApiDBUtils {
     static ClusterDetailsDao _clusterDetailsDao;
     static NicSecondaryIpDao _nicSecondaryIpDao;
     static AffinityGroupDao _affinityGroupDao;
+    static AffinityGroupJoinDao _affinityGroupJoinDao;
 
     @Inject private ManagementServer ms;
     @Inject public AsyncJobManager asyncMgr;
@@ -431,6 +435,7 @@ public class ApiDBUtils {
     @Inject private VMSnapshotDao vmSnapshotDao;
     @Inject private NicSecondaryIpDao nicSecondaryIpDao;
     @Inject private AffinityGroupDao affinityGroupDao;
+    @Inject private AffinityGroupJoinDao affinityGroupJoinDao;
 
     @PostConstruct
     void init() {
@@ -534,6 +539,7 @@ public class ApiDBUtils {
         _vmSnapshotDao = vmSnapshotDao;
         _nicSecondaryIpDao = nicSecondaryIpDao;
         _affinityGroupDao = affinityGroupDao;
+        _affinityGroupJoinDao = affinityGroupJoinDao;
         // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned
         _statsCollector = StatsCollector.getInstance();
     }
@@ -1540,4 +1546,12 @@ public class ApiDBUtils {
     public static AffinityGroup getAffinityGroup(String groupName, long accountId) {
         return _affinityGroupDao.findByAccountAndName(accountId, groupName);
     }
+
+    public static AffinityGroupResponse newAffinityGroupResponse(AffinityGroupJoinVO group) {
+        return _affinityGroupJoinDao.newAffinityGroupResponse(group);
+    }
+
+    public static AffinityGroupResponse fillAffinityGroupDetails(AffinityGroupResponse resp, AffinityGroupJoinVO group) {
+        return _affinityGroupJoinDao.setAffinityGroupResponse(resp, group);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/server/src/com/cloud/api/query/QueryManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java
index 951d09e..a498c18 100644
--- a/server/src/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/com/cloud/api/query/QueryManagerImpl.java
@@ -27,6 +27,11 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.cloudstack.affinity.AffinityGroup;
+import org.apache.cloudstack.affinity.AffinityGroupResponse;
+import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
+import org.apache.cloudstack.affinity.AffinityGroupVO;
+import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
 import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
 import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd;
 import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd;
@@ -69,6 +74,7 @@ import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
 import com.cloud.api.query.dao.AccountJoinDao;
+import com.cloud.api.query.dao.AffinityGroupJoinDao;
 import com.cloud.api.query.dao.AsyncJobJoinDao;
 import com.cloud.api.query.dao.DataCenterJoinDao;
 import com.cloud.api.query.dao.DiskOfferingJoinDao;
@@ -86,6 +92,7 @@ import com.cloud.api.query.dao.UserAccountJoinDao;
 import com.cloud.api.query.dao.UserVmJoinDao;
 import com.cloud.api.query.dao.VolumeJoinDao;
 import com.cloud.api.query.vo.AccountJoinVO;
+import com.cloud.api.query.vo.AffinityGroupJoinVO;
 import com.cloud.api.query.vo.AsyncJobJoinVO;
 import com.cloud.api.query.vo.DataCenterJoinVO;
 import com.cloud.api.query.vo.DiskOfferingJoinVO;
@@ -138,6 +145,7 @@ import com.cloud.utils.Ternary;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.JoinBuilder;
 import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.SearchCriteria.Func;
@@ -246,6 +254,12 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
     @Inject
     private HighAvailabilityManager _haMgr;
 
+    @Inject
+    AffinityGroupVMMapDao _affinityGroupVMMapDao;
+
+    @Inject
+    private AffinityGroupJoinDao _affinityGroupJoinDao;
+
     /* (non-Javadoc)
      * @see com.cloud.api.query.QueryService#searchForUsers(org.apache.cloudstack.api.command.admin.user.ListUsersCmd)
      */
@@ -2328,5 +2342,99 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
         return false;
     }
 
+    @Override
+    public ListResponse<AffinityGroupResponse> listAffinityGroups(Long affinityGroupId, String affinityGroupName,
+            String affinityGroupType, Long vmId, Long startIndex, Long pageSize) {
+        Pair<List<AffinityGroupJoinVO>, Integer> result = listAffinityGroupsInternal(affinityGroupId,
+                affinityGroupName, affinityGroupType, vmId, startIndex, pageSize);
+        ListResponse<AffinityGroupResponse> response = new ListResponse<AffinityGroupResponse>();
+        List<AffinityGroupResponse> agResponses = ViewResponseHelper.createAffinityGroupResponses(result.first());
+        response.setResponses(agResponses, result.second());
+        return response;
+    }
+
+
+    public Pair<List<AffinityGroupJoinVO>, Integer> listAffinityGroupsInternal(Long affinityGroupId,
+            String affinityGroupName, String affinityGroupType, Long vmId, Long startIndex, Long pageSize) {
+
+        Account caller = UserContext.current().getCaller();
+
+        Long accountId = caller.getAccountId();
+        Long domainId = caller.getDomainId();
+
+        if (vmId != null) {
+            UserVmVO userVM = _userVmDao.findById(vmId);
+            if (userVM == null){
+                throw new InvalidParameterValueException("Unable to list affinity groups for virtual machine instance "
+                        + vmId + "; instance not found.");
+            }
+            _accountMgr.checkAccess(caller, null, true, userVM);
+            return listAffinityGroupsByVM(vmId.longValue(), startIndex, pageSize);
+        }
+
+        Filter searchFilter = new Filter(AffinityGroupJoinVO.class, "id", true, startIndex, pageSize);
+        SearchBuilder<AffinityGroupJoinVO> groupSearch = _affinityGroupJoinDao.createSearchBuilder();
+        groupSearch.select(null, Func.DISTINCT, groupSearch.entity().getId()); // select
+                                                                               // distinct
+
+        SearchCriteria<AffinityGroupJoinVO> sc = groupSearch.create();
+
+        if (accountId != null) {
+            sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
+        }
+
+        if (domainId != null) {
+            sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
+        }
+
+        if (affinityGroupId != null) {
+            sc.addAnd("id", SearchCriteria.Op.EQ, affinityGroupId);
+        }
+
+        if (affinityGroupName != null) {
+            sc.addAnd("name", SearchCriteria.Op.EQ, affinityGroupName);
+        }
+
+        if (affinityGroupType != null) {
+            sc.addAnd("type", SearchCriteria.Op.EQ, affinityGroupType);
+        }
+
+
+        Pair<List<AffinityGroupJoinVO>, Integer> uniqueGroupsPair = _affinityGroupJoinDao.searchAndCount(sc,
+                searchFilter);
+        // search group details by ids
+        Integer count = uniqueGroupsPair.second();
+        if (count.intValue() == 0) {
+            // empty result
+            return uniqueGroupsPair;
+        }
+        List<AffinityGroupJoinVO> uniqueGroups = uniqueGroupsPair.first();
+        Long[] vrIds = new Long[uniqueGroups.size()];
+        int i = 0;
+        for (AffinityGroupJoinVO v : uniqueGroups) {
+            vrIds[i++] = v.getId();
+        }
+        List<AffinityGroupJoinVO> vrs = _affinityGroupJoinDao.searchByIds(vrIds);
+        return new Pair<List<AffinityGroupJoinVO>, Integer>(vrs, count);
+
+    }
+
+    private Pair<List<AffinityGroupJoinVO>, Integer> listAffinityGroupsByVM(long vmId, long pageInd, long pageSize) {
+        Filter sf = new Filter(SecurityGroupVMMapVO.class, null, true, pageInd, pageSize);
+        Pair<List<AffinityGroupVMMapVO>, Integer> agVmMappingPair = _affinityGroupVMMapDao.listByInstanceId(vmId, sf);
+        Integer count = agVmMappingPair.second();
+        if (count.intValue() == 0) {
+            // handle empty result cases
+            return new Pair<List<AffinityGroupJoinVO>, Integer>(new ArrayList<AffinityGroupJoinVO>(), count);
+        }
+        List<AffinityGroupVMMapVO> agVmMappings = agVmMappingPair.first();
+        Long[] agIds = new Long[agVmMappings.size()];
+        int i = 0;
+        for (AffinityGroupVMMapVO agVm : agVmMappings) {
+            agIds[i++] = agVm.getAffinityGroupId();
+        }
+        List<AffinityGroupJoinVO> ags = _affinityGroupJoinDao.searchByIds(agIds);
+        return new Pair<List<AffinityGroupJoinVO>, Integer>(ags, count);
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/server/src/com/cloud/api/query/ViewResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/ViewResponseHelper.java b/server/src/com/cloud/api/query/ViewResponseHelper.java
index 931327a..dc2727e 100644
--- a/server/src/com/cloud/api/query/ViewResponseHelper.java
+++ b/server/src/com/cloud/api/query/ViewResponseHelper.java
@@ -21,6 +21,7 @@ import java.util.EnumSet;
 import java.util.Hashtable;
 import java.util.List;
 
+import org.apache.cloudstack.affinity.AffinityGroupResponse;
 import org.apache.cloudstack.api.ApiConstants.HostDetails;
 import org.apache.cloudstack.api.ApiConstants.VMDetails;
 import org.apache.cloudstack.api.response.AccountResponse;
@@ -45,6 +46,7 @@ import org.apache.log4j.Logger;
 
 import com.cloud.api.ApiDBUtils;
 import com.cloud.api.query.vo.AccountJoinVO;
+import com.cloud.api.query.vo.AffinityGroupJoinVO;
 import com.cloud.api.query.vo.AsyncJobJoinVO;
 import com.cloud.api.query.vo.DataCenterJoinVO;
 import com.cloud.api.query.vo.DiskOfferingJoinVO;
@@ -303,4 +305,20 @@ public class ViewResponseHelper {
         }
         return respList;
     }
+
+    public static List<AffinityGroupResponse> createAffinityGroupResponses(List<AffinityGroupJoinVO> groups) {
+        Hashtable<Long, AffinityGroupResponse> vrDataList = new Hashtable<Long, AffinityGroupResponse>();
+        for (AffinityGroupJoinVO vr : groups) {
+            AffinityGroupResponse vrData = vrDataList.get(vr.getId());
+            if (vrData == null) {
+                // first time encountering this AffinityGroup
+                vrData = ApiDBUtils.newAffinityGroupResponse(vr);
+            } else {
+                // update vms
+                vrData = ApiDBUtils.fillAffinityGroupDetails(vrData, vr);
+            }
+            vrDataList.put(vr.getId(), vrData);
+        }
+        return new ArrayList<AffinityGroupResponse>(vrDataList.values());
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/server/src/com/cloud/api/query/dao/AffinityGroupJoinDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/AffinityGroupJoinDao.java b/server/src/com/cloud/api/query/dao/AffinityGroupJoinDao.java
new file mode 100644
index 0000000..c029b3f
--- /dev/null
+++ b/server/src/com/cloud/api/query/dao/AffinityGroupJoinDao.java
@@ -0,0 +1,37 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.api.query.dao;
+
+import java.util.List;
+
+import org.apache.cloudstack.affinity.AffinityGroup;
+import org.apache.cloudstack.affinity.AffinityGroupResponse;
+import com.cloud.api.query.vo.AffinityGroupJoinVO;
+import com.cloud.user.Account;
+import com.cloud.utils.db.GenericDao;
+
+public interface AffinityGroupJoinDao extends GenericDao<AffinityGroupJoinVO, Long> {
+
+    AffinityGroupResponse newAffinityGroupResponse(AffinityGroupJoinVO vsg);
+
+    AffinityGroupResponse setAffinityGroupResponse(AffinityGroupResponse vsgData, AffinityGroupJoinVO vsg);
+
+    List<AffinityGroupJoinVO> newAffinityGroupView(AffinityGroup ag);
+
+    List<AffinityGroupJoinVO> searchByIds(Long... ids);
+}
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/server/src/com/cloud/api/query/dao/AffinityGroupJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/AffinityGroupJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/AffinityGroupJoinDaoImpl.java
new file mode 100644
index 0000000..98c6440
--- /dev/null
+++ b/server/src/com/cloud/api/query/dao/AffinityGroupJoinDaoImpl.java
@@ -0,0 +1,155 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.api.query.dao;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+
+import org.apache.cloudstack.affinity.AffinityGroup;
+import org.apache.cloudstack.affinity.AffinityGroupResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+import com.cloud.api.ApiResponseHelper;
+import com.cloud.api.query.vo.AffinityGroupJoinVO;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.user.Account;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+@Local(value = { AffinityGroupJoinDao.class })
+public class AffinityGroupJoinDaoImpl extends GenericDaoBase<AffinityGroupJoinVO, Long> implements AffinityGroupJoinDao {
+    public static final Logger s_logger = Logger.getLogger(AffinityGroupJoinDaoImpl.class);
+
+    @Inject
+    private ConfigurationDao  _configDao;
+
+    private final SearchBuilder<AffinityGroupJoinVO> agSearch;
+
+    private final SearchBuilder<AffinityGroupJoinVO> agIdSearch;
+
+    protected AffinityGroupJoinDaoImpl() {
+
+        agSearch = createSearchBuilder();
+        agSearch.and("idIN", agSearch.entity().getId(), SearchCriteria.Op.IN);
+        agSearch.done();
+
+        agIdSearch = createSearchBuilder();
+        agIdSearch.and("id", agIdSearch.entity().getId(), SearchCriteria.Op.EQ);
+        agIdSearch.done();
+
+        this._count = "select count(distinct id) from affinity_group_view WHERE ";
+    }
+
+    @Override
+    public AffinityGroupResponse newAffinityGroupResponse(AffinityGroupJoinVO vag) {
+        AffinityGroupResponse agResponse = new AffinityGroupResponse();
+        agResponse.setId(vag.getUuid());
+        agResponse.setName(vag.getName());
+        agResponse.setDescription(vag.getDescription());
+
+        ApiResponseHelper.populateOwner(agResponse, vag);
+
+        // update vm information
+        long instanceId = vag.getVmId();
+        if (instanceId > 0) {
+            UserVmResponse resp = new UserVmResponse();
+            resp.setObjectName("virtualmachine");
+            resp.setId(vag.getVmUuid());
+            resp.setName(vag.getVmName());
+            resp.setDisplayName(vag.getVmDisplayName());
+            resp.setState(vag.getVmState().toString());
+            agResponse.addVM(resp);
+        }
+
+        agResponse.setObjectName("affinitygroup");
+        return agResponse;
+    }
+
+    @Override
+    public AffinityGroupResponse setAffinityGroupResponse(AffinityGroupResponse vagData, AffinityGroupJoinVO vag) {
+        // update vm information
+        long instanceId = vag.getVmId();
+        if (instanceId > 0) {
+            UserVmResponse resp = new UserVmResponse();
+            resp.setObjectName("virtualmachine");
+            resp.setId(vag.getVmUuid());
+            resp.setName(vag.getVmName());
+            resp.setDisplayName(vag.getVmDisplayName());
+            resp.setState(vag.getVmState().toString());
+            vagData.addVM(resp);
+        }
+        return vagData;
+    }
+
+    @Override
+    public List<AffinityGroupJoinVO> newAffinityGroupView(AffinityGroup ag) {
+
+        SearchCriteria<AffinityGroupJoinVO> sc = agIdSearch.create();
+        sc.setParameters("id", ag.getId());
+        return searchIncludingRemoved(sc, null, null, false);
+    }
+
+    @Override
+    public List<AffinityGroupJoinVO> searchByIds(Long... agIds) {
+        // set detail batch query size
+        int DETAILS_BATCH_SIZE = 2000;
+        String batchCfg = _configDao.getValue("detail.batch.query.size");
+        if ( batchCfg != null ){
+            DETAILS_BATCH_SIZE = Integer.parseInt(batchCfg);
+        }
+        // query details by batches
+        List<AffinityGroupJoinVO> uvList = new ArrayList<AffinityGroupJoinVO>();
+        // query details by batches
+        int curr_index = 0;
+        if (agIds.length > DETAILS_BATCH_SIZE) {
+            while ((curr_index + DETAILS_BATCH_SIZE) <= agIds.length) {
+                Long[] ids = new Long[DETAILS_BATCH_SIZE];
+                for (int k = 0, j = curr_index; j < curr_index + DETAILS_BATCH_SIZE; j++, k++) {
+                    ids[k] = agIds[j];
+                }
+                SearchCriteria<AffinityGroupJoinVO> sc = agSearch.create();
+                sc.setParameters("idIN", ids);
+                List<AffinityGroupJoinVO> vms = searchIncludingRemoved(sc, null, null, false);
+                if (vms != null) {
+                    uvList.addAll(vms);
+                }
+                curr_index += DETAILS_BATCH_SIZE;
+            }
+        }
+        if (curr_index < agIds.length) {
+            int batch_size = (agIds.length - curr_index);
+            // set the ids value
+            Long[] ids = new Long[batch_size];
+            for (int k = 0, j = curr_index; j < curr_index + batch_size; j++, k++) {
+                ids[k] = agIds[j];
+            }
+            SearchCriteria<AffinityGroupJoinVO> sc = agSearch.create();
+            sc.setParameters("idIN", ids);
+            List<AffinityGroupJoinVO> vms = searchIncludingRemoved(sc, null, null, false);
+            if (vms != null) {
+                uvList.addAll(vms);
+            }
+        }
+        return uvList;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java b/server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java
new file mode 100644
index 0000000..e68996c
--- /dev/null
+++ b/server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java
@@ -0,0 +1,248 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.api.query.vo;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import com.cloud.vm.VirtualMachine;
+
+@Entity
+@Table(name = "affinity_group_view")
+public class AffinityGroupJoinVO extends BaseViewVO implements ControlledViewEntity {
+
+    @Id
+    @Column(name="id", updatable=false, nullable = false)
+    private long id;
+
+    @Column(name="name")
+    private String name;
+
+    @Column(name = "description")
+    private String description;
+
+    @Column(name = "uuid")
+    private String uuid;
+
+    @Column(name="account_id")
+    private long accountId;
+
+    @Column(name="account_uuid")
+    private String accountUuid;
+
+    @Column(name="account_name")
+    private String accountName = null;
+
+    @Column(name="account_type")
+    private short accountType;
+
+    @Column(name="domain_id")
+    private long domainId;
+
+    @Column(name="domain_uuid")
+    private String domainUuid;
+
+    @Column(name="domain_name")
+    private String domainName = null;
+
+    @Column(name="domain_path")
+    private String domainPath = null;
+
+    @Column(name = "vm_id")
+    private long vmId;
+
+    @Column(name = "vm_uuid")
+    private String vmUuid;
+
+    @Column(name = "vm_name")
+    private String vmName;
+
+    @Column(name = "vm_display_name")
+    private String vmDisplayName;
+
+    @Column(name = "vm_state")
+    @Enumerated(value = EnumType.STRING)
+    protected VirtualMachine.State vmState = null;
+
+
+    public AffinityGroupJoinVO() {
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+
+    @Override
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public long getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(long accountId) {
+        this.accountId = accountId;
+    }
+
+    @Override
+    public String getAccountUuid() {
+        return accountUuid;
+    }
+
+    public void setAccountUuid(String accountUuid) {
+        this.accountUuid = accountUuid;
+    }
+
+    @Override
+    public String getAccountName() {
+        return accountName;
+    }
+
+    public void setAccountName(String accountName) {
+        this.accountName = accountName;
+    }
+
+    @Override
+    public short getAccountType() {
+        return accountType;
+    }
+
+    public void setAccountType(short accountType) {
+        this.accountType = accountType;
+    }
+
+    @Override
+    public long getDomainId() {
+        return domainId;
+    }
+
+    public void setDomainId(long domainId) {
+        this.domainId = domainId;
+    }
+
+    @Override
+    public String getDomainUuid() {
+        return domainUuid;
+    }
+
+    public void setDomainUuid(String domainUuid) {
+        this.domainUuid = domainUuid;
+    }
+
+    @Override
+    public String getDomainName() {
+        return domainName;
+    }
+
+    public void setDomainName(String domainName) {
+        this.domainName = domainName;
+    }
+
+    @Override
+    public String getDomainPath() {
+        return domainPath;
+    }
+
+    public void setDomainPath(String domainPath) {
+        this.domainPath = domainPath;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public long getVmId() {
+        return vmId;
+    }
+
+    public void setVmId(long vmId) {
+        this.vmId = vmId;
+    }
+
+    public String getVmUuid() {
+        return vmUuid;
+    }
+
+    public void setVmUuid(String vmUuid) {
+        this.vmUuid = vmUuid;
+    }
+
+    public String getVmName() {
+        return vmName;
+    }
+
+    public void setVmName(String vmName) {
+        this.vmName = vmName;
+    }
+
+    public String getVmDisplayName() {
+        return vmDisplayName;
+    }
+
+    public void setVmDisplayName(String vmDisplayName) {
+        this.vmDisplayName = vmDisplayName;
+    }
+
+    public VirtualMachine.State getVmState() {
+        return vmState;
+    }
+
+    public void setVmState(VirtualMachine.State vmState) {
+        this.vmState = vmState;
+    }
+
+    @Override
+    public String getProjectUuid() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public String getProjectName() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java
index f7db418..d189d60 100644
--- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java
+++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java
@@ -26,7 +26,6 @@ import com.cloud.utils.db.GenericDaoBase;
 import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 
-@Component
 @Local(value = { AffinityGroupDao.class })
 public class AffinityGroupDaoImpl extends GenericDaoBase<AffinityGroupVO, Long> implements AffinityGroupDao {
     private SearchBuilder<AffinityGroupVO> AccountIdSearch;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java
index b17d0b3..abc2a2b 100644
--- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java
+++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java
@@ -37,7 +37,6 @@ import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.SearchCriteria.Func;
 import com.cloud.utils.db.Transaction;
 
-@Component
 @Local(value = { AffinityGroupVMMapDao.class })
 public class AffinityGroupVMMapDaoImpl extends GenericDaoBase<AffinityGroupVMMapVO, Long> implements
         AffinityGroupVMMapDao {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1b60135f/setup/db/db/schema-410to420.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql
index fc0a718..cc759b8 100644
--- a/setup/db/db/schema-410to420.sql
+++ b/setup/db/db/schema-410to420.sql
@@ -591,6 +591,38 @@ CREATE VIEW `cloud`.`user_vm_view` AS
 			left join
         `cloud`.`affinity_group` ON affinity_group_vm_map.affinity_group_id = affinity_group.id;
 
-			
+DROP VIEW IF EXISTS `cloud`.`affinity_group_view`;
+CREATE VIEW `cloud`.`affinity_group_view` AS
+    select 
+        affinity_group.id id,
+        affinity_group.name name,
+        affinity_group.description description,
+        affinity_group.uuid uuid,
+        account.id account_id,
+        account.uuid account_uuid,
+        account.account_name account_name,
+        account.type account_type,
+        domain.id domain_id,
+        domain.uuid domain_uuid,
+        domain.name domain_name,
+        domain.path domain_path,
+        vm_instance.id vm_id,
+        vm_instance.uuid vm_uuid,
+        vm_instance.name vm_name,
+        vm_instance.state vm_state,
+        user_vm.display_name vm_display_name
+    from
+        `cloud`.`affinity_group`
+            inner join
+        `cloud`.`account` ON affinity_group.account_id = account.id
+            inner join
+        `cloud`.`domain` ON affinity_group.domain_id = domain.id
+            left join
+        `cloud`.`affinity_group_vm_map` ON affinity_group.id = affinity_group_vm_map.affinity_group_id
+            left join
+        `cloud`.`vm_instance` ON vm_instance.id = affinity_group_vm_map.instance_id
+            left join
+		`cloud`.`user_vm` ON user_vm.id = vm_instance.id;
+		
 -- Re-enable foreign key checking, at the end of the upgrade path
 SET foreign_key_checks = 1;			
\ No newline at end of file