You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by bf...@apache.org on 2013/04/12 00:13:24 UTC

[16/48] git commit: updated refs/heads/ui-vm-affinity to 96999be

Changes to add AffinityGroupprocessor, deployVM changes


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

Branch: refs/heads/ui-vm-affinity
Commit: fe2a86871fde27832b8ed99f5fe965b905b874c0
Parents: 1aed5bf
Author: Prachi Damle <pr...@cloud.com>
Authored: Wed Mar 13 13:57:47 2013 -0700
Committer: Prachi Damle <pr...@cloud.com>
Committed: Thu Apr 11 13:22:42 2013 -0700

----------------------------------------------------------------------
 api/src/com/cloud/event/EventTypes.java            |    1 +
 .../cloud/exception/AffinityConflictException.java |   18 ++
 api/src/com/cloud/vm/UserVmService.java            |  183 ++++++++-------
 .../affinity/AffinityGroupProcessor.java           |   14 ++
 .../cloudstack/affinity/AffinityGroupService.java  |    3 +
 .../org/apache/cloudstack/api/ApiConstants.java    |    2 +
 .../user/affinitygroup/ListAffinityGroupsCmd.java  |    3 +-
 .../affinitygroup/UpdateVMAffinityGroupCmd.java    |  158 +++++++++++++
 .../api/command/user/vm/DeployVMCmd.java           |   43 ++++-
 .../deploy/UserPreferrenceProcessor.java           |   27 +++
 .../cloud/deploy/DeploymentPlanningManager.java    |   29 +++
 .../deploy/DeploymentPlanningManagerImpl.java      |   80 +++++++
 server/src/com/cloud/vm/UserVmManagerImpl.java     |   62 ++++--
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |   97 ++++----
 .../affinity/AffinityGroupServiceImpl.java         |   71 +++++-
 .../affinity/HostAntiAffinityProcessor.java        |   66 ++++++
 .../affinity/dao/AffinityGroupVMMapDao.java        |    4 +
 .../affinity/dao/AffinityGroupVMMapDaoImpl.java    |   43 ++++
 .../test/com/cloud/vm/MockUserVmManagerImpl.java   |   16 +-
 utils/src/com/cloud/utils/SerialVersionUID.java    |    1 +
 20 files changed, 755 insertions(+), 166 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/api/src/com/cloud/event/EventTypes.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index bd5f220..6a26212 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -386,6 +386,7 @@ public class EventTypes {
     public static final String EVENT_AFFINITY_GROUP_DELETE = "AG.DELETE";
     public static final String EVENT_AFFINITY_GROUP_ASSIGN = "AG.ASSIGN";
     public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE";
+    public static final String EVENT_VM_AFFINITY_GROUP_UPDATE = "VM.AG.UPDATE";
 
     static {
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/api/src/com/cloud/exception/AffinityConflictException.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/exception/AffinityConflictException.java b/api/src/com/cloud/exception/AffinityConflictException.java
new file mode 100644
index 0000000..75df784
--- /dev/null
+++ b/api/src/com/cloud/exception/AffinityConflictException.java
@@ -0,0 +1,18 @@
+package com.cloud.exception;
+
+import com.cloud.exception.CloudException;
+import com.cloud.utils.SerialVersionUID;
+
+public class AffinityConflictException extends CloudException {
+
+    private static final long serialVersionUID = SerialVersionUID.AffinityConflictException;
+
+    public AffinityConflictException(String message) {
+        super(message);
+    }
+
+    public AffinityConflictException(String message, Throwable th) {
+        super(message, th);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/api/src/com/cloud/vm/UserVmService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java
index 2c33d41..d963b74 100755
--- a/api/src/com/cloud/vm/UserVmService.java
+++ b/api/src/com/cloud/vm/UserVmService.java
@@ -26,9 +26,6 @@ import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
 import org.apache.cloudstack.api.command.user.vm.*;
 import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
 import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
-import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
-import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
-
 import com.cloud.dc.DataCenter;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientCapacityException;
@@ -42,7 +39,6 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.Network.IpAddresses;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.storage.StoragePool;
-import com.cloud.storage.Volume;
 import com.cloud.template.VirtualMachineTemplate;
 import com.cloud.user.Account;
 import com.cloud.uservm.UserVm;
@@ -104,14 +100,14 @@ public interface UserVmService {
      * @return the vm object if successful, null otherwise
      */
     UserVm addNicToVirtualMachine(AddNicToVMCmd cmd);
-    
+
     /**
      * Removes a NIC on the given network from the virtual machine
      * @param cmd the command object that defines the vm and the given network
      * @return the vm object if successful, null otherwise
      */
     UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd);
-    
+
     /**
      * Updates default Nic to the given network for given virtual machine
      * @param cmd the command object that defines the vm and the given network
@@ -123,7 +119,8 @@ public interface UserVmService {
 
 
     /**
-     * Creates a Basic Zone User VM in the database and returns the VM to the caller.
+     * Creates a Basic Zone User VM in the database and returns the VM to the
+     * caller.
      *
      * @param zone
      *            - availability zone for the virtual machine
@@ -132,61 +129,69 @@ public interface UserVmService {
      * @param template
      *            - the template for the virtual machine
      * @param securityGroupIdList
-     *            - comma separated list of security groups id that going to be applied to the virtual machine
+     *            - comma separated list of security groups id that going to be
+     *            applied to the virtual machine
      * @param hostName
      *            - host name for the virtual machine
      * @param displayName
      *            - an optional user generated name for the virtual machine
      * @param diskOfferingId
-     *            - the ID of the disk offering for the virtual machine. If the template is of ISO format, the
-     *            diskOfferingId is
-     *            for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk
-     *            volume.
-     *            If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk
-     *            Volume
-     *            created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT
-     *            Disk
-     *            Volume created
+     *            - the ID of the disk offering for the virtual machine. If the
+     *            template is of ISO format, the diskOfferingId is for the root
+     *            disk volume. Otherwise this parameter is used to indicate the
+     *            offering for the data disk volume. If the templateId parameter
+     *            passed is from a Template object, the diskOfferingId refers to
+     *            a DATA Disk Volume created. If the templateId parameter passed
+     *            is from an ISO object, the diskOfferingId refers to a ROOT
+     *            Disk Volume created
      * @param diskSize
-     *            - the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId
+     *            - the arbitrary size for the DATADISK volume. Mutually
+     *            exclusive with diskOfferingId
      * @param group
      *            - an optional group for the virtual machine
      * @param hypervisor
      *            - the hypervisor on which to deploy the virtual machine
      * @param userData
-     *            - an optional binary data that can be sent to the virtual machine upon a successful deployment. This
-     *            binary
-     *            data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported.
-     *            Using HTTP
-     *            GET (via querystring), you can send up to 2KB of data after base64 encoding
+     *            - an optional binary data that can be sent to the virtual
+     *            machine upon a successful deployment. This binary data must be
+     *            base64 encoded before adding it to the request. Currently only
+     *            HTTP GET is supported. Using HTTP GET (via querystring), you
+     *            can send up to 2KB of data after base64 encoding
      * @param sshKeyPair
-     *            - name of the ssh key pair used to login to the virtual machine
+     *            - name of the ssh key pair used to login to the virtual
+     *            machine
      * @param requestedIps
      *            TODO
      * @param defaultIp
      *            TODO
+     * @param affinityGroupIdList
      * @param accountName
-     *            - an optional account for the virtual machine. Must be used with domainId
+     *            - an optional account for the virtual machine. Must be used
+     *            with domainId
      * @param domainId
-     *            - an optional domainId for the virtual machine. If the account parameter is used, domainId must also
-     *            be used
+     *            - an optional domainId for the virtual machine. If the account
+     *            parameter is used, domainId must also be used
      * @return UserVm object if successful.
      *
      * @throws InsufficientCapacityException
      *             if there is insufficient capacity to deploy the VM.
      * @throws ConcurrentOperationException
-     *             if there are multiple users working on the same VM or in the same environment.
+     *             if there are multiple users working on the same VM or in the
+     *             same environment.
      * @throws ResourceUnavailableException
-     *             if the resources required to deploy the VM is not currently available.
+     *             if the resources required to deploy the VM is not currently
+     *             available.
      * @throws InsufficientResourcesException
      */
     UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, Account owner, String hostName,
-            String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, String keyboard)
+            String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
+            String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp,
+            String keyboard, List<Long> affinityGroupIdList)
             throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
 
     /**
-     * Creates a User VM in Advanced Zone (Security Group feature is enabled) in the database and returns the VM to the
-     * caller.
+     * Creates a User VM in Advanced Zone (Security Group feature is enabled) in
+     * the database and returns the VM to the caller.
      *
      * @param zone
      *            - availability zone for the virtual machine
@@ -197,63 +202,69 @@ public interface UserVmService {
      * @param networkIdList
      *            - list of network ids used by virtual machine
      * @param securityGroupIdList
-     *            - comma separated list of security groups id that going to be applied to the virtual machine
+     *            - comma separated list of security groups id that going to be
+     *            applied to the virtual machine
      * @param hostName
      *            - host name for the virtual machine
      * @param displayName
      *            - an optional user generated name for the virtual machine
      * @param diskOfferingId
-     *            - the ID of the disk offering for the virtual machine. If the template is of ISO format, the
-     *            diskOfferingId is
-     *            for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk
-     *            volume.
-     *            If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk
-     *            Volume
-     *            created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT
-     *            Disk
-     *            Volume created
+     *            - the ID of the disk offering for the virtual machine. If the
+     *            template is of ISO format, the diskOfferingId is for the root
+     *            disk volume. Otherwise this parameter is used to indicate the
+     *            offering for the data disk volume. If the templateId parameter
+     *            passed is from a Template object, the diskOfferingId refers to
+     *            a DATA Disk Volume created. If the templateId parameter passed
+     *            is from an ISO object, the diskOfferingId refers to a ROOT
+     *            Disk Volume created
      * @param diskSize
-     *            - the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId
+     *            - the arbitrary size for the DATADISK volume. Mutually
+     *            exclusive with diskOfferingId
      * @param group
      *            - an optional group for the virtual machine
      * @param hypervisor
      *            - the hypervisor on which to deploy the virtual machine
      * @param userData
-     *            - an optional binary data that can be sent to the virtual machine upon a successful deployment. This
-     *            binary
-     *            data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported.
-     *            Using HTTP
-     *            GET (via querystring), you can send up to 2KB of data after base64 encoding
+     *            - an optional binary data that can be sent to the virtual
+     *            machine upon a successful deployment. This binary data must be
+     *            base64 encoded before adding it to the request. Currently only
+     *            HTTP GET is supported. Using HTTP GET (via querystring), you
+     *            can send up to 2KB of data after base64 encoding
      * @param sshKeyPair
-     *            - name of the ssh key pair used to login to the virtual machine
+     *            - name of the ssh key pair used to login to the virtual
+     *            machine
      * @param requestedIps
      *            TODO
      * @param defaultIps
      *            TODO
+     * @param affinityGroupIdList
      * @param accountName
-     *            - an optional account for the virtual machine. Must be used with domainId
+     *            - an optional account for the virtual machine. Must be used
+     *            with domainId
      * @param domainId
-     *            - an optional domainId for the virtual machine. If the account parameter is used, domainId must also
-     *            be used
+     *            - an optional domainId for the virtual machine. If the account
+     *            parameter is used, domainId must also be used
      * @return UserVm object if successful.
      *
      * @throws InsufficientCapacityException
      *             if there is insufficient capacity to deploy the VM.
      * @throws ConcurrentOperationException
-     *             if there are multiple users working on the same VM or in the same environment.
+     *             if there are multiple users working on the same VM or in the
+     *             same environment.
      * @throws ResourceUnavailableException
-     *             if the resources required to deploy the VM is not currently available.
+     *             if the resources required to deploy the VM is not currently
+     *             available.
      * @throws InsufficientResourcesException
      */
     UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, List<Long> securityGroupIdList,
             Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps,
-            IpAddresses defaultIps, String keyboard)
+            IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
             throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
 
     /**
-     * Creates a User VM in Advanced Zone (Security Group feature is disabled) in the database and returns the VM to the
-     * caller.
-     *
+     * Creates a User VM in Advanced Zone (Security Group feature is disabled)
+     * in the database and returns the VM to the caller.
+     * 
      * @param zone
      *            - availability zone for the virtual machine
      * @param serviceOffering
@@ -267,49 +278,57 @@ public interface UserVmService {
      * @param displayName
      *            - an optional user generated name for the virtual machine
      * @param diskOfferingId
-     *            - the ID of the disk offering for the virtual machine. If the template is of ISO format, the
-     *            diskOfferingId is
-     *            for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk
-     *            volume.
-     *            If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk
-     *            Volume
-     *            created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT
-     *            Disk
-     *            Volume created
+     *            - the ID of the disk offering for the virtual machine. If the
+     *            template is of ISO format, the diskOfferingId is for the root
+     *            disk volume. Otherwise this parameter is used to indicate the
+     *            offering for the data disk volume. If the templateId parameter
+     *            passed is from a Template object, the diskOfferingId refers to
+     *            a DATA Disk Volume created. If the templateId parameter passed
+     *            is from an ISO object, the diskOfferingId refers to a ROOT
+     *            Disk Volume created
      * @param diskSize
-     *            - the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId
+     *            - the arbitrary size for the DATADISK volume. Mutually
+     *            exclusive with diskOfferingId
      * @param group
      *            - an optional group for the virtual machine
      * @param hypervisor
      *            - the hypervisor on which to deploy the virtual machine
      * @param userData
-     *            - an optional binary data that can be sent to the virtual machine upon a successful deployment. This
-     *            binary
-     *            data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported.
-     *            Using HTTP
-     *            GET (via querystring), you can send up to 2KB of data after base64 encoding
+     *            - an optional binary data that can be sent to the virtual
+     *            machine upon a successful deployment. This binary data must be
+     *            base64 encoded before adding it to the request. Currently only
+     *            HTTP GET is supported. Using HTTP GET (via querystring), you
+     *            can send up to 2KB of data after base64 encoding
      * @param sshKeyPair
-     *            - name of the ssh key pair used to login to the virtual machine
+     *            - name of the ssh key pair used to login to the virtual
+     *            machine
      * @param requestedIps
      *            TODO
-     * @param defaultIps TODO
+     * @param defaultIps
+     *            TODO
+     * @param affinityGroupIdList
      * @param accountName
-     *            - an optional account for the virtual machine. Must be used with domainId
+     *            - an optional account for the virtual machine. Must be used
+     *            with domainId
      * @param domainId
-     *            - an optional domainId for the virtual machine. If the account parameter is used, domainId must also
-     *            be used
+     *            - an optional domainId for the virtual machine. If the account
+     *            parameter is used, domainId must also be used
      * @return UserVm object if successful.
-     *
+     * 
      * @throws InsufficientCapacityException
      *             if there is insufficient capacity to deploy the VM.
      * @throws ConcurrentOperationException
-     *             if there are multiple users working on the same VM or in the same environment.
+     *             if there are multiple users working on the same VM or in the
+     *             same environment.
      * @throws ResourceUnavailableException
-     *             if the resources required to deploy the VM is not currently available.
+     *             if the resources required to deploy the VM is not currently
+     *             available.
      * @throws InsufficientResourcesException
      */
     UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, String hostName,
-            String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard)
+            String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
+            String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps,
+            String keyboard, List<Long> affinityGroupIdList)
             throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
 
     /**

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java
new file mode 100644
index 0000000..e6c64b3
--- /dev/null
+++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java
@@ -0,0 +1,14 @@
+package org.apache.cloudstack.affinity;
+
+import org.apache.cloudstack.deploy.UserPreferrenceProcessor;
+
+public interface AffinityGroupProcessor extends UserPreferrenceProcessor {
+
+    /**
+     * getType() should return the affinity/anti-affinity group being
+     * implemented
+     *
+     * @return String Affinity/Anti-affinity type
+     */
+    String getType();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java
index 368abe2..b6bf2ab 100644
--- a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java
+++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java
@@ -3,6 +3,7 @@ package org.apache.cloudstack.affinity;
 import java.util.List;
 
 import com.cloud.exception.ResourceInUseException;
