cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From prachida...@apache.org
Subject [1/4] git commit: updated refs/heads/4.2 to b0947c9
Date Sat, 10 Aug 2013 18:19:43 GMT
Updated Branches:
  refs/heads/4.2 359967d9f -> b0947c957


CLOUDSTACK-4168 Root Admin should be able to create 'ExplicitDedication' affinity group at domain level and make it available for all accounts in the domain

Changes:
- 'ExcplicitDedication' type of group can be created/deleted by Root admin only
- Users can no longer create this type of affinity group
- RootAdmin can create this type of affinitygroup at domain level. Such a domain level group is available for all accounts in that domain for listing and for use during deployVM.
- The domain level affinitygroup should be visible to the users in that domain, domain admins and Root admin.


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

Branch: refs/heads/4.2
Commit: b965032b57a6023859fbc4b0faad533dc8adc2dc
Parents: 359967d
Author: Prachi Damle <prachi@cloud.com>
Authored: Wed Aug 7 16:21:27 2013 -0700
Committer: Prachi Damle <prachi@cloud.com>
Committed: Sat Aug 10 11:02:42 2013 -0700

----------------------------------------------------------------------
 .../cloudstack/affinity/AffinityGroup.java      |   2 +
 .../affinity/AffinityGroupProcessor.java        |  19 +++
 .../affinity/AffinityGroupService.java          |   4 +
 .../affinity/AffinityProcessorBase.java         |  10 ++
 client/tomcatconf/applicationContext.xml.in     |   3 +
 client/tomcatconf/componentContext.xml.in       |   1 +
 engine/schema/src/com/cloud/user/AccountVO.java |   6 +-
 .../affinity/AffinityGroupDomainMapVO.java      |  73 ++++++++++
 .../cloudstack/affinity/AffinityGroupVO.java    |  15 +-
 .../affinity/dao/AffinityGroupDomainMapDao.java |  31 ++++
 .../dao/AffinityGroupDomainMapDaoImpl.java      |  67 +++++++++
 .../affinity/ExplicitDedicationProcessor.java   |   9 ++
 .../cloud/acl/AffinityGroupAccessChecker.java   |  80 +++++++++++
 server/src/com/cloud/acl/DomainChecker.java     |   3 +
 .../com/cloud/api/query/QueryManagerImpl.java   | 122 +++++++++++++---
 .../cloud/api/query/vo/AffinityGroupJoinVO.java |  16 +++
 .../src/com/cloud/user/AccountManagerImpl.java  |   5 +-
 server/src/com/cloud/vm/UserVmManagerImpl.java  |  28 +++-
 .../affinity/AffinityGroupServiceImpl.java      | 140 +++++++++++++++++--
 .../affinity/AffinityApiUnitTest.java           |  22 ++-
 setup/db/db/schema-412to420.sql                 |  13 +-
 21 files changed, 625 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/api/src/org/apache/cloudstack/affinity/AffinityGroup.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroup.java b/api/src/org/apache/cloudstack/affinity/AffinityGroup.java
index ac2eb61..c1ad11d 100644
--- a/api/src/org/apache/cloudstack/affinity/AffinityGroup.java
+++ b/api/src/org/apache/cloudstack/affinity/AffinityGroup.java
@@ -28,4 +28,6 @@ public interface AffinityGroup extends ControlledEntity, InternalIdentity, Ident
 
     String getType();
 
