cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r...@apache.org
Subject [01/11] git commit: updated refs/heads/master to 7e902cd
Date Thu, 03 Dec 2015 19:43:30 GMT
Repository: cloudstack
Updated Branches:
  refs/heads/master 3b511a139 -> 7e902cd50


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c76d3171/server/test/org/apache/cloudstack/affinity/AffinityGroupServiceImplTest.java
----------------------------------------------------------------------
diff --git a/server/test/org/apache/cloudstack/affinity/AffinityGroupServiceImplTest.java b/server/test/org/apache/cloudstack/affinity/AffinityGroupServiceImplTest.java
new file mode 100644
index 0000000..4484247
--- /dev/null
+++ b/server/test/org/apache/cloudstack/affinity/AffinityGroupServiceImplTest.java
@@ -0,0 +1,358 @@
+// 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.affinity;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import com.cloud.utils.db.EntityManager;
+import com.cloud.event.ActionEventUtils;
+import com.cloud.user.User;
+
+import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
+import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
+import org.apache.cloudstack.test.utils.SpringUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.FilterType;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.core.type.filter.TypeFilter;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
+import org.apache.cloudstack.api.command.user.affinitygroup.CreateAffinityGroupCmd;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.messagebus.MessageBus;
+
+import com.cloud.dc.dao.DedicatedResourceDao;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.event.EventVO;
+import com.cloud.event.dao.EventDao;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceInUseException;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountService;
+import com.cloud.user.AccountVO;
+import com.cloud.user.DomainManager;
+import com.cloud.user.UserVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.user.dao.UserDao;
+import com.cloud.utils.component.ComponentContext;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.projects.dao.ProjectDao;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
+public class AffinityGroupServiceImplTest {
+
+    @Inject
+    AffinityGroupServiceImpl _affinityService;
+
+    @Inject
+    AccountManager _acctMgr;
+
+    @Inject
+    AffinityGroupProcessor _processor;
+
+    @Inject
+    AffinityGroupDao _groupDao;
+
+    @Inject
+    UserVmDao _vmDao;
+
+    @Inject
+    AffinityGroupVMMapDao _affinityGroupVMMapDao;
+
+    @Inject
+    AffinityGroupDao _affinityGroupDao;
+
+    @Inject
+    ActionEventUtils _eventUtils;
+
+    @Inject
+    AccountDao _accountDao;
+
+    @Inject
+    ProjectDao _projectDao;
+
+    @Inject
+    EventDao _eventDao;
+
+    @Inject
+    DedicatedResourceDao _dedicatedDao;
+
+    private static final long DOMAIN_ID = 5L;
+    private static final long PROJECT_ID = 10L;
+    private static final String ACCOUNT_NAME = "user";
+    private static final String AFFINITY_GROUP_NAME = "group1";
+
+    private AccountVO acct;
+
+    @BeforeClass
+    public static void setUpClass() throws ConfigurationException {
+    }
+
+    @Before
+    public void setUp() {
+        ComponentContext.initComponentsLifeCycle();
+        acct = new AccountVO(200L);
+        acct.setType(Account.ACCOUNT_TYPE_NORMAL);
+        acct.setAccountName(ACCOUNT_NAME);
+        acct.setDomainId(DOMAIN_ID);
+
+        UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
+
+        CallContext.register(user, acct);
+
+        when(_processor.getType()).thenReturn("mock");
+        when(_accountDao.findByIdIncludingRemoved(0L)).thenReturn(acct);
+
+        List<AffinityGroupProcessor> affinityProcessors = new ArrayList<AffinityGroupProcessor>();
+        affinityProcessors.add(_processor);
+        _affinityService.setAffinityGroupProcessors(affinityProcessors);
+
+        AffinityGroupVO group = new AffinityGroupVO(AFFINITY_GROUP_NAME, "mock", "mock group", DOMAIN_ID, 200L, ControlledEntity.ACLType.Account);
+        Mockito.when(_affinityGroupDao.persist(Matchers.any(AffinityGroupVO.class))).thenReturn(group);
+        Mockito.when(_affinityGroupDao.findById(Matchers.anyLong())).thenReturn(group);
+        Mockito.when(_affinityGroupDao.findByAccountAndName(Matchers.anyLong(), Matchers.anyString())).thenReturn(group);
+        Mockito.when(_affinityGroupDao.lockRow(Matchers.anyLong(), anyBoolean())).thenReturn(group);
+        Mockito.when(_affinityGroupDao.expunge(Matchers.anyLong())).thenReturn(true);
+        Mockito.when(_eventDao.persist(Matchers.any(EventVO.class))).thenReturn(new EventVO());
+    }
+
+    @After
+    public void tearDown() {
+        CallContext.unregister();
+    }
+
+    @Test
+    public void createAffinityGroupFromCmdTest() {
+        when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
+        when(_groupDao.isNameInUse(anyLong(), anyLong(), eq(AFFINITY_GROUP_NAME))).thenReturn(false);
+        CreateAffinityGroupCmd mockCreateAffinityGroupCmd = Mockito.mock(CreateAffinityGroupCmd.class);
+        when(mockCreateAffinityGroupCmd.getProjectId()).thenReturn(PROJECT_ID);
+        when(mockCreateAffinityGroupCmd.getAffinityGroupName()).thenReturn(AFFINITY_GROUP_NAME);
+        when(mockCreateAffinityGroupCmd.getAffinityGroupType()).thenReturn("mock");
+        when(mockCreateAffinityGroupCmd.getDescription()).thenReturn("affinity group one");
+        AffinityGroup group = _affinityService.createAffinityGroup(mockCreateAffinityGroupCmd);
+        assertNotNull("Affinity group 'group1' of type 'mock' failed to create ", group);
+    }
+
+    @Test
+    public void createAffinityGroupTest() {
+        when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
+        when(_groupDao.isNameInUse(anyLong(), anyLong(), eq(AFFINITY_GROUP_NAME))).thenReturn(false);
+        AffinityGroup group = _affinityService.createAffinityGroup(ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME, "mock", "affinity group one");
+        assertNotNull("Affinity group 'group1' of type 'mock' failed to create ", group);
+
+    }
+
+    @Test
+    public void shouldDeleteDomainLevelAffinityGroup() {
+        AffinityGroupVO mockGroup = Mockito.mock(AffinityGroupVO.class);
+        when(mockGroup.getId()).thenReturn(2L);
+        when(_affinityGroupDao.findById(Matchers.anyLong())).thenReturn(mockGroup);
+        _affinityService.deleteAffinityGroup(2L, null, null, DOMAIN_ID, null);
+        Mockito.verify(_affinityGroupDao).expunge(2L);
+    }
+
+    @Test
+    public void shouldDeleteAffintyGroupById() {
+        AffinityGroupVO mockGroup = Mockito.mock(AffinityGroupVO.class);
+        when(mockGroup.getId()).thenReturn(1L);
+        when(_affinityGroupDao.findById(Matchers.anyLong())).thenReturn(mockGroup);
+        _affinityService.deleteAffinityGroup(1L, ACCOUNT_NAME, null, DOMAIN_ID, null);
+        Mockito.verify(_affinityGroupDao).expunge(1L);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void invalidAffinityTypeTest() {
+        when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
+        _affinityService.createAffinityGroup(ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME, "invalid", "affinity group one");
+
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void uniqueAffinityNameTest() {
+        when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
+        when(_groupDao.isNameInUse(anyLong(), anyLong(), eq(AFFINITY_GROUP_NAME))).thenReturn(true);
+        _affinityService.createAffinityGroup(ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME, "mock", "affinity group two");
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void deleteAffinityGroupInvalidIdTest() throws ResourceInUseException {
+        when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
+        when(_groupDao.findById(20L)).thenReturn(null);
+        _affinityService.deleteAffinityGroup(20L, ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void deleteAffinityGroupInvalidIdName() throws ResourceInUseException {
+        when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
+        when(_acctMgr.finalyzeAccountId(ACCOUNT_NAME, DOMAIN_ID, null, true)).thenReturn(200L);
+        when(_groupDao.findByAccountAndName(200L, AFFINITY_GROUP_NAME)).thenReturn(null);
+        _affinityService.deleteAffinityGroup(null, ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void deleteAffinityGroupNullIdName() throws ResourceInUseException {
+        when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
+        _affinityService.deleteAffinityGroup(null, ACCOUNT_NAME, null, DOMAIN_ID, null);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void updateAffinityGroupVMRunning() throws ResourceInUseException {
+        when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
+        UserVmVO vm = new UserVmVO(10L, "test", "test", 101L, HypervisorType.Any, 21L, false, false, DOMAIN_ID, 200L, 1, 5L, "", "test", 1L);
+        vm.setState(VirtualMachine.State.Running);
+        when(_vmDao.findById(10L)).thenReturn(vm);
+
+        List<Long> affinityGroupIds = new ArrayList<Long>();
+        affinityGroupIds.add(20L);
+
+        _affinityService.updateVMAffinityGroups(10L, affinityGroupIds);
+    }
+
+    @Configuration
+    @ComponentScan(basePackageClasses = {AffinityGroupServiceImpl.class, ActionEventUtils.class}, includeFilters = {@Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)}, useDefaultFilters = false)
+    public static class TestConfiguration extends SpringUtils.CloudStackTestConfiguration {
+
+        @Bean
+        public AccountDao accountDao() {
+            return Mockito.mock(AccountDao.class);
+        }
+
+        @Bean
+        public ProjectDao projectDao() {
+            return Mockito.mock(ProjectDao.class);
+        }
+
+        @Bean
+        public AccountService accountService() {
+            return Mockito.mock(AccountService.class);
+        }
+
+        @Bean
+        public AffinityGroupProcessor affinityGroupProcessor() {
+            return Mockito.mock(AffinityGroupProcessor.class);
+        }
+
+        @Bean
+        public AffinityGroupDao affinityGroupDao() {
+            return Mockito.mock(AffinityGroupDao.class);
+        }
+
+        @Bean
+        public AffinityGroupVMMapDao affinityGroupVMMapDao() {
+            return Mockito.mock(AffinityGroupVMMapDao.class);
+        }
+
+        @Bean
+        public DedicatedResourceDao dedicatedResourceDao() {
+            return Mockito.mock(DedicatedResourceDao.class);
+        }
+
+        @Bean
+        public AccountManager accountManager() {
+            return Mockito.mock(AccountManager.class);
+        }
+
+        @Bean
+        public DomainManager domainManager() {
+            return Mockito.mock(DomainManager.class);
+        }
+
+        @Bean
+        public EventDao eventDao() {
+            return Mockito.mock(EventDao.class);
+        }
+
+        @Bean
+        public UserVmDao userVMDao() {
+            return Mockito.mock(UserVmDao.class);
+        }
+
+        @Bean
+        public UserDao userDao() {
+            return Mockito.mock(UserDao.class);
+        }
+
+        @Bean
+        public AffinityGroupDomainMapDao affinityGroupDomainMapDao() {
+            return Mockito.mock(AffinityGroupDomainMapDao.class);
+        }
+
+        @Bean
+        public EntityManager entityManager() {
+            return Mockito.mock(EntityManager.class);
+        }
+
+        @Bean
+        public DomainDao domainDao() {
+            return Mockito.mock(DomainDao.class);
+        }
+
+        @Bean
+        public MessageBus messageBus() {
+            return Mockito.mock(MessageBus.class);
+        }
+
+        @Bean
+        public ConfigurationDao configDao() {
+            return Mockito.mock(ConfigurationDao.class);
+        }
+
+        public static class Library implements TypeFilter {
+
+            @Override
+            public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException {
+                ComponentScan cs = TestConfiguration.class.getAnnotation(ComponentScan.class);
+                return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c76d3171/setup/db/db/schema-460to461.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-460to461.sql b/setup/db/db/schema-460to461.sql
index e42d0b2..4e07344 100644
--- a/setup/db/db/schema-460to461.sql
+++ b/setup/db/db/schema-460to461.sql
@@ -18,3 +18,35 @@
 --;
 -- Schema upgrade from 4.6.0 to 4.6.1;
 --;
+DROP VIEW IF EXISTS `cloud`.`affinity_group_view`;
+CREATE VIEW `affinity_group_view`
+	AS SELECT
+	   `affinity_group`.`id` AS `id`,
+	   `affinity_group`.`name` AS `name`,
+	   `affinity_group`.`type` AS `type`,
+	   `affinity_group`.`description` AS `description`,
+	   `affinity_group`.`uuid` AS `uuid`,
+	   `affinity_group`.`acl_type` AS `acl_type`,
+	   `account`.`id` AS `account_id`,
+	   `account`.`uuid` AS `account_uuid`,
+	   `account`.`account_name` AS `account_name`,
+	   `account`.`type` AS `account_type`,
+	   `domain`.`id` AS `domain_id`,
+	   `domain`.`uuid` AS `domain_uuid`,
+	   `domain`.`name` AS `domain_name`,
+	   `domain`.`path` AS `domain_path`,
+	   `projects`.`id` AS `project_id`,
+	   `projects`.`uuid` AS `project_uuid`,
+	   `projects`.`name` AS `project_name`,
+	   `vm_instance`.`id` AS `vm_id`,
+	   `vm_instance`.`uuid` AS `vm_uuid`,
+	   `vm_instance`.`name` AS `vm_name`,
+	   `vm_instance`.`state` AS `vm_state`,
+	   `user_vm`.`display_name` AS `vm_display_name`
+FROM `affinity_group`
+	JOIN `account` ON`affinity_group`.`account_id` = `account`.`id`
+	JOIN `domain` ON`affinity_group`.`domain_id` = `domain`.`id`
+	LEFT JOIN `projects` ON`projects`.`project_account_id` = `account`.`id`
+	LEFT JOIN `affinity_group_vm_map` ON`affinity_group`.`id` = `affinity_group_vm_map`.`affinity_group_id`
+	LEFT JOIN `vm_instance` ON`vm_instance`.`id` = `affinity_group_vm_map`.`instance_id`
+	LEFT JOIN `user_vm` ON`user_vm`.`id` = `vm_instance`.`id`;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c76d3171/test/integration/component/test_affinity_groups_projects.py
----------------------------------------------------------------------
diff --git a/test/integration/component/test_affinity_groups_projects.py b/test/integration/component/test_affinity_groups_projects.py
new file mode 100644
index 0000000..ffd10ef
--- /dev/null
+++ b/test/integration/component/test_affinity_groups_projects.py
@@ -0,0 +1,1083 @@
+#!/usr/bin/env python
+#  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.
+from marvin.cloudstackTestCase import cloudstackTestCase, unittest
+from marvin.cloudstackAPI import deleteAffinityGroup
+from marvin.lib.utils import (cleanup_resources,
+                        random_gen)
+from marvin.lib.base import (Account,
+                        Project,
+                        ServiceOffering,
+                        VirtualMachine,
+                        AffinityGroup,
+                        Domain)
+from marvin.lib.common import (get_zone,
+                         get_domain,
+                         get_template,
+                         list_hosts,
+                         list_virtual_machines,
+                         wait_for_cleanup)
+from nose.plugins.attrib import attr
+
+class Services:
+    """Test Account Services
+    """
+
+    def __init__(self):
+       self.services = {
+          "domain": {
+             "name": "NonRootDomain"
+          },
+          "domain_admin_account": {
+             "email": "newtest@test.com",
+             "firstname": "Test",
+             "lastname": "User",
+             "username": "doadmintest",
+             "password": "password"
+          },
+          "account": {
+             "email": "newtest@test.com",
+             "firstname": "Test",
+             "lastname": "User",
+             "username": "acc",
+             "password": "password"
+          },
+          "account_not_in_project": {
+             "email": "newtest@test.com",
+             "firstname": "Test",
+             "lastname": "User",
+             "username": "account_not_in_project",
+             "password": "password"
+          },
+          "project": {
+             "name": "Project",
+             "displaytext": "Project"
+          },
+          "project2": {
+             "name": "Project2",
+             "displaytext": "Project2"
+          },
+          "service_offering": {
+             "name": "Tiny Instance",
+             "displaytext": "Tiny Instance",
+             "cpunumber": 1,
+             "cpuspeed": 100,
+             "memory": 64
+          },
+          "ostype": 'CentOS 5.3 (64-bit)',
+          "host_anti_affinity": {
+                "name": "",
+                "type": "host anti-affinity"
+             },
+          "virtual_machine" : {
+             "hypervisor" : "KVM"
+          }
+       }
+
+class TestCreateAffinityGroup(cloudstackTestCase):
+    """
+    Test various scenarios for Create Affinity Group API for projects
+    """
+
+    @classmethod
+    def setUpClass(cls):
+       cls.testClient = super(TestCreateAffinityGroup, cls).getClsTestClient()
+       cls.api_client = cls.testClient.getApiClient()
+       cls.services = Services().services
+
+       #Get Zone, Domain and templates
+       cls.rootdomain = get_domain(cls.api_client)
+       cls.domain = Domain.create(cls.api_client, cls.services["domain"])
+
+       cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+       cls.template = get_template(
+          cls.api_client,
+          cls.zone.id,
+          cls.services["ostype"]
+       )
+       
+       cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+       cls.services["template"] = cls.template.id
+       cls.services["zoneid"] = cls.zone.id
+       
+       cls.domain_admin_account = Account.create(
+          cls.api_client,
+          cls.services["domain_admin_account"],
+          domainid=cls.domain.id,
+          admin=True
+       )
+
+       cls.domain_api_client = cls.testClient.getUserApiClient(cls.domain_admin_account.name, cls.domain.name, 2)
+
+       cls.account = Account.create(
+          cls.api_client,
+          cls.services["account"],
+          domainid=cls.domain.id
+       )       
+
+       cls.account_api_client = cls.testClient.getUserApiClient(cls.account.name, cls.domain.name, 0)
+
+       cls.account_not_in_project = Account.create(
+          cls.api_client,
+          cls.services["account_not_in_project"],
+          domainid=cls.domain.id
+       )
+
+       cls.account_not_in_project_api_client = cls.testClient.getUserApiClient(cls.account_not_in_project.name, cls.domain.name, 0)
+
+       cls.project = Project.create(
+          cls.api_client,
+          cls.services["project"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+       
+       cls.project2 = Project.create(
+          cls.api_client,
+          cls.services["project2"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+
+       cls.debug("Created project with ID: %s" % cls.project.id)
+       cls.debug("Created project2 with ID: %s" % cls.project2.id)
+
+       # Add user to the project
+       cls.project.addAccount(
+          cls.api_client,
+          cls.account.name
+       )
+
+       cls.service_offering = ServiceOffering.create(
+          cls.api_client,
+          cls.services["service_offering"],
+          domainid=cls.account.domainid
+       )
+       
+       cls._cleanup = []
+       return
+
+    def setUp(self):
+       self.apiclient = self.testClient.getApiClient()
+       self.dbclient = self.testClient.getDbConnection()
+       self.cleanup = []
+
+    def tearDown(self):
+       try:
+#            #Clean up, terminate the created instance, volumes and snapshots
+          cleanup_resources(self.apiclient, self.cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+       return
+
+    @classmethod
+    def tearDownClass(cls):
+       try:
+          #Clean up, terminate the created templates
+          cls.domain.delete(cls.api_client, cleanup=True)
+          cleanup_resources(cls.api_client, cls._cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+
+    def create_aff_grp(self, api_client=None, aff_grp=None, aff_grp_name=None, projectid=None):
+
+       if not api_client:
+          api_client = self.api_client
+       if aff_grp is None:
+          aff_grp = self.services["host_anti_affinity"]
+       if aff_grp_name is None:
+          aff_grp["name"] = "aff_grp_" + random_gen(size=6)
+       else:
+          aff_grp["name"] = aff_grp_name
+       if projectid is None:
+          projectid = self.project.id
+       try:
+          return AffinityGroup.create(api_client, aff_grp, None, None, projectid)
+       except Exception as e:
+          raise Exception("Error: Creation of Affinity Group failed : %s" % e)
+   
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_01_admin_create_aff_grp_for_project(self):
+       """
+       Test create affinity group as admin in project
+       @return:
+       """
+       aff_grp = self.create_aff_grp()
+       self.debug("Created Affinity Group: %s" % aff_grp.name)
+       list_aff_grps = AffinityGroup.list(self.api_client, id=aff_grp.id)
+       self.assert_(isinstance(list_aff_grps, list) and len(list_aff_grps) > 0)
+       self.assert_(list_aff_grps[0].id == aff_grp.id)
+       self.assert_(list_aff_grps[0].projectid == self.project.id)
+       self.cleanup.append(aff_grp)
+ 
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_02_doadmin_create_aff_grp_for_project(self):
+        """
+        Test create affinity group as domain admin for projects
+        @return:
+        """
+        aff_grp = self.create_aff_grp(api_client=self.domain_api_client)
+        list_aff_grps = AffinityGroup.list(self.domain_api_client, id=aff_grp.id)
+        self.assert_(isinstance(list_aff_grps, list) and len(list_aff_grps) > 0)
+        self.assert_(list_aff_grps[0].id == aff_grp.id)
+        self.assert_(list_aff_grps[0].projectid == self.project.id)
+        self.cleanup.append(aff_grp)
+ 
+    @attr(tags=["vogxn", "simulator", "basic", "advanced"], required_hardware="false")
+    def test_03_user_create_aff_grp_for_project(self):
+        """
+        Test create affinity group as user for projects
+        @return:
+        """
+        aff_grp = self.create_aff_grp(api_client=self.account_api_client)
+        list_aff_grps = AffinityGroup.list(self.api_client, id=aff_grp.id)
+        self.assert_(isinstance(list_aff_grps, list) and len(list_aff_grps) > 0)
+        self.assert_(list_aff_grps[0].id == aff_grp.id)
+        self.assert_(list_aff_grps[0].projectid == self.project.id)
+        self.cleanup.append(aff_grp)
+  
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_4_user_create_aff_grp_existing_name_for_project(self):
+        """
+        Test create affinity group that exists (same name) for projects
+        @return:
+        """
+        
+        failed_aff_grp = None
+        aff_grp = self.create_aff_grp(api_client=self.account_api_client)
+        with self.assertRaises(Exception):
+           failed_aff_grp = self.create_aff_grp(api_client=self.account_api_client,aff_grp_name = aff_grp.name)
+        
+        if failed_aff_grp:
+            self.cleanup.append(failed_aff_grp)
+        self.cleanup.append(aff_grp)
+
+class TestListAffinityGroups(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+       cls.testClient = super(TestListAffinityGroups, cls).getClsTestClient()
+       cls.api_client = cls.testClient.getApiClient()
+       cls.services = Services().services
+
+       #Get Zone, Domain and templates
+       cls.rootdomain = get_domain(cls.api_client)
+       cls.domain = Domain.create(cls.api_client, cls.services["domain"])
+
+       cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+       cls.template = get_template(
+          cls.api_client,
+          cls.zone.id,
+          cls.services["ostype"]
+       )
+       
+       cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+       cls.services["template"] = cls.template.id
+       cls.services["zoneid"] = cls.zone.id
+       
+       cls.domain_admin_account = Account.create(
+          cls.api_client,
+          cls.services["domain_admin_account"],
+          domainid=cls.domain.id,
+          admin=True
+       )
+
+       cls.domain_api_client = cls.testClient.getUserApiClient(cls.domain_admin_account.name, cls.domain.name, 2)
+
+       cls.account = Account.create(
+          cls.api_client,
+          cls.services["account"],
+          domainid=cls.domain.id
+       )       
+
+       cls.account_api_client = cls.testClient.getUserApiClient(cls.account.name, cls.domain.name, 0)
+
+       cls.account_not_in_project = Account.create(
+          cls.api_client,
+          cls.services["account_not_in_project"],
+          domainid=cls.domain.id
+       )
+
+       cls.account_not_in_project_api_client = cls.testClient.getUserApiClient(cls.account_not_in_project.name, cls.domain.name, 0)
+
+       cls.project = Project.create(
+          cls.api_client,
+          cls.services["project"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+       
+       cls.project2 = Project.create(
+          cls.api_client,
+          cls.services["project2"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+
+       cls.debug("Created project with ID: %s" % cls.project.id)
+       cls.debug("Created project2 with ID: %s" % cls.project2.id)
+
+       # Add user to the project
+       cls.project.addAccount(
+          cls.api_client,
+          cls.account.name
+       )
+
+       cls.service_offering = ServiceOffering.create(
+          cls.api_client,
+          cls.services["service_offering"],
+          domainid=cls.account.domainid
+       )
+       
+       cls._cleanup = []
+       return
+
+    def setUp(self):
+       self.apiclient = self.testClient.getApiClient()
+       self.dbclient = self.testClient.getDbConnection()
+       self.cleanup = []
+
+    def tearDown(self):
+       try:
+#            #Clean up, terminate the created instance, volumes and snapshots
+          cleanup_resources(self.api_client, self.cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+       return
+
+    @classmethod
+    def tearDownClass(cls):
+       try:
+          cls.domain.delete(cls.api_client, cleanup=True)
+          cleanup_resources(cls.api_client, cls._cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+
+    def create_aff_grp(self, api_client=None, aff_grp=None, aff_grp_name=None, projectid=None):
+
+       if not api_client:
+          api_client = self.api_client
+       if aff_grp is None:
+          aff_grp = self.services["host_anti_affinity"]
+       if aff_grp_name is None:
+          aff_grp["name"] = "aff_grp_" + random_gen(size=6)
+       else:
+          aff_grp["name"] = aff_grp_name
+       if projectid is None:
+          projectid = self.project.id
+       try:
+          return AffinityGroup.create(api_client, aff_grp, None, None, projectid)
+       except Exception as e:
+          raise Exception("Error: Creation of Affinity Group failed : %s" % e)
+
+    def create_vm_in_aff_grps(self, api_client=None, ag_list=[], projectid=None):
+        self.debug('Creating VM in AffinityGroups=%s' % ag_list)
+
+        if api_client is None:
+           api_client = self.api_client
+        if projectid is None:
+           projectid = self.project.id
+
+        vm = VirtualMachine.create(
+                api_client,
+                self.services["virtual_machine"],
+                projectid=projectid,
+                templateid=self.template.id,
+                serviceofferingid=self.service_offering.id,
+                affinitygroupnames=ag_list
+              )
+        self.debug('Created VM=%s in Affinity Group=%s' % (vm.id, tuple(ag_list)))
+
+        list_vm = list_virtual_machines(api_client, id=vm.id, projectid=projectid)
+        self.assertEqual(isinstance(list_vm, list), True,"Check list response returns a valid list")
+        self.assertNotEqual(len(list_vm),0, "Check VM available in List Virtual Machines")
+        vm_response = list_vm[0]
+        self.assertEqual(vm_response.state, 'Running',msg="VM is not in Running state")
+        self.assertEqual(vm_response.projectid, projectid,msg="VM is not in project")
+        return vm, vm_response.hostid
+
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_01_list_aff_grps_for_vm(self):
+        """
+          List affinity group for a vm for projects
+        """
+        aff_grps = []
+        aff_grps.append(self.create_aff_grp(self.domain_api_client, projectid=self.project.id))
+
+        vm, hostid = self.create_vm_in_aff_grps(self.account_api_client,ag_list=[aff_grps[0].name])
+        list_aff_grps = AffinityGroup.list(self.api_client,virtualmachineid=vm.id)
+
+        self.assertEqual(list_aff_grps[0].name, aff_grps[0].name,"Listing Affinity Group by VM id failed")
+        self.assertEqual(list_aff_grps[0].projectid, self.project.id,"Listing Affinity Group by VM id failed, vm was not in project")
+
+        vm.delete(self.api_client)
+        #Wait for expunge interval to cleanup VM
+        wait_for_cleanup(self.apiclient, ["expunge.delay", "expunge.interval"])
+        self.cleanup.append(aff_grps[0])
+
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_02_list_multiple_aff_grps_for_vm(self):
+        """
+          List multiple affinity groups associated with a vm for projects
+        """
+
+        aff_grp_01 = self.create_aff_grp(self.account_api_client)
+        aff_grp_02 = self.create_aff_grp(self.account_api_client)
+
+        aff_grps_names = [aff_grp_01.name, aff_grp_02.name]
+        vm, hostid = self.create_vm_in_aff_grps(ag_list=aff_grps_names)
+        list_aff_grps = AffinityGroup.list(self.api_client,
+                                    virtualmachineid=vm.id)
+
+        list_aff_grps_names = [list_aff_grps[0].name, list_aff_grps[1].name]
+
+        aff_grps_names.sort()
+        list_aff_grps_names.sort()
+        self.assertEqual(aff_grps_names, list_aff_grps_names,"One of the Affinity Groups is missing %s" % list_aff_grps_names)
+
+        vm.delete(self.api_client)
+        #Wait for expunge interval to cleanup VM
+        wait_for_cleanup(self.apiclient, ["expunge.delay", "expunge.interval"])
+        self.cleanup.append(aff_grp_01)
+        self.cleanup.append(aff_grp_02)
+
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_03_list_aff_grps_by_id(self):
+        """
+          List affinity groups by id for projects
+        """
+        aff_grp = self.create_aff_grp(self.account_api_client)
+        list_aff_grps = AffinityGroup.list(self.account_api_client, id=aff_grp.id, projectid=self.project.id)
+        self.assertEqual(list_aff_grps[0].id, aff_grp.id,"Listing Affinity Group by id failed")
+        with self.assertRaises(Exception):
+           AffinityGroup.list(self.account_not_in_project_api_client, id=aff_grp.id, projectid=self.project.id)
+        self.cleanup.append(aff_grp)
+
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_04_list_aff_grps_by_name(self):
+        """
+           List Affinity Groups by name for projects
+        """
+        aff_grp = self.create_aff_grp(self.account_api_client)
+        list_aff_grps = AffinityGroup.list(self.account_api_client, name=aff_grp.name, projectid=self.project.id)
+        self.assertEqual(list_aff_grps[0].name, aff_grp.name,"Listing Affinity Group by name failed")
+        with self.assertRaises(Exception):
+           AffinityGroup.list(self.account_not_in_project_api_client, id=aff_grp.id, projectid=self.project.id)
+        self.cleanup.append(aff_grp)
+
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_05_list_aff_grps_by_non_existing_id(self):
+        """
+           List Affinity Groups by non-existing id for projects
+        """
+        aff_grp = self.create_aff_grp(self.account_api_client)
+        list_aff_grps = AffinityGroup.list(self.account_api_client, id=1234, projectid=self.project.id)
+        self.assertEqual(list_aff_grps, None, "Listing Affinity Group by non-existing id succeeded.")
+        self.cleanup.append(aff_grp)
+
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_06_list_aff_grps_by_non_existing_name(self):
+        """
+           List Affinity Groups by non-existing name for projects
+        """
+
+        aff_grp = self.create_aff_grp(self.account_api_client)
+        list_aff_grps = AffinityGroup.list(self.account_api_client, name="inexistantName", projectid=self.project.id)
+        self.assertEqual(list_aff_grps, None, "Listing Affinity Group by non-existing name succeeded.")
+        self.cleanup.append(aff_grp)
+
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_07_list_all_vms_in_aff_grp(self):
+        """
+          List affinity group should list all for a vms associated with that group for projects
+        """
+
+        aff_grp = self.create_aff_grp(self.account_api_client)
+
+        vm1, hostid1 = self.create_vm_in_aff_grps(ag_list=[aff_grp.name])
+        vm2, hostid2 = self.create_vm_in_aff_grps(ag_list=[aff_grp.name])
+        list_aff_grps = AffinityGroup.list(self.api_client, id=aff_grp.id, projectid=self.project.id)
+
+        self.assertEqual(list_aff_grps[0].name, aff_grp.name, "Listing Affinity Group by id failed")
+
+        self.assertEqual(list_aff_grps[0].virtualmachineIds[0], vm1.id, "List affinity group response.virtualmachineIds for group: %s doesn't contain vmid : %s" % (aff_grp.name, vm1.id))
+        self.assertEqual(list_aff_grps[0].virtualmachineIds[1], vm2.id, "List affinity group response.virtualmachineIds for group: %s doesn't contain vmid : %s" % (aff_grp.name, vm2.id))
+
+
+        vm1.delete(self.api_client)
+        vm2.delete(self.api_client)
+        #Wait for expunge interval to cleanup VM
+        wait_for_cleanup(self.apiclient, ["expunge.delay", "expunge.interval"])
+        self.cleanup.append(aff_grp)
+ 
+class TestDeleteAffinityGroups(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+       cls.testClient = super(TestDeleteAffinityGroups, cls).getClsTestClient()
+       cls.api_client = cls.testClient.getApiClient()
+       cls.services = Services().services
+
+       #Get Zone, Domain and templates
+       cls.rootdomain = get_domain(cls.api_client)
+       cls.domain = Domain.create(cls.api_client, cls.services["domain"])
+
+       cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+       cls.template = get_template(
+          cls.api_client,
+          cls.zone.id,
+          cls.services["ostype"]
+       )
+       
+       cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+       cls.services["template"] = cls.template.id
+       cls.services["zoneid"] = cls.zone.id
+       
+       cls.domain_admin_account = Account.create(
+          cls.api_client,
+          cls.services["domain_admin_account"],
+          domainid=cls.domain.id,
+          admin=True
+       )
+
+       cls.domain_api_client = cls.testClient.getUserApiClient(cls.domain_admin_account.name, cls.domain.name, 2)
+
+       cls.account = Account.create(
+          cls.api_client,
+          cls.services["account"],
+          domainid=cls.domain.id
+       )       
+
+       cls.account_api_client = cls.testClient.getUserApiClient(cls.account.name, cls.domain.name, 0)
+
+       cls.account_not_in_project = Account.create(
+          cls.api_client,
+          cls.services["account_not_in_project"],
+          domainid=cls.domain.id
+       )
+
+       cls.account_not_in_project_api_client = cls.testClient.getUserApiClient(cls.account_not_in_project.name, cls.domain.name, 0)
+
+       cls.project = Project.create(
+          cls.api_client,
+          cls.services["project"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+       
+       cls.project2 = Project.create(
+          cls.api_client,
+          cls.services["project2"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+
+       cls.debug("Created project with ID: %s" % cls.project.id)
+       cls.debug("Created project2 with ID: %s" % cls.project2.id)
+
+       # Add user to the project
+       cls.project.addAccount(
+          cls.api_client,
+          cls.account.name
+       )
+
+       cls.service_offering = ServiceOffering.create(
+          cls.api_client,
+          cls.services["service_offering"],
+          domainid=cls.account.domainid
+       )
+       
+       cls._cleanup = []
+       return
+
+    def setUp(self):
+       self.apiclient = self.testClient.getApiClient()
+       self.dbclient = self.testClient.getDbConnection()
+       self.cleanup = []
+
+    def tearDown(self):
+       try:
+#            #Clean up, terminate the created instance, volumes and snapshots
+          cleanup_resources(self.api_client, self.cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+       return
+
+    @classmethod
+    def tearDownClass(cls):
+       try:
+          cls.domain.delete(cls.api_client, cleanup=True)
+          cleanup_resources(cls.api_client, cls._cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+
+    def create_aff_grp(self, api_client=None, aff_grp=None, aff_grp_name=None, projectid=None):
+
+       if not api_client:
+          api_client = self.api_client
+       if aff_grp is None:
+          aff_grp = self.services["host_anti_affinity"]
+       if aff_grp_name is None:
+          aff_grp["name"] = "aff_grp_" + random_gen(size=6)
+       else:
+          aff_grp["name"] = aff_grp_name
+       if projectid is None:
+          projectid = self.project.id
+       try:
+          return AffinityGroup.create(api_client, aff_grp, None, None, projectid)
+       except Exception as e:
+          raise Exception("Error: Creation of Affinity Group failed : %s" % e)
+
+    def create_vm_in_aff_grps(self, api_client=None, ag_list=[], projectid=None):
+        self.debug('Creating VM in AffinityGroups=%s' % ag_list)
+
+        if api_client is None:
+           api_client = self.api_client
+        if projectid is None:
+           projectid = self.project.id
+
+        vm = VirtualMachine.create(
+                api_client,
+                self.services["virtual_machine"],
+                projectid=projectid,
+                templateid=self.template.id,
+                serviceofferingid=self.service_offering.id,
+                affinitygroupnames=ag_list
+              )
+        self.debug('Created VM=%s in Affinity Group=%s' % (vm.id, tuple(ag_list)))
+        list_vm = list_virtual_machines(self.api_client, id=vm.id, projectid=projectid)
+        self.assertEqual(isinstance(list_vm, list), True,"Check list response returns an invalid list %s" % list_vm)
+        self.assertNotEqual(len(list_vm),0, "Check VM available in TestDeployVMAffinityGroups")
+        self.assertEqual(list_vm[0].id, vm.id,"Listed vm does not have the same ids")
+        vm_response = list_vm[0]
+        self.assertEqual(vm.state, 'Running',msg="VM is not in Running state")
+        self.assertEqual(vm.projectid, projectid,msg="VM is not in project")
+        self.assertNotEqual(vm_response.hostid, None, "Host id was null for vm %s" % vm_response)
+        return vm, vm_response.hostid
+
+    def delete_aff_group(self, apiclient, **kwargs):
+        cmd = deleteAffinityGroup.deleteAffinityGroupCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return apiclient.deleteAffinityGroup(cmd)
+
+
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_01_delete_aff_grp_by_id(self):
+        """
+           #Delete Affinity Group by id.
+        """
+
+        aff_grp1 = self.create_aff_grp(self.account_api_client)
+        aff_grp2 = self.create_aff_grp(self.account_api_client)
+
+        aff_grp1.delete(self.account_api_client)
+        
+        with self.assertRaises(Exception):
+           list_aff_grps = AffinityGroup.list(self.api_client, id=aff_grp1.id)
+        
+        self.cleanup.append(aff_grp2)
+
+    @attr(tags=["simulator", "basic", "advanced"], required_hardware="false")
+    def test_02_delete_aff_grp_by_id_another_user(self):
+        """
+           #Delete Affinity Group by id should fail for user not in project
+        """
+
+        aff_grp1 = self.create_aff_grp(self.account_api_client)
+        aff_grp2 = self.create_aff_grp(self.account_api_client)
+
+        with self.assertRaises(Exception):
+           aff_grp1.delete(self.account_not_in_project_api_client)
+
+        self.cleanup.append(aff_grp1)
+        self.cleanup.append(aff_grp2)
+
+class TestUpdateVMAffinityGroups(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+       cls.testClient = super(TestUpdateVMAffinityGroups, cls).getClsTestClient()
+       cls.api_client = cls.testClient.getApiClient()
+       cls.services = Services().services
+
+       #Get Zone, Domain and templates
+       cls.rootdomain = get_domain(cls.api_client)
+       cls.domain = Domain.create(cls.api_client, cls.services["domain"])
+
+       cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+       cls.template = get_template(
+          cls.api_client,
+          cls.zone.id,
+          cls.services["ostype"]
+       )
+       
+       cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+       cls.services["template"] = cls.template.id
+       cls.services["zoneid"] = cls.zone.id
+       
+       cls.domain_admin_account = Account.create(
+          cls.api_client,
+          cls.services["domain_admin_account"],
+          domainid=cls.domain.id,
+          admin=True
+       )
+
+       cls.domain_api_client = cls.testClient.getUserApiClient(cls.domain_admin_account.name, cls.domain.name, 2)
+
+       cls.account = Account.create(
+          cls.api_client,
+          cls.services["account"],
+          domainid=cls.domain.id
+       )       
+
+       cls.account_api_client = cls.testClient.getUserApiClient(cls.account.name, cls.domain.name, 0)
+
+       cls.account_not_in_project = Account.create(
+          cls.api_client,
+          cls.services["account_not_in_project"],
+          domainid=cls.domain.id
+       )
+
+       cls.account_not_in_project_api_client = cls.testClient.getUserApiClient(cls.account_not_in_project.name, cls.domain.name, 0)
+
+       cls.project = Project.create(
+          cls.api_client,
+          cls.services["project"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+       
+       cls.project2 = Project.create(
+          cls.api_client,
+          cls.services["project2"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+
+       cls.debug("Created project with ID: %s" % cls.project.id)
+       cls.debug("Created project2 with ID: %s" % cls.project2.id)
+
+       # Add user to the project
+       cls.project.addAccount(
+          cls.api_client,
+          cls.account.name
+       )
+
+       cls.service_offering = ServiceOffering.create(
+          cls.api_client,
+          cls.services["service_offering"],
+          domainid=cls.account.domainid
+       )
+       
+       cls._cleanup = []
+       return
+
+    def setUp(self):
+       self.apiclient = self.testClient.getApiClient()
+       self.dbclient = self.testClient.getDbConnection()
+       self.cleanup = []
+
+    def tearDown(self):
+       try:
+#            #Clean up, terminate the created instance, volumes and snapshots
+          cleanup_resources(self.api_client, self.cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+       return
+
+    @classmethod
+    def tearDownClass(cls):
+       try:
+          cls.domain.delete(cls.api_client, cleanup=True)
+          cleanup_resources(cls.api_client, cls._cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+
+    def create_aff_grp(self, api_client=None, aff_grp=None, aff_grp_name=None, projectid=None):
+
+       if not api_client:
+          api_client = self.api_client
+       if aff_grp is None:
+          aff_grp = self.services["host_anti_affinity"]
+       if aff_grp_name is None:
+          aff_grp["name"] = "aff_grp_" + random_gen(size=6)
+       else:
+          aff_grp["name"] = aff_grp_name
+       if projectid is None:
+          projectid = self.project.id
+       try:
+          return AffinityGroup.create(api_client, aff_grp, None, None, projectid)
+       except Exception as e:
+          raise Exception("Error: Creation of Affinity Group failed : %s" % e)
+
+    def create_vm_in_aff_grps(self, api_client=None, ag_list=[], projectid=None):
+        self.debug('Creating VM in AffinityGroups=%s' % ag_list)
+
+        if api_client is None:
+           api_client = self.api_client
+        if projectid is None:
+           projectid = self.project.id
+
+        vm = VirtualMachine.create(
+                api_client,
+                self.services["virtual_machine"],
+                projectid=projectid,
+                templateid=self.template.id,
+                serviceofferingid=self.service_offering.id,
+                affinitygroupnames=ag_list
+              )
+        self.debug('Created VM=%s in Affinity Group=%s' % (vm.id, tuple(ag_list)))
+        list_vm = list_virtual_machines(self.api_client, id=vm.id, projectid=projectid)
+        self.assertEqual(isinstance(list_vm, list), True,"Check list response returns an invalid list %s" % list_vm)
+        self.assertNotEqual(len(list_vm),0, "Check VM available in TestDeployVMAffinityGroups")
+        self.assertEqual(list_vm[0].id, vm.id,"Listed vm does not have the same ids")
+        vm_response = list_vm[0]
+        self.assertEqual(vm.state, 'Running',msg="VM is not in Running state")
+        self.assertEqual(vm.projectid, projectid,msg="VM is not in project")
+        self.assertNotEqual(vm_response.hostid, None, "Host id was null for vm %s" % vm_response)
+        return vm, vm_response.hostid
+
+    @attr(tags=["simulator", "basic", "advanced", "multihost"], required_hardware="false")
+    def test_01_update_aff_grp_by_ids(self):
+        """
+           Update the list of affinityGroups by using affinity groupids
+
+        """
+        aff_grp1 = self.create_aff_grp(self.account_api_client)
+        aff_grp2 = self.create_aff_grp(self.account_api_client)
+
+        vm1, hostid1 = self.create_vm_in_aff_grps(ag_list=[aff_grp1.name])
+        vm2, hostid2 = self.create_vm_in_aff_grps(ag_list=[aff_grp1.name])
+
+        vm1.stop(self.api_client)
+
+        list_aff_grps = AffinityGroup.list(self.api_client, projectid=self.project.id)
+
+        self.assertEqual(len(list_aff_grps), 2 , "2 affinity groups should be present")
+
+        vm1.update_affinity_group(self.api_client,affinitygroupids=[list_aff_grps[0].id,list_aff_grps[1].id])
+
+        list_aff_grps = AffinityGroup.list(self.api_client,virtualmachineid=vm1.id)
+
+        list_aff_grps_names = [list_aff_grps[0].name, list_aff_grps[1].name]
+
+        aff_grps_names = [aff_grp1.name, aff_grp2.name]
+        aff_grps_names.sort()
+        list_aff_grps_names.sort()
+        self.assertEqual(aff_grps_names, list_aff_grps_names,"One of the Affinity Groups is missing %s" % list_aff_grps_names)
+
+        vm1.start(self.api_client)
+
+        vm_status = VirtualMachine.list(self.api_client, id=vm1.id)
+        self.assertNotEqual(vm_status[0].hostid, hostid2, "The virtual machine started on host %s violating the host anti-affinity rule" %vm_status[0].hostid)
+
+        vm1.delete(self.api_client)
+        vm2.delete(self.api_client)
+        #Wait for expunge interval to cleanup VM
+        wait_for_cleanup(self.apiclient, ["expunge.delay", "expunge.interval"])
+        aff_grp1.delete(self.api_client)
+        aff_grp2.delete(self.api_client)
+           
+
+class TestDeployVMAffinityGroups(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+       cls.testClient = super(TestDeployVMAffinityGroups, cls).getClsTestClient()
+       cls.api_client = cls.testClient.getApiClient()
+       cls.services = Services().services
+
+       #Get Zone, Domain and templates
+       cls.rootdomain = get_domain(cls.api_client)
+       cls.domain = Domain.create(cls.api_client, cls.services["domain"])
+
+       cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+       cls.template = get_template(
+          cls.api_client,
+          cls.zone.id,
+          cls.services["ostype"]
+       )
+       
+       cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+       cls.services["template"] = cls.template.id
+       cls.services["zoneid"] = cls.zone.id
+       
+       cls.domain_admin_account = Account.create(
+          cls.api_client,
+          cls.services["domain_admin_account"],
+          domainid=cls.domain.id,
+          admin=True
+       )
+
+       cls.domain_api_client = cls.testClient.getUserApiClient(cls.domain_admin_account.name, cls.domain.name, 2)
+
+       cls.account = Account.create(
+          cls.api_client,
+          cls.services["account"],
+          domainid=cls.domain.id
+       )       
+
+       cls.account_api_client = cls.testClient.getUserApiClient(cls.account.name, cls.domain.name, 0)
+
+       cls.account_not_in_project = Account.create(
+          cls.api_client,
+          cls.services["account_not_in_project"],
+          domainid=cls.domain.id
+       )
+
+       cls.account_not_in_project_api_client = cls.testClient.getUserApiClient(cls.account_not_in_project.name, cls.domain.name, 0)
+
+       cls.project = Project.create(
+          cls.api_client,
+          cls.services["project"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+       
+       cls.project2 = Project.create(
+          cls.api_client,
+          cls.services["project2"],
+          account=cls.domain_admin_account.name,
+          domainid=cls.domain_admin_account.domainid
+       )
+
+       cls.debug("Created project with ID: %s" % cls.project.id)
+       cls.debug("Created project2 with ID: %s" % cls.project2.id)
+
+       # Add user to the project
+       cls.project.addAccount(
+          cls.api_client,
+          cls.account.name
+       )
+
+       cls.service_offering = ServiceOffering.create(
+          cls.api_client,
+          cls.services["service_offering"],
+          domainid=cls.account.domainid
+       )
+       
+       cls._cleanup = []
+       return
+
+    def setUp(self):
+       self.apiclient = self.testClient.getApiClient()
+       self.dbclient = self.testClient.getDbConnection()
+       self.cleanup = []
+
+    def tearDown(self):
+       try:
+#            #Clean up, terminate the created instance, volumes and snapshots
+          cleanup_resources(self.api_client, self.cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+       return
+
+    @classmethod
+    def tearDownClass(cls):
+       try:
+          cls.domain.delete(cls.api_client, cleanup=True)
+          cleanup_resources(cls.api_client, cls._cleanup)
+       except Exception as e:
+          raise Exception("Warning: Exception during cleanup : %s" % e)
+
+    def create_aff_grp(self, api_client=None, aff_grp=None, aff_grp_name=None, projectid=None):
+
+       if not api_client:
+          api_client = self.api_client
+       if aff_grp is None:
+          aff_grp = self.services["host_anti_affinity"]
+       if aff_grp_name is None:
+          aff_grp["name"] = "aff_grp_" + random_gen(size=6)
+       else:
+          aff_grp["name"] = aff_grp_name
+       if projectid is None:
+          projectid = self.project.id
+       try:
+          return AffinityGroup.create(api_client, aff_grp, None, None, projectid)
+       except Exception as e:
+          raise Exception("Error: Creation of Affinity Group failed : %s" % e)
+
+    def create_vm_in_aff_grps(self, api_client=None, ag_list=[], projectid=None):
+        self.debug('Creating VM in AffinityGroups=%s' % ag_list)
+
+        if api_client is None:
+           api_client = self.api_client
+        if projectid is None:
+           projectid = self.project.id
+
+        vm = VirtualMachine.create(
+                api_client,
+                self.services["virtual_machine"],
+                projectid=projectid,
+                templateid=self.template.id,
+                serviceofferingid=self.service_offering.id,
+                affinitygroupnames=ag_list
+              )
+        self.debug('Created VM=%s in Affinity Group=%s' % (vm.id, tuple(ag_list)))
+        list_vm = list_virtual_machines(self.api_client, id=vm.id, projectid=projectid)
+        self.assertEqual(isinstance(list_vm, list), True,"Check list response returns an invalid list %s" % list_vm)
+        self.assertNotEqual(len(list_vm),0, "Check VM available in TestDeployVMAffinityGroups")
+        self.assertEqual(list_vm[0].id, vm.id,"Listed vm does not have the same ids")
+        vm_response = list_vm[0]
+        self.assertEqual(vm.state, 'Running',msg="VM is not in Running state")
+        self.assertEqual(vm.projectid, projectid,msg="VM is not in project")
+        self.assertNotEqual(vm_response.hostid, None, "Host id was null for vm %s" % vm_response)
+        return vm, vm_response.hostid
+
+    @attr(tags=["simulator", "basic", "advanced", "multihost"], required_hardware="false")
+    def test_01_deploy_vm_anti_affinity_group(self):
+        """
+        test DeployVM in anti-affinity groups
+
+        deploy VM1 and VM2 in the same host-anti-affinity groups
+        Verify that the vms are deployed on separate hosts
+        """
+        aff_grp = self.create_aff_grp(self.account_api_client)
+        vm1, hostid1 = self.create_vm_in_aff_grps(self.account_api_client,ag_list=[aff_grp.name])
+        vm2, hostid2 = self.create_vm_in_aff_grps(self.account_api_client, ag_list=[aff_grp.name])
+
+        self.assertNotEqual(hostid1, hostid2, msg="Both VMs of affinity group %s are on the same host: %s , %s, %s, %s" % (aff_grp.name, vm1, hostid1, vm2, hostid2))
+
+        vm1.delete(self.api_client)
+        vm2.delete(self.api_client)
+        wait_for_cleanup(self.api_client, ["expunge.delay", "expunge.interval"])
+        self.cleanup.append(aff_grp)
+
+    @attr(tags=["simulator", "basic", "advanced", "multihost"], required_hardware="false")
+    def test_02_deploy_vm_anti_affinity_group_fail_on_not_enough_hosts(self):
+        """
+        test DeployVM in anti-affinity groups with more vms than hosts.
+        """
+        hosts = list_hosts(self.api_client, type="routing")
+        aff_grp = self.create_aff_grp(self.account_api_client)
+        vms = []
+        for host in hosts:
+           vms.append(self.create_vm_in_aff_grps(self.account_api_client,ag_list=[aff_grp.name]))
+
+        vm_failed = None
+        with self.assertRaises(Exception):
+           vm_failed = self.create_vm_in_aff_grps(self.account_api_client,ag_list=[aff_grp.name])
+        
+        self.assertEqual(len(hosts), len(vms), "Received %s and %s " % (hosts, vms))
+        
+        if vm_failed:
+           vm_failed.expunge(self.api_client)
+
+        self.cleanup.append(aff_grp)
+
+
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c76d3171/test/integration/smoke/test_affinity_groups_projects.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_affinity_groups_projects.py b/test/integration/smoke/test_affinity_groups_projects.py
new file mode 100644
index 0000000..2e971c5
--- /dev/null
+++ b/test/integration/smoke/test_affinity_groups_projects.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+# 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.
+
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.lib.utils import *
+from marvin.lib.base import *
+from marvin.lib.common import *
+from marvin.sshClient import SshClient
+from nose.plugins.attrib import attr
+
+class TestDeployVmWithAffinityGroup(cloudstackTestCase):
+    """
+    This test deploys a virtual machine for a project
+    using the small service offering and builtin template
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        cls.testClient = super(TestDeployVmWithAffinityGroup, cls).getClsTestClient()
+        zone_name = cls.testClient.getZoneForTests()
+        cls.apiclient = cls.testClient.getApiClient()
+        cls.domain = get_domain(cls.apiclient) 
+        cls.services = cls.testClient.getParsedTestDataConfig()
+        # Get Zone, Domain and templates
+        cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
+                            
+        cls.template = get_template(
+            cls.apiclient,
+            cls.zone.id,
+            cls.services["ostype"]
+        )
+        
+        if cls.template == FAILED:
+            assert False, "get_template() failed to return template with description %s" % cls.services["ostype"]
+            
+        cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+
+        cls.services["template"] = cls.template.id
+        cls.services["zoneid"] = cls.zone.id
+
+        cls.account = Account.create(
+            cls.apiclient,
+            cls.services["account"],
+            domainid=cls.domain.id
+        )
+
+        projectData = {
+            "name": "Project",
+            "displaytext": "Test project",
+        }
+
+        cls.project = Project.create(
+            cls.apiclient,
+            projectData,
+            account=cls.account.name,
+            domainid=cls.account.domainid
+        )
+
+        # Add user to the project
+        cls.project.addAccount(
+            cls.apiclient,
+            cls.account.name
+        )
+
+        cls.service_offering = ServiceOffering.create(
+            cls.apiclient,
+            cls.services["service_offerings"]["tiny"]
+        )
+
+        cls.ag = AffinityGroup.create(cls.apiclient, cls.services["virtual_machine"]["affinity"],projectid=cls.project.id)
+
+        cls._cleanup = [
+            cls.service_offering,
+            cls.ag,
+            cls.project,
+            cls.account,
+        ]
+        return
+
+    @attr(tags=["basic", "advanced", "multihost"], required_hardware="false")
+    def test_DeployVmAntiAffinityGroup_in_project(self):
+        """
+        test DeployVM in anti-affinity groups for project
+
+        deploy VM1 and VM2 in the same host-anti-affinity groups
+        Verify that the vms are deployed on separate hosts
+        """
+        #deploy VM1 in affinity group created in setUp
+        vm1 = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            projectid=self.project.id,
+            serviceofferingid=self.service_offering.id,
+            affinitygroupnames=[self.ag.name]
+        )
+
+        list_vm1 = list_virtual_machines(
+            self.apiclient,
+            id=vm1.id
+        )
+        self.assertEqual(
+            isinstance(list_vm1, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(list_vm1),
+            0,
+            "Check VM available in List Virtual Machines"
+        )
+        vm1_response = list_vm1[0]
+        self.assertEqual(
+            vm1_response.state,
+            'Running',
+            msg="VM is not in Running state"
+        )
+        self.assertEqual(
+            vm1_response.projectid,
+            self.project.id,
+            msg="VM1 is not deployed in project"
+        )
+        host_of_vm1 = vm1_response.hostid
+
+        #deploy VM2 in affinity group created in setUp
+        vm2 = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            projectid=self.project.id,
+            serviceofferingid=self.service_offering.id,
+            affinitygroupnames=[self.ag.name]
+        )
+        list_vm2 = list_virtual_machines(
+            self.apiclient,
+            id=vm2.id
+        )
+        self.assertEqual(
+            isinstance(list_vm2, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(list_vm2),
+            0,
+            "Check VM available in List Virtual Machines"
+        )
+        vm2_response = list_vm2[0]
+        self.assertEqual(
+            vm2_response.state,
+            'Running',
+            msg="VM is not in Running state"
+        )
+        self.assertEqual(
+            vm2_response.projectid,
+            self.project.id,
+            msg="VM2 is not deployed in project"
+        )
+        host_of_vm2 = vm2_response.hostid
+
+        self.assertNotEqual(host_of_vm1, host_of_vm2,
+            msg="Both VMs of affinity group %s are on the same host" % self.ag.name)
+
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            #Clean up, terminate the created templates
+            cleanup_resources(cls.apiclient, cls._cleanup)
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c76d3171/tools/marvin/marvin/lib/base.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py
index 32e2d59..4b04e77 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -4220,7 +4220,7 @@ class AffinityGroup:
         self.__dict__.update(items)
 
     @classmethod
-    def create(cls, apiclient, aff_grp, account=None, domainid=None):
+    def create(cls, apiclient, aff_grp, account=None, domainid=None, projectid=None):
         cmd = createAffinityGroup.createAffinityGroupCmd()
         cmd.name = aff_grp['name']
         cmd.displayText = aff_grp['name']
@@ -4229,6 +4229,8 @@ class AffinityGroup:
             cmd.account = account
         if domainid:
             cmd.domainid = domainid
+        if projectid:
+            cmd.projectid = projectid
         return AffinityGroup(apiclient.createAffinityGroup(cmd).__dict__)
 
     def update(self, apiclient):


Mime
View raw message