+import com.cloud.uservm.UserVm;
 import com.cloud.utils.Pair;
 
 public interface AffinityGroupService {
@@ -57,4 +58,6 @@ public interface AffinityGroupService {
 
     AffinityGroup getAffinityGroup(Long groupId);
 
+    UserVm updateVMAffinityGroups(Long vmId, List<Long> affinityGroupIds);
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index c518830..cfabc61 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -473,6 +473,8 @@ public class ApiConstants {
     public static final String HEALTHCHECK_HEALTHY_THRESHOLD = "healthythreshold";
     public static final String HEALTHCHECK_UNHEALTHY_THRESHOLD = "unhealthythreshold";
     public static final String HEALTHCHECK_PINGPATH = "pingpath";
+    public static final String AFFINITY_GROUP_IDS = "affinitygroupids";
+    public static final String AFFINITY_GROUP_NAMES = "affinitygroupnames";
 
     public enum HostDetails {
         all, capacity, events, stats, min;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/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 09d1f8f..effbd86 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
@@ -83,7 +83,8 @@ public class ListAffinityGroupsCmd extends BaseListCmd {
     @Override
     public void execute(){
 
-        Pair<List<AffinityGroup>, Integer> result = _affinityGroupService.listAffinityGroups(id, affinityGroupName,
+        Pair<List<? extends AffinityGroup>, Integer> result = _affinityGroupService.listAffinityGroups(id,
+                affinityGroupName,
                 affinityGroupType, virtualMachineId, this.getStartIndex(), this.getPageSizeVal());
         if (result != null) {
             ListResponse<AffinityGroupResponse> response = new ListResponse<AffinityGroupResponse>();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/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
new file mode 100644
index 0000000..94f8446
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/user/affinitygroup/UpdateVMAffinityGroupCmd.java
@@ -0,0 +1,158 @@
+// 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 org.apache.cloudstack.api.command.user.affinitygroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cloudstack.affinity.AffinityGroupResponse;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+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.response.UserVmResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.async.AsyncJob;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+import com.cloud.user.UserContext;
+import com.cloud.uservm.UserVm;
+
+
+@APICommand(name = "updateVMAffinityGroup", description = "Updates the affinity/anti-affinity group associations of a virtual machine. The VM has to be stopped and restarted for the "
+        + "new properties to take effect.", responseObject = UserVmResponse.class)
+public class UpdateVMAffinityGroupCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(UpdateVMAffinityGroupCmd.class.getName());
+    private static final String s_name = "updatevirtualmachineresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+
+    @ACL
+    @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=UserVmResponse.class,
+            required=true, description="The ID of the virtual machine")
+    private Long id;
+
+    @ACL
+    @Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are going to be applied to the virtual machine. "
+            + "Should be passed only when vm is created from a zone with Basic Network support."
+            + " Mutually exclusive with securitygroupnames parameter")
+    private List<Long> affinityGroupIdList;
+
+    @ACL
+    @Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are going to be applied to the virtual machine."
+            + " Should be passed only when vm is created from a zone with Basic Network support. "
+            + "Mutually exclusive with securitygroupids parameter")
+    private List<String> affinityGroupNameList;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+
+    public Long getId() {
+        return id;
+    }
+
+
+    public List<Long> getAffinityGroupIdList() {
+        if (affinityGroupNameList != null && affinityGroupIdList != null) {
+            throw new InvalidParameterValueException(
+                    "affinitygroupids parameter is mutually exclusive with affinitygroupnames parameter");
+        }
+
+        // transform group names to ids here
+        if (affinityGroupNameList != null) {
+            List<Long> affinityGroupIds = new ArrayList<Long>();
+            for (String groupName : affinityGroupNameList) {
+                Long groupId = _responseGenerator.getAffinityGroupId(groupName, getEntityOwnerId());
+                if (groupId == null) {
+                    throw new InvalidParameterValueException("Unable to find group by name " + groupName
+                            + " for account " + getEntityOwnerId());
+                } else {
+                    affinityGroupIds.add(groupId);
+                }
+            }
+            return affinityGroupIds;
+        } else {
+            return affinityGroupIdList;
+        }
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    public static String getResultObjectName() {
+        return "virtualmachine";
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        UserVm userVm = _entityMgr.findById(UserVm.class, getId());
+        if (userVm != null) {
+            return userVm.getAccountId();
+        }
+
+        return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException,
+            InsufficientCapacityException, ServerApiException {
+        UserContext.current().setEventDetails("Vm Id: "+getId());
+        UserVm result = _affinityGroupService.updateVMAffinityGroups(getId(), getAffinityGroupIdList());
+        if (result != null){
+            UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", result).get(0);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update vm's affinity groups");
+        }
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_VM_AFFINITY_GROUP_UPDATE;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "updating VM Affinity Group";
+    }
+
+    @Override
+    public AsyncJob.Type getInstanceType() {
+        return AsyncJob.Type.AffinityGroup;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
index 21a45f8..22fe1ba 100755
--- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.affinity.AffinityGroupResponse;
 import org.apache.cloudstack.api.ACL;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
@@ -172,6 +173,18 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
     @Parameter(name=ApiConstants.START_VM, type=CommandType.BOOLEAN, description="true if network offering supports specifying ip ranges; defaulted to true if not specified")
     private Boolean startVm;
 
+    @ACL
+    @Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are going to be applied to the virtual machine. "
+            + "Should be passed only when vm is created from a zone with Basic Network support."
+            + " Mutually exclusive with securitygroupnames parameter")
+    private List<Long> affinityGroupIdList;
+
+    @ACL
+    @Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are going to be applied to the virtual machine."
+            + " Should be passed only when vm is created from a zone with Basic Network support. "
+            + "Mutually exclusive with securitygroupids parameter")
+    private List<String> affinityGroupNameList;
+
 
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
@@ -321,6 +334,30 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
 		return ip6Address.toLowerCase();
 	}
 
+    public List<Long> getAffinityGroupIdList() {
+        if (affinityGroupNameList != null && affinityGroupIdList != null) {
+            throw new InvalidParameterValueException(
+                    "affinitygroupids parameter is mutually exclusive with affinitygroupnames parameter");
+        }
+
+        // transform group names to ids here
+        if (affinityGroupNameList != null) {
+            List<Long> affinityGroupIds = new ArrayList<Long>();
+            for (String groupName : affinityGroupNameList) {
+                Long groupId = _responseGenerator.getAffinityGroupId(groupName, getEntityOwnerId());
+                if (groupId == null) {
+                    throw new InvalidParameterValueException("Unable to find group by name " + groupName
+                            + " for account " + getEntityOwnerId());
+                } else {
+                    affinityGroupIds.add(groupId);
+                }
+            }
+            return affinityGroupIds;
+        } else {
+            return affinityGroupIdList;
+        }
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -447,18 +484,18 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
                     throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
                 } else {
                     vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name,
-                                displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard);
+                                displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
                 }
             } else {
                 if (zone.isSecurityGroupEnabled())  {
                     vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(),
-                                owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard);
+                                owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
                 } else {
                     if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) {
                         throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone");
                     }
                     vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName,
-                                diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard);
+                                diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java b/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java
new file mode 100644
index 0000000..ad26f0e
--- /dev/null
+++ b/api/src/org/apache/cloudstack/deploy/UserPreferrenceProcessor.java
@@ -0,0 +1,27 @@
+package org.apache.cloudstack.deploy;
+
+
+import com.cloud.deploy.DeploymentPlan;
+import com.cloud.deploy.DeploymentPlanner.ExcludeList;
+import com.cloud.exception.AffinityConflictException;
+import com.cloud.utils.component.Adapter;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+
+public interface UserPreferrenceProcessor extends Adapter {
+
+    /**
+     * process() is called to apply any user preferences to the deployment plan
+     * and avoid set for the given VM placement.
+     *
+     * @param vm
+     *            virtual machine.
+     * @param plan
+     *            deployment plan that tells you where it's being deployed to.
+     * @param avoid
+     *            avoid these data centers, pods, clusters, or hosts.
+     */
+    void process(VirtualMachineProfile<? extends VirtualMachine> vm, DeploymentPlan plan, ExcludeList avoid)
+            throws AffinityConflictException;
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/server/src/com/cloud/deploy/DeploymentPlanningManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManager.java b/server/src/com/cloud/deploy/DeploymentPlanningManager.java
new file mode 100644
index 0000000..4ac71e3
--- /dev/null
+++ b/server/src/com/cloud/deploy/DeploymentPlanningManager.java
@@ -0,0 +1,29 @@
+package com.cloud.deploy;
+
+import com.cloud.deploy.DeploymentPlanner.ExcludeList;
+import com.cloud.exception.AffinityConflictException;
+import com.cloud.exception.InsufficientServerCapacityException;
+import com.cloud.utils.component.Manager;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+
+public interface DeploymentPlanningManager extends Manager {
+
+    /**
+     * Manages vm deployment stages: First Process Affinity/Anti-affinity - Call
+     * the chain of AffinityGroupProcessor adapters to set deploymentplan scope
+     * and exclude list Secondly, Call DeploymentPlanner - to use heuristics to
+     * find the best spot to place the vm/volume. Planner will drill down to the
+     * write set of clusters to look for placement based on various heuristics.
+     * Lastly, Call Allocators - Given a cluster, allocators matches the
+     * requirements to capabilities of the physical resource (host, storage
+     * pool).
+     *
+     * @throws AffinityConflictException
+     *
+     *
+     *
+     */
+    DeployDestination planDeployment(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan,
+            ExcludeList avoids) throws InsufficientServerCapacityException, AffinityConflictException;
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
new file mode 100644
index 0000000..11e5b82
--- /dev/null
+++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
@@ -0,0 +1,80 @@
+package com.cloud.deploy;
+
+import java.util.List;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+import org.apache.cloudstack.affinity.AffinityGroupProcessor;
+import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
+import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
+import org.apache.log4j.Logger;
+
+import com.cloud.deploy.DeploymentPlanner.ExcludeList;
+import com.cloud.exception.AffinityConflictException;
+import com.cloud.exception.InsufficientServerCapacityException;
+import com.cloud.utils.component.Manager;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
+
+@Local(value = { DeploymentPlanningManager.class })
+public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager {
+
+    private static final Logger s_logger = Logger.getLogger(DeploymentPlanningManagerImpl.class);
+    @Inject
+    protected UserVmDao _vmDao;
+    @Inject
+    protected VMInstanceDao _vmInstanceDao;
+    @Inject
+    protected AffinityGroupDao _affinityGroupDao;
+    @Inject
+    protected AffinityGroupVMMapDao _affinityGroupVMMapDao;
+
+    @Inject
+    protected List<DeploymentPlanner> _planners;
+
+    @Inject
+    protected List<AffinityGroupProcessor> _affinityProcessors;
+
+    @Override
+    public DeployDestination planDeployment(VirtualMachineProfile<? extends VirtualMachine> vmProfile,
+            DeploymentPlan plan, ExcludeList avoids) throws InsufficientServerCapacityException,
+            AffinityConflictException {
+
+        // call affinitygroup chain
+        VirtualMachine vm = vmProfile.getVirtualMachine();
+        long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
+
+        if (vmGroupCount > 0) {
+            for (AffinityGroupProcessor processor : _affinityProcessors) {
+                processor.process(vmProfile, plan, avoids);
+            }
+        }
+
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Deploy avoids pods: " + avoids.getPodsToAvoid() + ", clusters: "
+                    + avoids.getClustersToAvoid() + ", hosts: " + avoids.getHostsToAvoid());
+        }
+
+        // call planners
+        DeployDestination dest = null;
+        for (DeploymentPlanner planner : _planners) {
+            if (planner.canHandle(vmProfile, plan, avoids)) {
+                dest = planner.plan(vmProfile, plan, avoids);
+            } else {
+                continue;
+            }
+            if (dest != null) {
+                avoids.addHost(dest.getHost().getId());
+                break;
+            }
+
+        }
+        return dest;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 1c3764a..ca158f1 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -35,6 +35,9 @@ import javax.naming.ConfigurationException;
 import com.cloud.api.ApiDBUtils;
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.affinity.AffinityGroupVO;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
+import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
 import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
 import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
 import org.apache.cloudstack.api.command.user.vm.*;
@@ -369,7 +372,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
     VpcManager _vpcMgr;
     @Inject
     TemplateManager templateMgr;
-    @Inject 
+    @Inject
     protected GuestOSCategoryDao _guestOSCategoryDao;
     @Inject
     UsageEventDao _usageEventDao;
@@ -379,6 +382,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
     protected VMSnapshotManager _vmSnapshotMgr;
 
     @Inject
+    AffinityGroupVMMapDao _affinityGroupVMMapDao;
+    @Inject
+    AffinityGroupDao _affinityGroupDao;
+
+    @Inject
     List<DeployPlannerSelector> plannerSelectors;
 
     protected ScheduledExecutorService _executor = null;
@@ -684,7 +692,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
 
         try {
             VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
-            status = vmEntity.stop(new Long(userId).toString());            
+            status = vmEntity.stop(new Long(userId).toString());
         } catch (ResourceUnavailableException e) {
             s_logger.debug("Unable to stop due to ", e);
             status = false;
@@ -1916,7 +1924,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
 
     @Override
     public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, Account owner,
-            String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard)
+ String hostName,
+            String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
+            String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps,
+            String keyboard, List<Long> affinityGroupIdList)
                     throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
 
         Account caller = UserContext.current().getCaller();
@@ -1966,13 +1977,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         }
 
         return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId,
-                diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard);
+                diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller,
+                requestedIps, defaultIps, keyboard, affinityGroupIdList);
     }
 
     @Override
     public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
             List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData,