+    ACLType getAclType();
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/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
index e3a9b62..09a4a31 100644
--- a/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java
+++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java
@@ -59,4 +59,23 @@ public interface AffinityGroupProcessor extends Adapter {
      */
     boolean check(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination plannedDestination)
             throws AffinityConflictException;
+
+    /**
+     * isAdminControlledGroup() should return true if the affinity/anti-affinity
+     * group can only be operated on[create/delete/modify] by the Admin
+     *
+     * @return boolean true/false
+     */
+    boolean isAdminControlledGroup();
+
+
+    /**
+     * canBeSharedDomainWide() should return true if the affinity/anti-affinity
+     * group can be created for a domain and shared by all accounts under the
+     * domain.
+     * 
+     * @return boolean true/false
+     */
+    boolean canBeSharedDomainWide();
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/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 1b30e58..43a4994 100644
--- a/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java
+++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupService.java
@@ -75,4 +75,8 @@ public interface AffinityGroupService {
 
     boolean isAffinityGroupProcessorAvailable(String affinityGroupType);
 
+    boolean isAdminControlledGroup(AffinityGroup group);
+
+    boolean isAffinityGroupAvailableInDomain(long affinityGroupId, long domainId);
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java b/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java
index 325ab80..c249f62 100644
--- a/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java
+++ b/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java
@@ -48,4 +48,14 @@ public class AffinityProcessorBase extends AdapterBase implements AffinityGroupP
             throws AffinityConflictException {
         return true;
     }
+
+    @Override
+    public boolean isAdminControlledGroup() {
+        return false;
+    }
+
+    @Override
+    public boolean canBeSharedDomainWide() {
+        return false;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/client/tomcatconf/applicationContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in
index 7992f93..4fb13c0 100644
--- a/client/tomcatconf/applicationContext.xml.in
+++ b/client/tomcatconf/applicationContext.xml.in
@@ -379,6 +379,7 @@
   <bean id="StaticRoleBasedAPIAccessChecker" class="org.apache.cloudstack.acl.StaticRoleBasedAPIAccessChecker"/>
   <bean id="databaseIntegrityChecker" class="com.cloud.upgrade.DatabaseIntegrityChecker" />
   <bean id="domainChecker" class="com.cloud.acl.DomainChecker" />
+  <bean id="affinityGroupAccessChecker" class="com.cloud.acl.AffinityGroupAccessChecker" />
   
   <!--
     Authenticators
@@ -917,6 +918,8 @@
   </bean>
   <bean id="AffinityGroupVMMapDaoImpl" class="org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDaoImpl">
   </bean>
+  <bean id="AffinityGroupDomainMapDaoImpl" class="org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDaoImpl">
+  </bean>
   
   <bean id="PlannerHostReservationDaoImpl" class="com.cloud.deploy.dao.PlannerHostReservationDaoImpl">
   </bean>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/client/tomcatconf/componentContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in
index 5ca0750..0a422a1 100644
--- a/client/tomcatconf/componentContext.xml.in
+++ b/client/tomcatconf/componentContext.xml.in
@@ -146,6 +146,7 @@
   <bean id="securityCheckers" class="com.cloud.utils.component.AdapterList">
     <property name="Adapters">
       <list>
+		  <ref bean="affinityGroupAccessChecker"/>
           <ref bean="domainChecker"/>
       </list>
     </property>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/engine/schema/src/com/cloud/user/AccountVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/user/AccountVO.java b/engine/schema/src/com/cloud/user/AccountVO.java
index 77110ae..4a7e73b 100644
--- a/engine/schema/src/com/cloud/user/AccountVO.java
+++ b/engine/schema/src/com/cloud/user/AccountVO.java
@@ -65,7 +65,7 @@ public class AccountVO implements Account {
 
     @Column(name="default_zone_id")
     private Long defaultZoneId = null;
-    
+
     @Column(name = "default")
     boolean isDefault;
 
@@ -77,7 +77,7 @@ public class AccountVO implements Account {
         this.id = id;
     	this.uuid = UUID.randomUUID().toString();
     }
-    
+
     public AccountVO(String accountName, long domainId, String networkDomain, short type, String uuid) {
         this.accountName = accountName;
         this.domainId = domainId;
@@ -161,7 +161,7 @@ public class AccountVO implements Account {
 
     @Override
     public String toString() {
-        return new StringBuilder("Acct[").append(id).append("-").append(accountName).append("]").toString();
+        return new StringBuilder("Acct[").append(uuid).append("-").append(accountName).append("]").toString();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupDomainMapVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupDomainMapVO.java b/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupDomainMapVO.java
new file mode 100644
index 0000000..ea37194
--- /dev/null
+++ b/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupDomainMapVO.java
@@ -0,0 +1,73 @@
+// 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 javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import com.cloud.domain.PartOf;
+import org.apache.cloudstack.api.InternalIdentity;
+
+@Entity
+@Table(name = "affinity_group_domain_map")
+public class AffinityGroupDomainMapVO implements PartOf, InternalIdentity {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    long id;
+
+    @Column(name = "domain_id")
+    long domainId;
+
+    @Column(name = "affinity_group_id")
+    private long affinityGroupId;
+
+    @Column(name = "subdomain_access")
+    public Boolean subdomainAccess;
+
+    protected AffinityGroupDomainMapVO() {
+    }
+
+    public AffinityGroupDomainMapVO(long affinityGroupId, long domainId, Boolean subdomainAccess) {
+        this.affinityGroupId = affinityGroupId;
+        this.domainId = domainId;
+        this.subdomainAccess = subdomainAccess;
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+
+    @Override
+    public long getDomainId() {
+        return domainId;
+    }
+
+    public long getAffinityGroupId() {
+        return affinityGroupId;
+    }
+
+    public Boolean isSubdomainAccess() {
+        return subdomainAccess;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupVO.java b/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupVO.java
index f418cef..44f8dd8 100644
--- a/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupVO.java
+++ b/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupVO.java
@@ -20,11 +20,14 @@ import java.util.UUID;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Table;
 
+import org.apache.cloudstack.acl.ControlledEntity;
 
 @Entity
 @Table(name = ("affinity_group"))
@@ -52,17 +55,22 @@ public class AffinityGroupVO implements AffinityGroup {
     @Column(name = "uuid")
     private String uuid;
 
+    @Column(name = "acl_type")
+    @Enumerated(value = EnumType.STRING)
+    ControlledEntity.ACLType aclType;
+
     public AffinityGroupVO() {
     	this.uuid = UUID.randomUUID().toString();
     }
 
-    public AffinityGroupVO(String name, String type, String description, long domainId, long accountId) {
+    public AffinityGroupVO(String name, String type, String description, long domainId, long accountId, ACLType aclType) {
         this.name = name;
         this.description = description;
         this.domainId = domainId;
         this.accountId = accountId;
     	this.uuid = UUID.randomUUID().toString();
         this.type = type;
+        this.aclType = aclType;
     }
 
     @Override
@@ -105,6 +113,11 @@ public class AffinityGroupVO implements AffinityGroup {
     }
 
     @Override
+    public ControlledEntity.ACLType getAclType() {
+        return aclType;
+    }
+
+    @Override
     public String toString() {
         StringBuilder buf = new StringBuilder("AffinityGroup[");
         buf.append(uuid).append("]");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDomainMapDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDomainMapDao.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDomainMapDao.java
new file mode 100644
index 0000000..07be976
--- /dev/null
+++ b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDomainMapDao.java
@@ -0,0 +1,31 @@
+// 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.dao;
+
+import java.util.List;
+
+import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
+
+import com.cloud.utils.db.GenericDao;
+
+public interface AffinityGroupDomainMapDao extends GenericDao<AffinityGroupDomainMapVO, Long> {
+
+    AffinityGroupDomainMapVO findByAffinityGroup(long affinityGroupId);
+
+    List<AffinityGroupDomainMapVO> listByDomain(Object... domainId);
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDomainMapDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDomainMapDaoImpl.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDomainMapDaoImpl.java
new file mode 100644
index 0000000..3777ef5
--- /dev/null
+++ b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDomainMapDaoImpl.java
@@ -0,0 +1,67 @@
+// 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.dao;
+
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria.Op;
+
+public class AffinityGroupDomainMapDaoImpl extends GenericDaoBase<AffinityGroupDomainMapVO, Long> implements
+        AffinityGroupDomainMapDao {
+
+    private SearchBuilder<AffinityGroupDomainMapVO> ListByAffinityGroup;
+
+    private SearchBuilder<AffinityGroupDomainMapVO> DomainsSearch;
+
+
+    public AffinityGroupDomainMapDaoImpl() {
+    }
+
+    @PostConstruct
+    protected void init() {
+        ListByAffinityGroup = createSearchBuilder();
+        ListByAffinityGroup.and("affinityGroupId", ListByAffinityGroup.entity().getAffinityGroupId(),
+                SearchCriteria.Op.EQ);
+        ListByAffinityGroup.done();
+
+        DomainsSearch = createSearchBuilder();
+        DomainsSearch.and("domainId", DomainsSearch.entity().getDomainId(), Op.IN);
+        DomainsSearch.done();
+    }
+
+    @Override
+    public AffinityGroupDomainMapVO findByAffinityGroup(long affinityGroupId) {
+        SearchCriteria<AffinityGroupDomainMapVO> sc = ListByAffinityGroup.create();
+        sc.setParameters("affinityGroupId", affinityGroupId);
+        return findOneBy(sc);
+    }
+
+    @Override
+    public List<AffinityGroupDomainMapVO> listByDomain(Object... domainId) {
+        SearchCriteria<AffinityGroupDomainMapVO> sc = DomainsSearch.create();
+        sc.setParameters("domainId", (Object[]) domainId);
+
+        return listBy(sc);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/plugins/affinity-group-processors/explicit-dedication/src/org/apache/cloudstack/affinity/ExplicitDedicationProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/affinity-group-processors/explicit-dedication/src/org/apache/cloudstack/affinity/ExplicitDedicationProcessor.java b/plugins/affinity-group-processors/explicit-dedication/src/org/apache/cloudstack/affinity/ExplicitDedicationProcessor.java
index a0eb56c..3806ae1 100644
--- a/plugins/affinity-group-processors/explicit-dedication/src/org/apache/cloudstack/affinity/ExplicitDedicationProcessor.java
+++ b/plugins/affinity-group-processors/explicit-dedication/src/org/apache/cloudstack/affinity/ExplicitDedicationProcessor.java
@@ -380,4 +380,13 @@ public class ExplicitDedicationProcessor extends AffinityProcessorBase implement
         return domainIds;
     }
 
+    @Override
+    public boolean isAdminControlledGroup() {
+        return true;
+    }
+
+    @Override
+    public boolean canBeSharedDomainWide() {
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/server/src/com/cloud/acl/AffinityGroupAccessChecker.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/acl/AffinityGroupAccessChecker.java b/server/src/com/cloud/acl/AffinityGroupAccessChecker.java
new file mode 100644
index 0000000..fcebf2f
--- /dev/null
+++ b/server/src/com/cloud/acl/AffinityGroupAccessChecker.java
@@ -0,0 +1,80 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.acl;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.affinity.AffinityGroup;
+import org.apache.cloudstack.affinity.AffinityGroupService;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
+import org.springframework.stereotype.Component;
+
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.DomainManager;
+
+@Component
+@Local(value = SecurityChecker.class)
+public class AffinityGroupAccessChecker extends DomainChecker {
+
+    @Inject
+    AffinityGroupService _affinityGroupService;
+    @Inject
+    AccountManager _accountMgr;
+    @Inject
+    AffinityGroupDomainMapDao _affinityGroupDomainMapDao;
+
+    @Override
+    public boolean checkAccess(Account caller, ControlledEntity entity, AccessType accessType)
+            throws PermissionDeniedException {
+        if (entity instanceof AffinityGroup) {
+            AffinityGroup group = (AffinityGroup) entity;
+
+            if (_affinityGroupService.isAdminControlledGroup(group)) {
+                if (accessType != null && accessType == AccessType.ModifyEntry
+                        && !_accountMgr.isRootAdmin(caller.getType())) {
+                    throw new PermissionDeniedException(caller + " does not have permission to operate with resource "
+                            + entity);
+                }
+            }
+
+            if (group.getAclType() == ACLType.Domain) {
+                if (!_affinityGroupService.isAffinityGroupAvailableInDomain(group.getId(), caller.getDomainId())) {
+                    throw new PermissionDeniedException("Affinity group is not available in domain id="
+                            + caller.getDomainId());
+                } else {
+                    return true;
+                }
+            } else {
+                //acl_type account 
+                if (caller.getId() != group.getAccountId()) {
+                      throw new PermissionDeniedException(caller
+                      + " does not have permission to operate with resource " + entity);
+                }
+
+            }
+
+        }
+
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/server/src/com/cloud/acl/DomainChecker.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/acl/DomainChecker.java b/server/src/com/cloud/acl/DomainChecker.java
index 94cdfd1..78ebe6e 100755
--- a/server/src/com/cloud/acl/DomainChecker.java
+++ b/server/src/com/cloud/acl/DomainChecker.java
@@ -21,6 +21,7 @@ import javax.inject.Inject;
 
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.affinity.AffinityGroup;
 import org.apache.cloudstack.api.BaseCmd;
 import org.springframework.stereotype.Component;
 
@@ -121,6 +122,8 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
             return true;
         } else if (entity instanceof Network && accessType != null && accessType == AccessType.UseNetwork) {
             _networkMgr.checkNetworkPermissions(caller, (Network) entity);
+        } else if (entity instanceof AffinityGroup) {
+            return false;
         } else {
             if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) {
                 Account account = _accountDao.findById(entity.getAccountId());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/server/src/com/cloud/api/query/QueryManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java
index 8739ac8..dab3c2a 100644
--- a/server/src/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/com/cloud/api/query/QueryManagerImpl.java
@@ -27,8 +27,11 @@ import java.util.Set;
 import javax.ejb.Local;
 import javax.inject.Inject;
 
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
 import org.apache.cloudstack.affinity.AffinityGroupResponse;
 import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
 import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
 import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
 import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
@@ -135,6 +138,8 @@ import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.PermissionDeniedException;
 import com.cloud.ha.HighAvailabilityManager;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.network.dao.NetworkDomainVO;
+import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.security.SecurityGroupVMMapVO;
 import com.cloud.network.security.dao.SecurityGroupVMMapDao;
 import com.cloud.org.Grouping;
@@ -166,6 +171,7 @@ import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
 import com.cloud.user.AccountVO;
+import com.cloud.user.DomainManager;
 import com.cloud.user.UserContext;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.DateUtil;
@@ -315,6 +321,12 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
     @Inject
     private DedicatedResourceDao _dedicatedDao;
 
+    @Inject
+    DomainManager _domainMgr;
+
+    @Inject
+    AffinityGroupDomainMapDao _affinityGroupDomainMapDao;
+
     /*
      * (non-Javadoc)
      *
@@ -3008,6 +3020,58 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
         ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
 
         Filter searchFilter = new Filter(AffinityGroupJoinVO.class, "id", true, startIndex, pageSize);
+        SearchCriteria<AffinityGroupJoinVO> sc = buildAffinityGroupSearchCriteria(domainId, isRecursive,
+                permittedAccounts, listProjectResourcesCriteria, affinityGroupId, affinityGroupName, affinityGroupType);
+        
+        Pair<List<AffinityGroupJoinVO>, Integer> uniqueGroupsPair = _affinityGroupJoinDao.searchAndCount(sc,
+                searchFilter);
+        // search group details by ids
+        List<AffinityGroupJoinVO> vrs = new ArrayList<AffinityGroupJoinVO>();
+        Integer count = uniqueGroupsPair.second();
+        if (count.intValue() != 0) {
+            List<AffinityGroupJoinVO> uniqueGroups = uniqueGroupsPair.first();
+            Long[] vrIds = new Long[uniqueGroups.size()];
+            int i = 0;
+            for (AffinityGroupJoinVO v : uniqueGroups) {
+                vrIds[i++] = v.getId();
+            }
+            vrs = _affinityGroupJoinDao.searchByIds(vrIds);
+        }
+
+        if (!permittedAccounts.isEmpty()) {
+            // add domain level affinity groups
+            if (domainId != null) {
+                SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive,
+                        new ArrayList<Long>(), listProjectResourcesCriteria, affinityGroupId, affinityGroupName,
+                        affinityGroupType);
+                vrs.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, domainId));
+            } else {
+
+                for (Long permAcctId : permittedAccounts) {
+                    Account permittedAcct = _accountDao.findById(permAcctId);
+                    SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(
+                            null, isRecursive, new ArrayList<Long>(),
+                            listProjectResourcesCriteria, affinityGroupId, affinityGroupName, affinityGroupType);
+
+                    vrs.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, permittedAcct.getDomainId()));
+                }
+            }
+        } else if (((permittedAccounts.isEmpty()) && (domainId != null) && isRecursive)) {
+            // list all domain level affinity groups for the domain admin case
+            SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive,
+                    new ArrayList<Long>(), listProjectResourcesCriteria, affinityGroupId, affinityGroupName,
+                    affinityGroupType);
+            vrs.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, domainId));
+        }
+
+        return new Pair<List<AffinityGroupJoinVO>, Integer>(vrs, vrs.size());
+
+    }
+
+    private SearchCriteria<AffinityGroupJoinVO> buildAffinityGroupSearchCriteria(Long domainId, boolean isRecursive,
+            List<Long> permittedAccounts, ListProjectResourcesCriteria listProjectResourcesCriteria,
+            Long affinityGroupId, String affinityGroupName, String affinityGroupType) {
+
         SearchBuilder<AffinityGroupJoinVO> groupSearch = _affinityGroupJoinDao.createSearchBuilder();
         _accountMgr.buildACLViewSearchBuilder(groupSearch, domainId, isRecursive, permittedAccounts,
                 listProjectResourcesCriteria);
@@ -3031,22 +3095,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
             sc.addAnd("type", SearchCriteria.Op.EQ, affinityGroupType);
         }
 
-        Pair<List<AffinityGroupJoinVO>, Integer> uniqueGroupsPair = _affinityGroupJoinDao.searchAndCount(sc,
-                searchFilter);
-        // search group details by ids
-        Integer count = uniqueGroupsPair.second();
-        if (count.intValue() == 0) {
-            // empty result
-            return uniqueGroupsPair;
-        }
-        List<AffinityGroupJoinVO> uniqueGroups = uniqueGroupsPair.first();
-        Long[] vrIds = new Long[uniqueGroups.size()];
-        int i = 0;
-        for (AffinityGroupJoinVO v : uniqueGroups) {
-            vrIds[i++] = v.getId();
-        }
-        List<AffinityGroupJoinVO> vrs = _affinityGroupJoinDao.searchByIds(vrIds);
-        return new Pair<List<AffinityGroupJoinVO>, Integer>(vrs, count);
+        return sc;
 
     }
 
@@ -3068,6 +3117,47 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
         return new Pair<List<AffinityGroupJoinVO>, Integer>(ags, count);
     }
 
+    private List<AffinityGroupJoinVO> listDomainLevelAffinityGroups(
+            SearchCriteria<AffinityGroupJoinVO> sc, Filter searchFilter, long domainId) {
+        List<Long> affinityGroupIds = new ArrayList<Long>();
+        Set<Long> allowedDomains = _domainMgr.getDomainParentIds(domainId);
+        List<AffinityGroupDomainMapVO> maps = _affinityGroupDomainMapDao.listByDomain(allowedDomains.toArray());
+
+        for (AffinityGroupDomainMapVO map : maps) {
+            boolean subdomainAccess = map.isSubdomainAccess();
+            if (map.getDomainId() == domainId || subdomainAccess) {
+                affinityGroupIds.add(map.getAffinityGroupId());
+            }
+        }
+
+        if (!affinityGroupIds.isEmpty()) {
+            SearchCriteria<AffinityGroupJoinVO> domainSC = _affinityGroupJoinDao.createSearchCriteria();
+            domainSC.addAnd("id", SearchCriteria.Op.IN, affinityGroupIds.toArray());
+            domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString());
+
+            sc.addAnd("id", SearchCriteria.Op.SC, domainSC);
+
+            Pair<List<AffinityGroupJoinVO>, Integer> uniqueGroupsPair = _affinityGroupJoinDao.searchAndCount(sc,
+                    searchFilter);
+            // search group by ids
+            Integer count = uniqueGroupsPair.second();
+            if (count.intValue() == 0) {
+                // empty result
+                return new ArrayList<AffinityGroupJoinVO>();
+            }
+            List<AffinityGroupJoinVO> uniqueGroups = uniqueGroupsPair.first();
+            Long[] vrIds = new Long[uniqueGroups.size()];
+            int i = 0;
+            for (AffinityGroupJoinVO v : uniqueGroups) {
+                vrIds[i++] = v.getId();
+            }
+            List<AffinityGroupJoinVO> vrs = _affinityGroupJoinDao.searchByIds(vrIds);
+            return vrs;
+        } else {
+            return new ArrayList<AffinityGroupJoinVO>();
+        }
+    }
+
     @Override
     public List<ResourceDetailResponse> listResource(ListResourceDetailsCmd cmd) {
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java b/server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java
index 1c0dc2c..ae63a8a 100644
--- a/server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java
+++ b/server/src/com/cloud/api/query/vo/AffinityGroupJoinVO.java
@@ -23,6 +23,8 @@ import javax.persistence.Enumerated;
 import javax.persistence.Id;
 import javax.persistence.Table;
 
+import org.apache.cloudstack.acl.ControlledEntity;
+
 import com.cloud.vm.VirtualMachine;
 
 @Entity
@@ -85,6 +87,10 @@ public class AffinityGroupJoinVO extends BaseViewVO implements ControlledViewEnt
     @Enumerated(value = EnumType.STRING)
     protected VirtualMachine.State vmState = null;
 
+    @Column(name = "acl_type")
+    @Enumerated(value = EnumType.STRING)
+    ControlledEntity.ACLType aclType;
+
 
     public AffinityGroupJoinVO() {
     }
@@ -256,4 +262,14 @@ public class AffinityGroupJoinVO extends BaseViewVO implements ControlledViewEnt
         // TODO Auto-generated method stub
         return null;
     }
+
+    public ControlledEntity.ACLType getAclType() {
+        return aclType;
+    }
+
+    public void setAclType(ControlledEntity.ACLType aclType) {
+        this.aclType = aclType;
+    }
+
 }
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/server/src/com/cloud/user/AccountManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java
index 0f4bdcd..71a2ae7 100755
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -41,6 +41,7 @@ import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.acl.SecurityChecker;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.affinity.AffinityGroup;
 import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
 import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd;
 import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd;
@@ -389,7 +390,9 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
                 Account account = ApiDBUtils.findAccountById(entity.getAccountId());
                 domainId = account != null ? account.getDomainId() : -1;
             }
-            if (entity.getAccountId() != -1 && domainId != -1 && !(entity instanceof VirtualMachineTemplate) && !(accessType != null && accessType == AccessType.UseNetwork)) {
+            if (entity.getAccountId() != -1 && domainId != -1 && !(entity instanceof VirtualMachineTemplate)
+                    && !(accessType != null && accessType == AccessType.UseNetwork)
+                    && !(entity instanceof AffinityGroup)) {
                 List<ControlledEntity> toBeChecked = domains.get(entity.getDomainId());
                 // for templates, we don't have to do cross domains check
                 if (toBeChecked == null) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/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 10d21d7..f48a2af 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -2581,13 +2581,27 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
                             + " ,type: " + ag.getType() + " , Please try again after removing the affinity group");
                 } else {
                     // verify permissions
-                    _accountMgr.checkAccess(caller, null, true, owner, ag);
-                    // Root admin has access to both VM and AG by default, but
-                    // make sure the owner of these entities is same
-                    if (caller.getId() == Account.ACCOUNT_ID_SYSTEM || _accountMgr.isRootAdmin(caller.getType())) {
-                        if (ag.getAccountId() != owner.getAccountId()) {
-                            throw new PermissionDeniedException("Affinity Group " + ag
-                                    + " does not belong to the VM's account");
+                    if (ag.getAclType() == ACLType.Domain) {
+                        _accountMgr.checkAccess(caller, null, false, owner, ag);
+                        // Root admin has access to both VM and AG by default,
+                        // but
+                        // make sure the owner of these entities is same
+                        if (caller.getId() == Account.ACCOUNT_ID_SYSTEM || _accountMgr.isRootAdmin(caller.getType())) {
+                            if (!_affinityGroupService.isAffinityGroupAvailableInDomain(ag.getId(), owner.getDomainId())) {
+                                throw new PermissionDeniedException("Affinity Group " + ag
+                                        + " does not belong to the VM's domain");
+                            }
+                        }
+                    } else {
+                        _accountMgr.checkAccess(caller, null, true, owner, ag);
+                        // Root admin has access to both VM and AG by default,
+                        // but
+                        // make sure the owner of these entities is same
+                        if (caller.getId() == Account.ACCOUNT_ID_SYSTEM || _accountMgr.isRootAdmin(caller.getType())) {
+                            if (ag.getAccountId() != owner.getAccountId()) {
+                                throw new PermissionDeniedException("Affinity Group " + ag
+                                        + " does not belong to the VM's account");
+                            }
                         }
                     }
                 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/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 ad43581..bca15ad 100644
--- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java
+++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java
@@ -20,27 +20,37 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.Map.Entry;
 
 import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
 import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
 import org.apache.log4j.Logger;
 import org.springframework.context.annotation.Primary;
 
 
 import com.cloud.deploy.DeploymentPlanner;
+import com.cloud.domain.DomainVO;
+import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.PermissionDeniedException;
 import com.cloud.exception.ResourceInUseException;
+import com.cloud.network.Network;
+import com.cloud.network.dao.NetworkDomainVO;
 import com.cloud.network.security.SecurityGroup;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
+import com.cloud.user.DomainManager;
 import com.cloud.user.UserContext;
 import com.cloud.uservm.UserVm;
 import com.cloud.utils.Pair;
@@ -78,8 +88,17 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
     AffinityGroupVMMapDao _affinityGroupVMMapDao;
 
     @Inject
+    AffinityGroupDomainMapDao _affinityGroupDomainMapDao;
+
+    @Inject
     private UserVmDao _userVmDao;
 
+    @Inject
+    DomainDao _domainDao;
+
+    @Inject
+    DomainManager _domainMgr;
+
     protected List<AffinityGroupProcessor> _affinityProcessors;
 
     public List<AffinityGroupProcessor> getAffinityGroupProcessors() {
@@ -90,20 +109,13 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
         this._affinityProcessors = affinityProcessors;
     }
 
+    @DB
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_AFFINITY_GROUP_CREATE, eventDescription = "Creating Affinity Group", create = true)
     public AffinityGroup createAffinityGroup(String account, Long domainId, String affinityGroupName,
             String affinityGroupType, String description) {
 
         Account caller = UserContext.current().getCaller();
-        Account owner = _accountMgr.finalizeOwner(caller, account, domainId, null);
-
-        if (_affinityGroupDao.isNameInUse(owner.getAccountId(), owner.getDomainId(), affinityGroupName)) {
-            throw new InvalidParameterValueException("Unable to create affinity group, a group with name "
-                    + affinityGroupName
-                    + " already exisits.");
-        }
-
 
         //validate the affinityGroupType
         Map<String, AffinityGroupProcessor> typeProcessorMap = getAffinityTypeToProcessorMap();
@@ -117,14 +129,65 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
                     "Unable to create affinity group, no Affinity Group Types configured");
         }
 
-        if (domainId == null) {
-            domainId = owner.getDomainId();
+        AffinityGroupProcessor processor = typeProcessorMap.get(affinityGroupType);
+
+        if (processor.isAdminControlledGroup() && !_accountMgr.isRootAdmin(caller.getType())) {
+            throw new PermissionDeniedException("Cannot create the affinity group");
         }
 
-        AffinityGroupVO group = new AffinityGroupVO(affinityGroupName, affinityGroupType, description, domainId,
-                owner.getId());
+        ControlledEntity.ACLType aclType = null;
+        Account owner = null;
+
+        if (account != null && domainId != null) {
+
+            owner = _accountMgr.finalizeOwner(caller, account, domainId, null);
+            aclType = ControlledEntity.ACLType.Account;
+
+        } else if (domainId != null && account == null) {
+
+            if (!_accountMgr.isRootAdmin(caller.getType())) {
+                // non root admin need to pass both account and domain
+                throw new InvalidParameterValueException(
+                        "Unable to create affinity group, account name must be passed with the domainId");
+            } else if (!processor.canBeSharedDomainWide()) {
+                // cannot be domain level
+                throw new InvalidParameterValueException("Unable to create affinity group, account name is needed");
+            }
+
+            DomainVO domain = _domainDao.findById(domainId);
+            if (domain == null) {
+                throw new InvalidParameterValueException("Unable to find domain by specified id");
+            }
+            _accountMgr.checkAccess(caller, domain);
+
+            // domain level group, owner is SYSTEM.
+            owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM);
+            aclType = ControlledEntity.ACLType.Domain;
+
+        } else {
+            owner = caller;
+            aclType = ControlledEntity.ACLType.Account;
+        }
+
+        if (_affinityGroupDao.isNameInUse(owner.getAccountId(), owner.getDomainId(), affinityGroupName)) {
+            throw new InvalidParameterValueException("Unable to create affinity group, a group with name "
+                    + affinityGroupName + " already exisits.");
+        }
+
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+        
+        AffinityGroupVO group = new AffinityGroupVO(affinityGroupName, affinityGroupType, description, owner.getDomainId(),
+                owner.getId(), aclType);
         _affinityGroupDao.persist(group);
 
+        if (domainId != null && aclType == ACLType.Domain) {
+            AffinityGroupDomainMapVO domainMap = new AffinityGroupDomainMapVO(group.getId(), domainId, false);
+            _affinityGroupDomainMapDao.persist(domainMap);
+        }
+
+        txn.commit();
+
         if (s_logger.isDebugEnabled()) {
             s_logger.debug("Created affinity group =" + affinityGroupName);
         }
@@ -132,6 +195,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
         return group;
     }
 
+
     @DB
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_AFFINITY_GROUP_DELETE, eventDescription = "Deleting affinity group")
@@ -161,7 +225,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
             affinityGroupId = group.getId();
         }
         // check permissions
-        _accountMgr.checkAccess(caller, null, true, group);
+        _accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, group);
 
         final Transaction txn = Transaction.currentTxn();
         txn.start();
@@ -249,12 +313,18 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
 
     @Override
     public List<String> listAffinityGroupTypes() {
+        Account caller = UserContext.current().getCaller();
+
         List<String> types = new ArrayList<String>();
         Map<String, AffinityGroupProcessor> componentMap = ComponentContext.getComponentsOfType(AffinityGroupProcessor.class);
 
         if (componentMap.size() > 0) {
             for (Entry<String, AffinityGroupProcessor> entry : componentMap.entrySet()) {
-                types.add(entry.getValue().getType());
+                AffinityGroupProcessor processor = entry.getValue();
+                if (processor.isAdminControlledGroup() && !_accountMgr.isRootAdmin(caller.getType())) {
+                    continue;
+                }
+                types.add(processor.getType());
             }
 
         }
@@ -275,6 +345,23 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
     }
 
     @Override
+    public boolean isAdminControlledGroup(AffinityGroup group) {
+
+        if (group != null) {
+            String affinityGroupType = group.getType();
+            Map<String, AffinityGroupProcessor> typeProcessorMap = getAffinityTypeToProcessorMap();
+            if (typeProcessorMap != null && !typeProcessorMap.isEmpty()) {
+                AffinityGroupProcessor processor = typeProcessorMap.get(affinityGroupType);
+                if (processor != null) {
+                    return processor.isAdminControlledGroup();
+                }
+            }
+        }
+        return false;
+
+    }
+
+    @Override
     public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
         _name = name;
         VirtualMachine.State.getStateMachine().registerListener(this);
@@ -379,4 +466,29 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
         return false;
     }
 
+    @Override
+    public boolean isAffinityGroupAvailableInDomain(long affinityGroupId, long domainId) {
+        Long groupDomainId = null;
+
+        AffinityGroupDomainMapVO domainMap = _affinityGroupDomainMapDao.findByAffinityGroup(affinityGroupId);
+        if (domainMap == null) {
+            return false;
+        } else {
+            groupDomainId = domainMap.getDomainId();
+        }
+
+        if (domainId == groupDomainId.longValue()) {
+            return true;
+        }
+
+        if (domainMap.subdomainAccess) {
+            Set<Long> parentDomains = _domainMgr.getDomainParentIds(domainId);
+            if (parentDomains.contains(groupDomainId)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java
----------------------------------------------------------------------
diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java
index 8c1c114..7e21c09 100644
--- a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java
+++ b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java
@@ -32,7 +32,9 @@ import java.util.List;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
 import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
 import org.apache.cloudstack.test.utils.SpringUtils;
 import org.junit.Before;
@@ -53,6 +55,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 import org.springframework.test.context.support.AnnotationConfigContextLoader;
 
 import com.cloud.dc.dao.DedicatedResourceDao;
+import com.cloud.domain.dao.DomainDao;
 import com.cloud.event.ActionEventUtils;
 import com.cloud.event.EventVO;
 import com.cloud.event.dao.EventDao;
@@ -63,6 +66,7 @@ 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.UserContext;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.component.ComponentContext;
@@ -132,7 +136,8 @@ public class AffinityApiUnitTest {
         when(_processor.getType()).thenReturn("mock");
         when(_accountDao.findByIdIncludingRemoved(0L)).thenReturn(acct);
 
-        AffinityGroupVO group = new AffinityGroupVO("group1", "mock", "mock group", domainId, 200L);
+        AffinityGroupVO group = new AffinityGroupVO("group1", "mock", "mock group", domainId, 200L,
+                ControlledEntity.ACLType.Account);
         Mockito.when(_affinityGroupDao.persist(Mockito.any(AffinityGroupVO.class))).thenReturn(group);
         Mockito.when(_affinityGroupDao.findById(Mockito.anyLong())).thenReturn(group);
         Mockito.when(_affinityGroupDao.findByAccountAndName(Mockito.anyLong(), Mockito.anyString())).thenReturn(group);
@@ -235,6 +240,11 @@ public class AffinityApiUnitTest {
         }
 
         @Bean
+        public DomainManager domainManager() {
+            return Mockito.mock(DomainManager.class);
+        }
+
+        @Bean
         public EventDao eventDao() {
             return Mockito.mock(EventDao.class);
         }
@@ -247,6 +257,16 @@ public class AffinityApiUnitTest {
         @Bean
         public UserDao userDao() {
             return Mockito.mock(UserDao.class);
+        }
+
+        @Bean
+        public AffinityGroupDomainMapDao affinityGroupDomainMapDao() {
+            return Mockito.mock(AffinityGroupDomainMapDao.class);
+        }
+
+        @Bean
+        public DomainDao domainDao() {
+            return Mockito.mock(DomainDao.class);
         }
 
         public static class Library implements TypeFilter {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b965032b/setup/db/db/schema-412to420.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-412to420.sql b/setup/db/db/schema-412to420.sql
index f00ee22..9cd2b9c 100644
--- a/setup/db/db/schema-412to420.sql
+++ b/setup/db/db/schema-412to420.sql
@@ -412,6 +412,7 @@ CREATE TABLE `cloud`.`affinity_group` (
   `description` varchar(4096) NULL,
   `domain_id` bigint unsigned NOT NULL,
   `account_id` bigint unsigned NOT NULL,
+  `acl_type` varchar(15) NOT NULL COMMENT 'ACL access type. can be Account/Domain',
   UNIQUE (`name`, `account_id`),
   PRIMARY KEY  (`id`),
   CONSTRAINT `fk_affinity_group__account_id` FOREIGN KEY(`account_id`) REFERENCES `account`(`id`),
@@ -419,6 +420,7 @@ CREATE TABLE `cloud`.`affinity_group` (
   CONSTRAINT `uc_affinity_group__uuid` UNIQUE (`uuid`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
+
 CREATE TABLE `cloud`.`affinity_group_vm_map` (
   `id` bigint unsigned NOT NULL auto_increment,
   `affinity_group_id` bigint unsigned NOT NULL,
@@ -428,7 +430,15 @@ CREATE TABLE `cloud`.`affinity_group_vm_map` (
   CONSTRAINT `fk_affinity_group_vm_map___instance_id` FOREIGN KEY(`instance_id`) REFERENCES `user_vm` (`id`) ON DELETE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
-
+CREATE TABLE `cloud`.`affinity_group_domain_map` (
+  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `domain_id` bigint unsigned NOT NULL COMMENT 'domain id',
+  `affinity_group_id` bigint unsigned NOT NULL COMMENT 'affinity group id',
+  `subdomain_access` int(1) unsigned COMMENT '1 if affinity group can be accessible from the subdomain',
+  PRIMARY KEY (`id`),
+  CONSTRAINT `fk_affinity_group_domain_map__domain_id` FOREIGN KEY (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE,
+  CONSTRAINT `fk_affinity_group_domain_map__affinity_group_id` FOREIGN KEY (`affinity_group_id`) REFERENCES `affinity_group`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 CREATE TABLE `cloud`.`dedicated_resources` (
   `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id',
@@ -898,6 +908,7 @@ CREATE VIEW `cloud`.`affinity_group_view` AS
         affinity_group.type type,
         affinity_group.description description,
         affinity_group.uuid uuid,
+		affinity_group.acl_type acl_type,
         account.id account_id,
         account.uuid account_uuid,
         account.account_name account_name,


Mime
View raw message