-            String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException,
+ String sshKeyPair, Map<Long, IpAddresses> requestedIps,
+            IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
+            throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
+            StorageUnavailableException,
             ResourceAllocationException {
 
         Account caller = UserContext.current().getCaller();
@@ -2018,7 +2033,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
             isSecurityGroupEnabledNetworkUsed = true;
 
         } else {
-            // Verify that all the networks are Shared/Guest; can't create combination of SG enabled and disabled networks 
+            // Verify that all the networks are Shared/Guest; can't create combination of SG enabled and disabled networks
             for (Long networkId : networkIdList) {
                 NetworkVO network = _networkDao.findById(networkId);
 
@@ -2034,7 +2049,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
                     }
 
                     isSecurityGroupEnabledNetworkUsed = true;
-                }            
+                }
 
                 if (!(network.getTrafficType() == TrafficType.Guest && network.getGuestType() == Network.GuestType.Shared)) {
                     throw new InvalidParameterValueException("Can specify only Shared Guest networks when" +
@@ -2079,12 +2094,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         }
 
         return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId,
-                diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard);
+                diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller,
+                requestedIps, defaultIps, keyboard, affinityGroupIdList);
     }
 
     @Override
     public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, String hostName,
-            String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard)
+            String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
+            String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps,
+            String keyboard, List<Long> affinityGroupIdList)
                     throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
 
         Account caller = UserContext.current().getCaller();
@@ -2192,7 +2210,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
             }
         }
 
-        return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard);
+        return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId,
+                diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps,
+                keyboard, affinityGroupIdList);
     }
 
 
@@ -2205,7 +2225,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
 
     @DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
     protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId,
-            Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard)
+            Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, String userData,
+            String sshKeyPair, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps,
+            IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
                     throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException {
 
         _accountMgr.checkAccess(caller, null, true, owner);
@@ -2261,6 +2283,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
             }
         }
 
+        // check that the affinity groups exist
+        for (Long affinityGroupId : affinityGroupIdList) {
+            AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId);
+            if (ag == null) {
+                throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId);
+            }
+        }
+
         if (template.getHypervisorType() != null && template.getHypervisorType() != HypervisorType.BareMetal) {
             // check if we have available pools for vm deployment
             long availablePools = _storagePoolDao.countPoolsByStatus(StoragePoolStatus.Up);
@@ -2438,7 +2468,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
                     // * verify that there are no duplicates
                     if (hostNames.contains(hostName)) {
                         throw new InvalidParameterValueException("The vm with hostName " + hostName
-                                + " already exists in the network domain: " + ntwkDomain + "; network=" 
+                                + " already exists in the network domain: " + ntwkDomain + "; network="
                                 + _networkModel.getNetwork(ntwkId));
                     }
                 }
@@ -2510,7 +2540,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         List<String> computeTags = new ArrayList<String>();
         computeTags.add(offering.getHostTag());
 
-        List<String> rootDiskTags =	new ArrayList<String>();    	
+        List<String> rootDiskTags =	new ArrayList<String>();
         rootDiskTags.add(offering.getTags());
 
         if(isIso){
@@ -2552,6 +2582,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
 
         _securityGroupMgr.addInstanceToGroups(vm.getId(), securityGroupIdList);
 
+        _affinityGroupVMMapDao.updateMap(vm.getId(), affinityGroupIdList);
+
         return vm;
     }
 
@@ -2829,7 +2861,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
 
         try {
             VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
-            vmEntity.stop(new Long(userId).toString());            
+            vmEntity.stop(new Long(userId).toString());
         } catch (ResourceUnavailableException e) {
             throw new CloudRuntimeException(
                     "Unable to contact the agent to stop the virtual machine "
@@ -3044,7 +3076,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
 
         try {
             VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
-            status = vmEntity.destroy(new Long(userId).toString());    
+            status = vmEntity.destroy(new Long(userId).toString());
         } catch (CloudException e) {
             CloudRuntimeException ex = new CloudRuntimeException(
                     "Unable to destroy with specified vmId", e);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
index af22716..08c6e7c 100755
--- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -5,7 +5,7 @@
 // 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,
@@ -68,7 +68,9 @@ import com.cloud.deploy.DeployDestination;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.deploy.DeploymentPlanner;
 import com.cloud.deploy.DeploymentPlanner.ExcludeList;
+import com.cloud.deploy.DeploymentPlanningManager;
 import com.cloud.domain.dao.DomainDao;
+import com.cloud.exception.AffinityConflictException;
 import com.cloud.exception.AgentUnavailableException;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.ConnectionException;
@@ -226,8 +228,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 
 	@Inject
     protected ResourceManager _resourceMgr;
-    
-    @Inject 
+
+    @Inject
     protected VMSnapshotManager _vmSnapshotMgr = null;
     @Inject
     protected ClusterDetailsDao  _clusterDetailsDao;
@@ -239,6 +241,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Inject
     VolumeManager volumeMgr;
 
+    @Inject
+    DeploymentPlanningManager _dpMgr;
+
     Map<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>> _vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>>();
     protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
 
@@ -586,7 +591,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     ConcurrentOperationException, ResourceUnavailableException {
         return advanceStart(vm, params, caller, account, null);
     }
-    
+
     @Override
     public <T extends VMInstanceVO> T advanceStart(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account, DeploymentPlan planToDeploy)
             throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
@@ -695,17 +700,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 
                 VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, template, offering, account, params);
                 DeployDestination dest = null;
-                for (DeploymentPlanner planner : _planners) {
-                    if (planner.canHandle(vmProfile, plan, avoids)) {
-                        dest = planner.plan(vmProfile, plan, avoids);
-                    } else {
-                        continue;
-                    }
-                    if (dest != null) {
-                        avoids.addHost(dest.getHost().getId());
-                        journal.record("Deployment found ", vmProfile, dest);
-                        break;
-                    }
+                try {
+                    dest = _dpMgr.planDeployment(vmProfile, plan, avoids);
+                } catch (AffinityConflictException e2) {
+                    // TODO Auto-generated catch block
+                    e2.printStackTrace();
                 }
 
                 if (dest == null) {
@@ -739,7 +738,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                     if (s_logger.isDebugEnabled()) {
                         s_logger.debug("VM is being created in podId: " + vm.getPodIdToDeployIn());
                     }
-                    _networkMgr.prepare(vmProfile, dest, ctx); 
+                    _networkMgr.prepare(vmProfile, dest, ctx);
                     if (vm.getHypervisorType() != HypervisorType.BareMetal) {
                         this.volumeMgr.prepare(vmProfile, dest);
                     }
@@ -797,7 +796,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                             StopCommand cmd = new StopCommand(vm);
                             StopAnswer answer = (StopAnswer) _agentMgr.easySend(destHostId, cmd);
                             if (answer == null || !answer.getResult()) {
-                                s_logger.warn("Unable to stop " + vm + " due to " + (answer != null ? answer.getDetails() : "no answers")); 
+                                s_logger.warn("Unable to stop " + vm + " due to " + (answer != null ? answer.getDetails() : "no answers"));
                                 _haMgr.scheduleStop(vm, destHostId, WorkType.ForceStop);
                                 throw new ExecutionException("Unable to stop " + vm + " so we are unable to retry the start operation");
                             }
@@ -1144,7 +1143,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             s_logger.error("State transit with event: " + e + " failed due to: " + vm.getInstanceName() + " has active VM snapshots tasks");
             return false;
         }
-        
+
         State oldState = vm.getState();
         if (oldState == State.Starting) {
             if (e == Event.OperationSucceeded) {
@@ -1179,12 +1178,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             s_logger.debug("Unable to stop " + vm);
             return false;
         }
-        
+
         if (!_vmSnapshotMgr.deleteAllVMSnapshots(vm.getId(),null)){
             s_logger.debug("Unable to delete all snapshots for " + vm);
             return false;
         }
-        
+
         try {
             if (!stateTransitTo(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId())) {
                 s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm);
@@ -1559,7 +1558,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 
     @Override
     public boolean isVirtualMachineUpgradable(VirtualMachine vm, ServiceOffering offering) {
-        boolean isMachineUpgradable = true;    	
+        boolean isMachineUpgradable = true;
         for(HostAllocator allocator : _hostAllocators) {
             isMachineUpgradable = allocator.isVirtualMachineUpgradable(vm, offering);
             if(isMachineUpgradable)
@@ -1628,7 +1627,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         return new StopCommand(vmName);
     }
 
-    public Commands fullHostSync(final long hostId, StartupRoutingCommand startup) {  
+    public Commands fullHostSync(final long hostId, StartupRoutingCommand startup) {
         Commands commands = new Commands(OnError.Continue);
 
         Map<Long, AgentVmInfo> infos = convertToInfos(startup);
@@ -1637,7 +1636,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         s_logger.debug("Found " + vms.size() + " VMs for host " + hostId);
         for (VMInstanceVO vm : vms) {
             AgentVmInfo info = infos.remove(vm.getId());
-            
+
             // sync VM Snapshots related transient states
             List<VMSnapshotVO> vmSnapshotsInTrasientStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging,VMSnapshot.State.Reverting, VMSnapshot.State.Creating);
             if(vmSnapshotsInTrasientStates.size() > 1){
@@ -1649,11 +1648,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                     s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName());
                 }
             }
-            
+
             VMInstanceVO castedVm = null;
             if (info == null) {
                 info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);
-            } 
+            }
             castedVm = info.guru.findById(vm.getId());
 
             HypervisorGuru hvGuru = _hvGuruMgr.getGuru(castedVm.getHypervisorType());
@@ -1767,7 +1766,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         for (VMInstanceVO vm : set_vms) {
             AgentVmInfo info =  infos.remove(vm.getId());
             VMInstanceVO castedVm = null;
-            
+
             // sync VM Snapshots related transient states
             List<VMSnapshotVO> vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Creating,VMSnapshot.State.Reverting);
             if(vmSnapshotsInExpungingStates.size() > 0){
@@ -1785,9 +1784,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                     s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName());
                 }
             }
-            
-            if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting ))  
-            		||  (info != null && (info.state == State.Running && vm.getState() == State.Starting))) 
+
+            if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting ))
+            		||  (info != null && (info.state == State.Running && vm.getState() == State.Starting)))
             {
                 s_logger.info("Found vm " + vm.getInstanceName() + " in inconsistent state. " + vm.getState() + " on CS while " +  (info == null ? "Stopped" : "Running") + " on agent");
                 info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);
@@ -1925,7 +1924,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         return map;
     }
 
-    protected Map<Long, AgentVmInfo> convertToInfos(StartupRoutingCommand cmd) { 
+    protected Map<Long, AgentVmInfo> convertToInfos(StartupRoutingCommand cmd) {
         final Map<String, VmState> states = cmd.getVmStates();
         final HashMap<Long, AgentVmInfo> map = new HashMap<Long, AgentVmInfo>();
         if (states == null) {
@@ -1989,7 +1988,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
      * compareState does as its name suggests and compares the states between
      * management server and agent. It returns whether something should be
      * cleaned up
-     * 
+     *
      */
     protected Command compareState(long hostId, VMInstanceVO vm, final AgentVmInfo info, final boolean fullSync, boolean trackExternalChange) {
         State agentState = info.state;
@@ -2192,7 +2191,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         List<NicVO> nics = _nicsDao.listByVmId(profile.getId());
         for (NicVO nic : nics) {
             Network network = _networkModel.getNetwork(nic.getNetworkId());
-            NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), null, 
+            NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), null,
                     _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(profile.getHypervisorType(), network));
             profile.addNic(nicProfile);
         }
@@ -2319,7 +2318,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                 s_logger.fatal("The Cluster VM sync process failed for cluster id " + clusterId + " with ", e);
             }
         }
-        else { // for others KVM and VMWare 
+        else { // for others KVM and VMWare
             StartupRoutingCommand startup = (StartupRoutingCommand) cmd;
             Commands commands = fullHostSync(agentId, startup);
 
@@ -2492,7 +2491,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     }
 
     @Override
-    public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException, 
+    public NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile requested) throws ConcurrentOperationException,
     ResourceUnavailableException, InsufficientCapacityException {
 
         s_logger.debug("Adding vm " + vm + " to network " + network + "; requested nic profile " + requested);
@@ -2502,14 +2501,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         } else {
             vmVO = _vmDao.findById(vm.getId());
         }
-        ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), 
+        ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM),
                 _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM));
 
-        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vmVO, null, 
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vmVO, null,
                 null, null, null);
 
         DataCenter dc = _configMgr.getZone(network.getDataCenterId());
-        Host host = _hostDao.findById(vm.getHostId()); 
+        Host host = _hostDao.findById(vm.getHostId());
         DeployDestination dest = new DeployDestination(dc, null, null, host);
 
         //check vm state
@@ -2557,14 +2556,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     public boolean removeNicFromVm(VirtualMachine vm, NicVO nic) throws ConcurrentOperationException, ResourceUnavailableException {
         VMInstanceVO vmVO = _vmDao.findById(vm.getId());
         NetworkVO network = _networkDao.findById(nic.getNetworkId());
-        ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), 
+        ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM),
                 _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM));
 
-        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vmVO, null, 
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vmVO, null,
                 null, null, null);
 
         DataCenter dc = _configMgr.getZone(network.getDataCenterId());
-        Host host = _hostDao.findById(vm.getHostId()); 
+        Host host = _hostDao.findById(vm.getHostId());
         DeployDestination dest = new DeployDestination(dc, null, null, host);
         VirtualMachineGuru<VMInstanceVO> vmGuru = getVmGuru(vmVO);
         HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vmProfile.getVirtualMachine().getHypervisorType());
@@ -2576,9 +2575,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + ", nic is default.");
         }
 
-        NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), 
-                _networkModel.getNetworkRate(network.getId(), vm.getId()), 
-                _networkModel.isSecurityGroupSupportedInNetwork(network), 
+        NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(),
+                _networkModel.getNetworkRate(network.getId(), vm.getId()),
+                _networkModel.isSecurityGroupSupportedInNetwork(network),
                 _networkModel.getNetworkTag(vmProfile.getVirtualMachine().getHypervisorType(), network));
 
         //1) Unplug the nic
@@ -2611,14 +2610,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Override
     public boolean removeVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException {
         VMInstanceVO vmVO = _vmDao.findById(vm.getId());
-        ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), 
+        ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM),
                 _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM));
 
-        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vmVO, null, 
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vmVO, null,
                 null, null, null);
 
         DataCenter dc = _configMgr.getZone(network.getDataCenterId());
-        Host host = _hostDao.findById(vm.getHostId()); 
+        Host host = _hostDao.findById(vm.getHostId());
         DeployDestination dest = new DeployDestination(dc, null, null, host);
         VirtualMachineGuru<VMInstanceVO> vmGuru = getVmGuru(vmVO);
         HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vmProfile.getVirtualMachine().getHypervisorType());
@@ -2643,9 +2642,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + ", nic is default.");
         }
 
-        NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), 
-                _networkModel.getNetworkRate(network.getId(), vm.getId()), 
-                _networkModel.isSecurityGroupSupportedInNetwork(network), 
+        NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(),
+                _networkModel.getNetworkRate(network.getId(), vm.getId()),
+                _networkModel.isSecurityGroupSupportedInNetwork(network),
                 _networkModel.getNetworkTag(vmProfile.getVirtualMachine().getHypervisorType(), network));
 
         //1) Unplug the nic

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java
index 994f225..f6c87cb 100644
--- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java
+++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java
@@ -1,6 +1,5 @@
 package org.apache.cloudstack.affinity;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -13,36 +12,34 @@ import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
 import org.apache.log4j.Logger;
 
 
-import com.cloud.api.query.vo.SecurityGroupJoinVO;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceInUseException;
-import com.cloud.network.PhysicalNetwork;
-import com.cloud.network.dao.PhysicalNetworkVO;
-import com.cloud.network.security.SecurityGroupManager;
-import com.cloud.network.security.SecurityGroupRuleVO;
-import com.cloud.network.security.SecurityGroupVMMapVO;
-import com.cloud.network.security.SecurityGroupVO;
+import com.cloud.network.security.SecurityGroup;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
 import com.cloud.user.UserContext;
+import com.cloud.uservm.UserVm;
 import com.cloud.utils.Pair;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Filter;
-import com.cloud.utils.db.JoinBuilder.JoinType;
 import com.cloud.utils.db.JoinBuilder;
 import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.Transaction;
+import com.cloud.utils.fsm.StateListener;
 import com.cloud.vm.UserVmVO;
-import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.Event;
+import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.dao.UserVmDao;
 
 @Local(value = { AffinityGroupService.class })
-public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager {
+public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager,
+        StateListener<State, VirtualMachine.Event, VirtualMachine> {
 
     public static final Logger s_logger = Logger.getLogger(AffinityGroupServiceImpl.class);
     private String _name;
@@ -221,4 +218,56 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
         return _affinityGroupDao.findById(groupId);
     }
 
+    @Override
+    public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo,
+            boolean status, Object opaque) {
+        return true;
+    }
+
+    @Override
+    public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo,
+            boolean status, Object opaque) {
+        if (!status) {
+            return false;
+        }
+        if ((newState == State.Expunging)) {
+            // cleanup all affinity groups associated to the Expunged VM
+            SearchCriteria<AffinityGroupVMMapVO> sc = _affinityGroupVMMapDao.createSearchCriteria();
+            sc.addAnd("instanceId", SearchCriteria.Op.EQ, vo.getId());
+            _affinityGroupVMMapDao.expunge(sc);
+        }
+        return true;
+    }
+
+    @Override
+    public UserVm updateVMAffinityGroups(Long vmId, List<Long> affinityGroupIds) {
+        // Verify input parameters
+        UserVmVO vmInstance = _userVmDao.findById(vmId);
+        if (vmInstance == null) {
+            throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId);
+        }
+
+        // Check that the VM is stopped
+        if (!vmInstance.getState().equals(State.Stopped)) {
+            s_logger.warn("Unable to update affinity groups of the virtual machine " + vmInstance.toString()
+                    + " in state " + vmInstance.getState());
+            throw new InvalidParameterValueException("Unable update affinity groups of the virtual machine "
+                    + vmInstance.toString() + " " + "in state " + vmInstance.getState()
+                    + "; make sure the virtual machine is stopped and not in an error state before updating.");
+        }
+
+        // check that the affinity groups exist
+        for (Long affinityGroupId : affinityGroupIds) {
+            AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId);
+            if (ag == null) {
+                throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId);
+            }
+        }
+        _affinityGroupVMMapDao.updateMap(vmId, affinityGroupIds);
+
+        // APIResponseHelper will pull out the updated affinitygroups.
+        return vmInstance;
+
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java b/server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
new file mode 100644
index 0000000..93bd358
--- /dev/null
+++ b/server/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
@@ -0,0 +1,66 @@
+package org.apache.cloudstack.affinity;
+
+import java.util.List;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
+import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
+import org.apache.log4j.Logger;
+
+import com.cloud.deploy.DeploymentPlan;
+import com.cloud.deploy.DeploymentPlanner.ExcludeList;
+import com.cloud.exception.AffinityConflictException;
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
+
+@Local(value = AffinityGroupProcessor.class)
+public class HostAntiAffinityProcessor extends AdapterBase implements AffinityGroupProcessor {
+
+    private static final Logger s_logger = Logger.getLogger(HostAntiAffinityProcessor.class);
+    @Inject
+    protected UserVmDao _vmDao;
+    @Inject
+    protected VMInstanceDao _vmInstanceDao;
+    @Inject
+    protected AffinityGroupDao _affinityGroupDao;
+    @Inject
+    protected AffinityGroupVMMapDao _affinityGroupVMMapDao;
+
+    @Override
+    public void process(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan,
+            ExcludeList avoid)
+            throws AffinityConflictException {
+        VirtualMachine vm = vmProfile.getVirtualMachine();
+        AffinityGroupVMMapVO vmGroupMapping = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType());
+
+        if (vmGroupMapping != null) {
+            AffinityGroupVO group = _affinityGroupDao.findById(vmGroupMapping.getAffinityGroupId());
+
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Processing affinity group " + group.getName() + " for VM Id: " + vm.getId());
+            }
+
+            List<Long> groupVMIds = _affinityGroupVMMapDao.listVmIdsByAffinityGroup(group.getId());
+
+            for (Long groupVMId : groupVMIds) {
+                VMInstanceVO groupVM = _vmInstanceDao.findById(groupVMId);
+                if (groupVM != null && !groupVM.isRemoved() && groupVM.getHostId() != null) {
+                    avoid.addHost(groupVM.getHostId());
+                }
+            }
+        }
+
+    }
+
+    @Override
+    public String getType() {
+        return "HostAntiAffinity";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fe2a8687/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java
index 9841de4..a98ae0f 100644
--- a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java
+++ b/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java
@@ -40,4 +40,8 @@ public interface AffinityGroupVMMapDao extends GenericDao<AffinityGroupVMMapVO,
     long countAffinityGroupsForVm(long instanceId);
 
     int deleteVM(long instanceId);
+
+    AffinityGroupVMMapVO findByVmIdType(long instanceId, String type);
+
+    void updateMap(Long vmId, List<Long> affinityGroupIds);
 }