cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sate...@apache.org
Subject [27/50] [abbrv] git commit: updated refs/heads/vmware-datamodel to d07f875
Date Sun, 19 May 2013 12:05:58 GMT
Changes for implicitly dedicating a resource. It includes a following:
1. A new implicit planner which extends the functionality provided by FirstFitPlanner.
2. Implicit planner can be used in either strict or preferred mode. In strict mode it tries to deploy a vm of a given account on a host on which vms of the account are already running. If no such host is found it'll search for an empty host to service the request. Otherwise the deploy vm request fails.
3. In preferred mode, if a host which is running vms of the account or an empty host isn't found, the planner then tries to deploy on any other host provided it isn't running implicitly dedicated strict vms of any other account.
4. Updated the createServiceOffering api to configure the details for the planner that the service offering is using.
5. Made db changes to store the service offering details for the planner.
6. Unit tests for testing the implicit planner functionality.
7. Marvin test for validating the functionality.


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

Branch: refs/heads/vmware-datamodel
Commit: adbebc1892cf88df8c801291a88bc836c99b8c14
Parents: caf0dd2
Author: Devdeep Singh <devdeep@gmail.com>
Authored: Fri May 17 11:14:25 2013 +0530
Committer: Devdeep Singh <devdeep@gmail.com>
Committed: Fri May 17 11:40:31 2013 +0530

----------------------------------------------------------------------
 api/src/com/cloud/deploy/DeploymentPlanner.java    |    7 +
 .../org/apache/cloudstack/api/ApiConstants.java    |    1 +
 .../admin/offering/CreateServiceOfferingCmd.java   |   16 +
 client/pom.xml                                     |    5 +
 client/tomcatconf/applicationContext.xml.in        |    6 +-
 client/tomcatconf/componentContext.xml.in          |    1 +
 .../cloud/service/ServiceOfferingDetailsVO.java    |   73 ++
 .../src/com/cloud/service/ServiceOfferingVO.java   |   27 +
 .../com/cloud/service/dao/ServiceOfferingDao.java  |    2 +
 .../cloud/service/dao/ServiceOfferingDaoImpl.java  |   19 +-
 .../service/dao/ServiceOfferingDetailsDao.java     |   29 +
 .../service/dao/ServiceOfferingDetailsDaoImpl.java |   98 +++
 .../implicit-dedication/pom.xml                    |   29 +
 .../cloud/deploy/ImplicitDedicationPlanner.java    |  249 ++++++
 .../implicitplanner/ImplicitPlannerTest.java       |  586 +++++++++++++++
 plugins/pom.xml                                    |    1 +
 .../cloud/configuration/ConfigurationManager.java  |    3 +-
 .../configuration/ConfigurationManagerImpl.java    |   20 +-
 .../cloud/vpc/MockConfigurationManagerImpl.java    |    2 +-
 .../networkoffering/ChildTestConfiguration.java    |   27 +-
 setup/db/db/schema-410to420.sql                    |   11 +-
 .../integration/component/test_implicit_planner.py |  232 ++++++
 tools/marvin/marvin/integration/lib/base.py        |    4 +
 23 files changed, 1430 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/api/src/com/cloud/deploy/DeploymentPlanner.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/deploy/DeploymentPlanner.java b/api/src/com/cloud/deploy/DeploymentPlanner.java
index eb56a59..769da39 100644
--- a/api/src/com/cloud/deploy/DeploymentPlanner.java
+++ b/api/src/com/cloud/deploy/DeploymentPlanner.java
@@ -213,6 +213,13 @@ public interface DeploymentPlanner extends Adapter {
             _hostIds.add(hostId);
         }
 
+        public void addHostList(Collection<Long> hostList) {
+            if (_hostIds == null) {
+                _hostIds = new HashSet<Long>();
+            }
+            _hostIds.addAll(hostList);
+        }
+
         public boolean shouldAvoid(Host host) {
             if (_dcIds != null && _dcIds.contains(host.getDataCenterId())) {
                 return true;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 8d7739c..cf093bf 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -312,6 +312,7 @@ public class ApiConstants {
     public static final String ACCEPT = "accept";
     public static final String SORT_KEY = "sortkey";
     public static final String ACCOUNT_DETAILS = "accountdetails";
+    public static final String SERVICE_OFFERING_DETAILS = "serviceofferingdetails";
     public static final String SERVICE_PROVIDER_LIST = "serviceproviderlist";
     public static final String SERVICE_CAPABILITY_LIST = "servicecapabilitylist";
     public static final String CAN_CHOOSE_SERVICE_CAPABILITY = "canchooseservicecapability";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
index c155b70..4c54a4e 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
@@ -16,6 +16,9 @@
 // under the License.
 package org.apache.cloudstack.api.command.admin.offering;
 
+import java.util.Collection;
+import java.util.Map;
+
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
@@ -87,6 +90,9 @@ public class CreateServiceOfferingCmd extends BaseCmd {
     @Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "The deployment planner heuristics used to deploy a VM of this offering. If null, value of global config vm.deployment.planner is used")
     private String deploymentPlanner;
 
+    @Parameter(name = ApiConstants.SERVICE_OFFERING_DETAILS, type = CommandType.MAP, description = "details for planner, used to store specific parameters")
+    private Map<String, String> details;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -155,6 +161,16 @@ public class CreateServiceOfferingCmd extends BaseCmd {
         return deploymentPlanner;
     }
 
+    public Map<String, String> getDetails() {
+        if (details == null || details.isEmpty()) {
+            return null;
+        }
+
+        Collection<String> paramsCollection = details.values();
+        Map<String, String> params = (Map<String, String>)(paramsCollection.toArray())[0];
+        return params;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/client/pom.xml
----------------------------------------------------------------------
diff --git a/client/pom.xml b/client/pom.xml
index 197ba27..0c38ecb 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -133,6 +133,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-plugin-planner-implicit-dedication</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
       <artifactId>cloud-plugin-host-allocator-random</artifactId>
       <version>${project.version}</version>
     </dependency>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/client/tomcatconf/applicationContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in
index 1d1eca4..b500fde 100644
--- a/client/tomcatconf/applicationContext.xml.in
+++ b/client/tomcatconf/applicationContext.xml.in
@@ -370,7 +370,7 @@
   <bean id="vpnUserDaoImpl" class="com.cloud.network.dao.VpnUserDaoImpl" />
   <bean id="applicationLbRuleDaoImpl" class="org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDaoImpl" />
   <bean id="networkOfferingDetailsDaoImpl" class="com.cloud.offerings.dao.NetworkOfferingDetailsDaoImpl" />
-
+  <bean id="serviceOfferingDetailsDaoImpl" class="com.cloud.service.dao.ServiceOfferingDetailsDaoImpl"/>
 
   <!--
     Checkers
@@ -547,6 +547,10 @@
     <property name="name" value="UserConcentratedPodPlanner"/>
   </bean>
 
+  <bean id="ImplicitDedicationPlanner" class="com.cloud.deploy.ImplicitDedicationPlanner">
+    <property name="name" value="ImplicitDedicationPlanner"/>
+  </bean>
+
   <bean id="clusterBasedAgentLoadBalancerPlanner" class="com.cloud.cluster.agentlb.ClusterBasedAgentLoadBalancerPlanner">
     <property name="name" value="ClusterBasedAgentLoadBalancerPlanner"/>
   </bean>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/client/tomcatconf/componentContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in
index 8a45e5f..e946f44 100644
--- a/client/tomcatconf/componentContext.xml.in
+++ b/client/tomcatconf/componentContext.xml.in
@@ -156,6 +156,7 @@
           <ref bean="FirstFitPlanner" />
           <ref bean="UserDispersingPlanner" />
           <ref bean="UserConcentratedPodPlanner" />
+          <ref bean="ImplicitDedicationPlanner" />
 <!--
           <ref bean="BareMetalPlanner" />
 -->

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java b/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java
new file mode 100644
index 0000000..b005c73
--- /dev/null
+++ b/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.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 com.cloud.service;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="service_offering_details")
+public class ServiceOfferingDetailsVO implements InternalIdentity {
+    @Id
+    @GeneratedValue(strategy=GenerationType.IDENTITY)
+    @Column(name="id")
+    private long id;
+
+    @Column(name="service_offering_id")
+    private long serviceOfferingId;
+
+    @Column(name="name")
+    private String name;
+
+    @Column(name="value")
+    private String value;
+
+    protected ServiceOfferingDetailsVO() {
+    }
+
+    public ServiceOfferingDetailsVO(long serviceOfferingId, String name, String value) {
+        this.serviceOfferingId = serviceOfferingId;
+        this.name = name;
+        this.value = value;
+    }
+
+    public long getServiceOfferingId() {
+        return serviceOfferingId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public long getId() {
+        return id;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/engine/schema/src/com/cloud/service/ServiceOfferingVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/service/ServiceOfferingVO.java b/engine/schema/src/com/cloud/service/ServiceOfferingVO.java
index fd31d30..9a262c5 100755
--- a/engine/schema/src/com/cloud/service/ServiceOfferingVO.java
+++ b/engine/schema/src/com/cloud/service/ServiceOfferingVO.java
@@ -16,6 +16,8 @@
 // under the License.
 package com.cloud.service;
 
+import java.util.Map;
+
 import javax.persistence.Column;
 import javax.persistence.DiscriminatorValue;
 import javax.persistence.Entity;
@@ -71,6 +73,12 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
     @Column(name = "deployment_planner")
     private String deploymentPlanner = null;
 
+    // This is a delayed load value.  If the value is null,
+    // then this field has not been loaded yet.
+    // Call service offering dao to load it.
+    @Transient
+    Map<String, String> details;
+
     protected ServiceOfferingVO() {
         super();
     }
@@ -225,4 +233,23 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
         return deploymentPlanner;
     }
 
+    public Map<String, String> getDetails() {
+        return details;
+    }
+
+    public String getDetail(String name) {
+        assert (details != null) : "Did you forget to load the details?";
+
+        return details != null ? details.get(name) : null;
+    }
+
+    public void setDetail(String name, String value) {
+        assert (details != null) : "Did you forget to load the details?";
+
+        details.put(name, value);
+    }
+
+    public void setDetails(Map<String, String> details) {
+        this.details = details;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java
index 589de7c..7da7208 100644
--- a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java
+++ b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java
@@ -31,4 +31,6 @@ public interface ServiceOfferingDao extends GenericDao<ServiceOfferingVO, Long>
 	List<ServiceOfferingVO> findServiceOfferingByDomainId(Long domainId);
     List<ServiceOfferingVO> findSystemOffering(Long domainId, Boolean isSystem, String vm_type);
     ServiceOfferingVO persistDeafultServiceOffering(ServiceOfferingVO offering);
+    void loadDetails(ServiceOfferingVO serviceOffering);
+    void saveDetails(ServiceOfferingVO serviceOffering);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java
index 062103e..14b2abf 100644
--- a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java
+++ b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java
@@ -18,15 +18,16 @@ package com.cloud.service.dao;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 import javax.ejb.Local;
+import javax.inject.Inject;
 import javax.persistence.EntityExistsException;
 
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
 import com.cloud.service.ServiceOfferingVO;
-import com.cloud.storage.DiskOfferingVO;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.GenericDaoBase;
 import com.cloud.utils.db.SearchBuilder;
@@ -37,6 +38,8 @@ import com.cloud.utils.db.SearchCriteria;
 public class ServiceOfferingDaoImpl extends GenericDaoBase<ServiceOfferingVO, Long> implements ServiceOfferingDao {
     protected static final Logger s_logger = Logger.getLogger(ServiceOfferingDaoImpl.class);
 
+    @Inject protected ServiceOfferingDetailsDao detailsDao;
+
     protected final SearchBuilder<ServiceOfferingVO> UniqueNameSearch;
     protected final SearchBuilder<ServiceOfferingVO> ServiceOfferingsByDomainIdSearch;
     protected final SearchBuilder<ServiceOfferingVO> SystemServiceOffering;
@@ -154,4 +157,18 @@ public class ServiceOfferingDaoImpl extends GenericDaoBase<ServiceOfferingVO, Lo
 
         return update(id, offering);
     }
+
+    @Override
+    public void loadDetails(ServiceOfferingVO serviceOffering) {
+        Map<String, String> details = detailsDao.findDetails(serviceOffering.getId());
+        serviceOffering.setDetails(details);
+    }
+
+    @Override
+    public void saveDetails(ServiceOfferingVO serviceOffering) {
+        Map<String, String> details = serviceOffering.getDetails();
+        if (details != null) {
+            detailsDao.persist(serviceOffering.getId(), details);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/engine/schema/src/com/cloud/service/dao/ServiceOfferingDetailsDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDetailsDao.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDetailsDao.java
new file mode 100644
index 0000000..3816910
--- /dev/null
+++ b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDetailsDao.java
@@ -0,0 +1,29 @@
+// 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.service.dao;
+
+import java.util.Map;
+
+import com.cloud.service.ServiceOfferingDetailsVO;
+import com.cloud.utils.db.GenericDao;
+
+public interface ServiceOfferingDetailsDao extends GenericDao<ServiceOfferingDetailsVO, Long> {
+    Map<String, String> findDetails(long serviceOfferingId);
+    void persist(long serviceOfferingId, Map<String, String> details);
+    ServiceOfferingDetailsVO findDetail(long serviceOfferingId, String name);
+    void deleteDetails(long serviceOfferingId);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/engine/schema/src/com/cloud/service/dao/ServiceOfferingDetailsDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDetailsDaoImpl.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDetailsDaoImpl.java
new file mode 100644
index 0000000..91d736a
--- /dev/null
+++ b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDetailsDaoImpl.java
@@ -0,0 +1,98 @@
+// 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.service.dao;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+
+import org.springframework.stereotype.Component;
+
+import com.cloud.service.ServiceOfferingDetailsVO;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+
+@Component
+@Local(value=ServiceOfferingDetailsDao.class)
+public class ServiceOfferingDetailsDaoImpl extends GenericDaoBase<ServiceOfferingDetailsVO, Long>
+        implements ServiceOfferingDetailsDao {
+    protected final SearchBuilder<ServiceOfferingDetailsVO> ServiceOfferingSearch;
+    protected final SearchBuilder<ServiceOfferingDetailsVO> DetailSearch;
+
+    public ServiceOfferingDetailsDaoImpl() {
+        ServiceOfferingSearch = createSearchBuilder();
+        ServiceOfferingSearch.and("serviceOfferingId", ServiceOfferingSearch.entity().getServiceOfferingId(), SearchCriteria.Op.EQ);
+        ServiceOfferingSearch.done();
+
+        DetailSearch = createSearchBuilder();
+        DetailSearch.and("serviceOfferingId", DetailSearch.entity().getServiceOfferingId(), SearchCriteria.Op.EQ);
+        DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ);
+        DetailSearch.done();
+    }
+
+    @Override
+    public ServiceOfferingDetailsVO findDetail(long serviceOfferingId, String name) {
+        SearchCriteria<ServiceOfferingDetailsVO> sc = DetailSearch.create();
+        sc.setParameters("serviceOfferingId", serviceOfferingId);
+        sc.setParameters("name", name);
+        ServiceOfferingDetailsVO detail = findOneIncludingRemovedBy(sc);
+        return detail;
+    }
+
+    @Override
+    public Map<String, String> findDetails(long serviceOfferingId) {
+        SearchCriteria<ServiceOfferingDetailsVO> sc = ServiceOfferingSearch.create();
+        sc.setParameters("serviceOfferingId", serviceOfferingId);
+        List<ServiceOfferingDetailsVO> results = search(sc, null);
+        Map<String, String> details = new HashMap<String, String>(results.size());
+        for (ServiceOfferingDetailsVO result : results) {
+            details.put(result.getName(), result.getValue());
+        }
+
+        return details;
+    }
+
+    @Override
+    public void deleteDetails(long serviceOfferingId) {
+        SearchCriteria sc = ServiceOfferingSearch.create();
+        sc.setParameters("serviceOfferingId", serviceOfferingId);
+        List<ServiceOfferingDetailsVO> results = search(sc, null);
+        for (ServiceOfferingDetailsVO result : results) {
+            remove(result.getId());
+        }
+    }
+
+    @Override
+    public void persist(long serviceOfferingId, Map<String, String> details) {
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+        SearchCriteria<ServiceOfferingDetailsVO> sc = ServiceOfferingSearch.create();
+        sc.setParameters("serviceOfferingId", serviceOfferingId);
+        expunge(sc);
+
+        for (Map.Entry<String, String> detail : details.entrySet()) {
+            String value = detail.getValue();
+            ServiceOfferingDetailsVO vo = new ServiceOfferingDetailsVO(serviceOfferingId, detail.getKey(), value);
+            persist(vo);
+        }
+        txn.commit();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/plugins/deployment-planners/implicit-dedication/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/deployment-planners/implicit-dedication/pom.xml b/plugins/deployment-planners/implicit-dedication/pom.xml
new file mode 100644
index 0000000..1855592
--- /dev/null
+++ b/plugins/deployment-planners/implicit-dedication/pom.xml
@@ -0,0 +1,29 @@
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cloud-plugin-planner-implicit-dedication</artifactId>
+  <name>Apache CloudStack Plugin - Implicit Dedication Planner</name>
+  <parent>
+    <groupId>org.apache.cloudstack</groupId>
+    <artifactId>cloudstack-plugins</artifactId>
+    <version>4.2.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+</project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/plugins/deployment-planners/implicit-dedication/src/com/cloud/deploy/ImplicitDedicationPlanner.java
----------------------------------------------------------------------
diff --git a/plugins/deployment-planners/implicit-dedication/src/com/cloud/deploy/ImplicitDedicationPlanner.java b/plugins/deployment-planners/implicit-dedication/src/com/cloud/deploy/ImplicitDedicationPlanner.java
new file mode 100644
index 0000000..d47d8f5
--- /dev/null
+++ b/plugins/deployment-planners/implicit-dedication/src/com/cloud/deploy/ImplicitDedicationPlanner.java
@@ -0,0 +1,249 @@
+// 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.deploy;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.configuration.Config;
+import com.cloud.exception.InsufficientServerCapacityException;
+import com.cloud.host.HostVO;
+import com.cloud.resource.ResourceManager;
+import com.cloud.service.ServiceOfferingVO;
+import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.service.dao.ServiceOfferingDetailsDao;
+import com.cloud.user.Account;
+import com.cloud.utils.DateUtil;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+
+@Local(value=DeploymentPlanner.class)
+public class ImplicitDedicationPlanner extends FirstFitPlanner implements DeploymentClusterPlanner {
+
+    private static final Logger s_logger = Logger.getLogger(ImplicitDedicationPlanner.class);
+
+    @Inject
+    private ServiceOfferingDao serviceOfferingDao;
+    @Inject
+    private ServiceOfferingDetailsDao serviceOfferingDetailsDao;
+    @Inject
+    private ResourceManager resourceMgr;
+
+    private int capacityReleaseInterval;
+
+    @Override
+    public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
+        super.configure(name, params);
+        capacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), 3600);
+        return true;
+    }
+
+    @Override
+    public List<Long> orderClusters(VirtualMachineProfile<? extends VirtualMachine> vmProfile,
+            DeploymentPlan plan, ExcludeList avoid) throws InsufficientServerCapacityException {
+        List<Long> clusterList = super.orderClusters(vmProfile, plan, avoid);
+        Set<Long> hostsToAvoid = avoid.getHostsToAvoid();
+        Account account = vmProfile.getOwner();
+
+        if (clusterList == null || clusterList.isEmpty()) {
+            return clusterList;
+        }
+
+        // Check if strict or preferred mode should be used.
+        boolean preferred = isServiceOfferingUsingPlannerInPreferredMode(vmProfile.getServiceOfferingId());
+
+        // Get the list of all the hosts in the given clusters
+        List<Long> allHosts = new ArrayList<Long>();
+        for (Long cluster : clusterList) {
+            List<HostVO> hostsInCluster = resourceMgr.listAllHostsInCluster(cluster);
+            for (HostVO hostVO : hostsInCluster) {
+                allHosts.add(hostVO.getId());
+            }
+        }
+
+        // Go over all the hosts in the cluster and get a list of
+        // 1. All empty hosts, not running any vms.
+        // 2. Hosts running vms for this account and created by a service offering which uses an
+        //    implicit dedication planner.
+        // 3. Hosts running vms created by implicit planner and in strict mode of other accounts.
+        // 4. Hosts running vms from other account or from this account but created by a service offering which uses
+        //    any planner besides implicit.
+        Set<Long> emptyHosts = new HashSet<Long>();
+        Set<Long> hostRunningVmsOfAccount = new HashSet<Long>();
+        Set<Long> hostRunningStrictImplicitVmsOfOtherAccounts = new HashSet<Long>();
+        Set<Long> allOtherHosts = new HashSet<Long>();
+        for (Long host : allHosts) {
+            List<UserVmVO> userVms = getVmsOnHost(host);
+            if (userVms == null || userVms.isEmpty()) {
+                emptyHosts.add(host);
+            } else if (checkHostSuitabilityForImplicitDedication(account.getAccountId(), userVms)) {
+                hostRunningVmsOfAccount.add(host);
+            } else if (checkIfAllVmsCreatedInStrictMode(account.getAccountId(), userVms)) {
+                hostRunningStrictImplicitVmsOfOtherAccounts.add(host);
+            } else {
+                allOtherHosts.add(host);
+            }
+        }
+
+        // Hosts running vms of other accounts created by ab implicit planner in strict mode should always be avoided.
+        avoid.addHostList(hostRunningStrictImplicitVmsOfOtherAccounts);
+
+        if (!hostRunningVmsOfAccount.isEmpty() && (hostsToAvoid == null ||
+                !hostsToAvoid.containsAll(hostRunningVmsOfAccount))) {
+            // Check if any of hosts that are running implicit dedicated vms are available (not in avoid list).
+            // If so, we'll try and use these hosts.
+            avoid.addHostList(emptyHosts);
+            avoid.addHostList(allOtherHosts);
+            clusterList = getUpdatedClusterList(clusterList, avoid.getHostsToAvoid());
+        } else if (!emptyHosts.isEmpty() && (hostsToAvoid == null || !hostsToAvoid.containsAll(emptyHosts))) {
+            // If there aren't implicit resources try on empty hosts
+            avoid.addHostList(allOtherHosts);
+            clusterList = getUpdatedClusterList(clusterList, avoid.getHostsToAvoid());
+        } else if (!preferred) {
+            // If in strict mode, there is nothing else to try.
+            clusterList = null;
+        } else {
+            // If in preferred mode, check if hosts are available to try, otherwise return an empty cluster list.
+            if (!allOtherHosts.isEmpty() && (hostsToAvoid == null || !hostsToAvoid.containsAll(allOtherHosts))) {
+                clusterList = getUpdatedClusterList(clusterList, avoid.getHostsToAvoid());
+            } else {
+                clusterList = null;
+            }
+        }
+
+        return clusterList;
+    }
+
+    private List<UserVmVO> getVmsOnHost(long hostId) {
+        List<UserVmVO> vms = _vmDao.listUpByHostId(hostId);
+        List<UserVmVO> vmsByLastHostId = _vmDao.listByLastHostId(hostId);
+        if (vmsByLastHostId.size() > 0) {
+            // check if any VMs are within skip.counting.hours, if yes we have to consider the host.
+            for (UserVmVO stoppedVM : vmsByLastHostId) {
+                long secondsSinceLastUpdate = (DateUtil.currentGMTTime().getTime() - stoppedVM.getUpdateTime()
+                        .getTime()) / 1000;
+                if (secondsSinceLastUpdate < capacityReleaseInterval) {
+                    vms.add(stoppedVM);
+                }
+            }
+        }
+
+        return vms;
+    }
+
+    private boolean checkHostSuitabilityForImplicitDedication(Long accountId, List<UserVmVO> allVmsOnHost) {
+        boolean suitable = true;
+        for (UserVmVO vm : allVmsOnHost) {
+            if (vm.getAccountId() != accountId) {
+                s_logger.info("Host " + vm.getHostId() + " found to be unsuitable for implicit dedication as it is " +
+                        "running instances of another account");
+                suitable = false;
+                break;
+            } else {
+                if (!isImplicitPlannerUsedByOffering(vm.getServiceOfferingId())) {
+                    s_logger.info("Host " + vm.getHostId() + " found to be unsuitable for implicit dedication as it " +
+                            "is running instances of this account which haven't been created using implicit dedication.");
+                    suitable = false;
+                    break;
+                }
+            }
+        }
+        return suitable;
+    }
+
+    private boolean checkIfAllVmsCreatedInStrictMode(Long accountId, List<UserVmVO> allVmsOnHost) {
+        boolean createdByImplicitStrict = true;
+        for (UserVmVO vm : allVmsOnHost) {
+            if (!isImplicitPlannerUsedByOffering(vm.getServiceOfferingId())) {
+                s_logger.info("Host " + vm.getHostId() + " found to be running a vm created by a planner other" +
+                        " than implicit.");
+                createdByImplicitStrict = false;
+                break;
+            } else if (isServiceOfferingUsingPlannerInPreferredMode(vm.getServiceOfferingId())) {
+                s_logger.info("Host " + vm.getHostId() + " found to be running a vm created by an implicit planner" +
+                        " in preferred mode.");
+                createdByImplicitStrict = false;
+                break;
+            }
+        }
+        return createdByImplicitStrict;
+    }
+
+    private boolean isImplicitPlannerUsedByOffering(long offeringId) {
+        boolean implicitPlannerUsed = false;
+        ServiceOfferingVO offering = serviceOfferingDao.findByIdIncludingRemoved(offeringId);
+        if (offering == null) {
+            s_logger.error("Couldn't retrieve the offering by the given id : " + offeringId);
+        } else {
+            String plannerName = offering.getDeploymentPlanner();
+            if (plannerName == null) {
+                plannerName = _globalDeploymentPlanner;
+            }
+
+            if (plannerName != null && this.getName().equals(plannerName)) {
+                implicitPlannerUsed = true;
+            }
+        }
+
+        return implicitPlannerUsed;
+    }
+
+    private boolean isServiceOfferingUsingPlannerInPreferredMode(long serviceOfferingId) {
+        boolean preferred = false;
+        Map<String, String> details = serviceOfferingDetailsDao.findDetails(serviceOfferingId);
+        if (details != null && !details.isEmpty()) {
+            String preferredAttribute = details.get("ImplicitDedicationMode");
+            if (preferredAttribute != null && preferredAttribute.equals("Preferred")) {
+                preferred = true;
+            }
+        }
+        return preferred;
+    }
+
+    private List<Long> getUpdatedClusterList(List<Long> clusterList, Set<Long> hostsSet) {
+        List<Long> updatedClusterList = new ArrayList<Long>();
+        for (Long cluster : clusterList) {
+            List<HostVO> hosts = resourceMgr.listAllHostsInCluster(cluster);
+            Set<Long> hostsInClusterSet = new HashSet<Long>();
+            for (HostVO host : hosts) {
+                hostsInClusterSet.add(host.getId());
+            }
+
+            if (!hostsSet.containsAll(hostsInClusterSet)) {
+                updatedClusterList.add(cluster);
+            }
+        }
+
+        return updatedClusterList;
+    }
+
+    @Override
+    public PlannerResourceUsage getResourceUsage() {
+        return PlannerResourceUsage.Dedicated;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/plugins/deployment-planners/implicit-dedication/test/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java
----------------------------------------------------------------------
diff --git a/plugins/deployment-planners/implicit-dedication/test/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java b/plugins/deployment-planners/implicit-dedication/test/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java
new file mode 100644
index 0000000..4450760
--- /dev/null
+++ b/plugins/deployment-planners/implicit-dedication/test/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java
@@ -0,0 +1,586 @@
+// 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.implicitplanner;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.test.utils.SpringUtils;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+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 com.cloud.capacity.CapacityManager;
+import com.cloud.capacity.CapacityVO;
+import com.cloud.capacity.dao.CapacityDao;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
+import com.cloud.deploy.DataCenterDeployment;
+import com.cloud.deploy.DeploymentPlanner.ExcludeList;
+import com.cloud.deploy.ImplicitDedicationPlanner;
+import com.cloud.exception.InsufficientServerCapacityException;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.resource.ResourceManager;
+import com.cloud.service.ServiceOfferingVO;
+import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.service.dao.ServiceOfferingDetailsDao;
+import com.cloud.storage.StorageManager;
+import com.cloud.storage.dao.DiskOfferingDao;
+import com.cloud.storage.dao.GuestOSCategoryDao;
+import com.cloud.storage.dao.GuestOSDao;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.UserContext;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.ComponentContext;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachineProfileImpl;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
+public class ImplicitPlannerTest {
+
+    @Inject
+    ImplicitDedicationPlanner planner = new ImplicitDedicationPlanner();
+    @Inject
+    HostDao hostDao;
+    @Inject
+    DataCenterDao dcDao;
+    @Inject
+    HostPodDao podDao;
+    @Inject
+    ClusterDao clusterDao;
+    @Inject
+    GuestOSDao guestOSDao;
+    @Inject
+    GuestOSCategoryDao guestOSCategoryDao;
+    @Inject
+    DiskOfferingDao diskOfferingDao;
+    @Inject
+    StoragePoolHostDao poolHostDao;
+    @Inject
+    UserVmDao vmDao;
+    @Inject
+    VMInstanceDao vmInstanceDao;
+    @Inject
+    VolumeDao volsDao;
+    @Inject
+    CapacityManager capacityMgr;
+    @Inject
+    ConfigurationDao configDao;
+    @Inject
+    PrimaryDataStoreDao storagePoolDao;
+    @Inject
+    CapacityDao capacityDao;
+    @Inject
+    AccountManager accountMgr;
+    @Inject
+    StorageManager storageMgr;
+    @Inject
+    DataStoreManager dataStoreMgr;
+    @Inject
+    ClusterDetailsDao clusterDetailsDao;
+    @Inject
+    ServiceOfferingDao serviceOfferingDao;
+    @Inject
+    ServiceOfferingDetailsDao serviceOfferingDetailsDao;
+    @Inject
+    ResourceManager resourceMgr;
+
+    private static long domainId = 5L;
+    long dataCenterId = 1L;
+    long accountId = 200L;
+    long offeringId = 12L;
+    int noOfCpusInOffering = 1;
+    int cpuSpeedInOffering = 500;
+    int ramInOffering = 512;
+    AccountVO acct = new AccountVO(accountId);
+
+    @BeforeClass
+    public static void setUp() throws ConfigurationException {
+    }
+
+    @Before
+    public void testSetUp() {
+        ComponentContext.initComponentsLifeCycle();
+
+        acct.setType(Account.ACCOUNT_TYPE_NORMAL);
+        acct.setAccountName("user1");
+        acct.setDomainId(domainId);
+        acct.setId(accountId);
+
+        UserContext.registerContext(1, acct, null, true);
+    }
+
+    @Test
+    public void checkWhenDcInAvoidList() throws InsufficientServerCapacityException {
+        DataCenterVO mockDc = mock(DataCenterVO.class);
+        ExcludeList avoids = mock(ExcludeList.class);
+        @SuppressWarnings("unchecked")
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = mock(VirtualMachineProfileImpl.class);
+        VMInstanceVO vm = mock(VMInstanceVO.class);
+        DataCenterDeployment plan = mock(DataCenterDeployment.class);
+
+        when(avoids.shouldAvoid(mockDc)).thenReturn(true);
+        when(vmProfile.getVirtualMachine()).thenReturn(vm);
+        when(vm.getDataCenterId()).thenReturn(1L);
+        when(dcDao.findById(1L)).thenReturn(mockDc);
+
+        List<Long> clusterList = planner.orderClusters(vmProfile, plan, avoids);
+        assertTrue("Cluster list should be null/empty if the dc is in avoid list",
+                (clusterList == null || clusterList.isEmpty()));
+    }
+
+    @Test
+    public void checkStrictModeWithCurrentAccountVmsPresent() throws InsufficientServerCapacityException {
+        @SuppressWarnings("unchecked")
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = mock(VirtualMachineProfileImpl.class);
+        DataCenterDeployment plan = mock(DataCenterDeployment.class);
+        ExcludeList avoids = new ExcludeList();
+
+        initializeForTest(vmProfile, plan);
+
+        initializeForImplicitPlannerTest(false);
+
+        List<Long> clusterList = planner.orderClusters(vmProfile, plan, avoids);
+
+        // Validations.
+        // Check cluster 2 and 3 are not in the cluster list.
+        // Host 6 and 7 should also be in avoid list.
+        assertFalse("Cluster list should not be null/empty", (clusterList == null || clusterList.isEmpty()));
+        boolean foundNeededCluster = false;
+        for (Long cluster : clusterList) {
+            if (cluster != 1) {
+                fail("Found a cluster that shouldn't have been present, cluster id : " + cluster);
+            }else {
+                foundNeededCluster = true;
+            }
+        }
+        assertTrue("Didn't find cluster 1 in the list. It should have been present", foundNeededCluster);
+
+        Set<Long> hostsInAvoidList = avoids.getHostsToAvoid();
+        assertFalse("Host 5 shouldn't have be in the avoid list, but it is present", hostsInAvoidList.contains(5L));
+        Set<Long> hostsThatShouldBeInAvoidList = new HashSet<Long>();
+        hostsThatShouldBeInAvoidList.add(6L);
+        hostsThatShouldBeInAvoidList.add(7L);
+        assertTrue("Hosts 6 and 7 that should have been present were not found in avoid list" ,
+                hostsInAvoidList.containsAll(hostsThatShouldBeInAvoidList));
+    }
+
+    @Test
+    public void checkStrictModeHostWithCurrentAccountVmsFull() throws InsufficientServerCapacityException {
+        @SuppressWarnings("unchecked")
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = mock(VirtualMachineProfileImpl.class);
+        DataCenterDeployment plan = mock(DataCenterDeployment.class);
+        ExcludeList avoids = new ExcludeList();
+
+        initializeForTest(vmProfile, plan);
+
+        initializeForImplicitPlannerTest(false);
+
+        // Mark the host 5 with current account vms to be in avoid list.
+        avoids.addHost(5L);
+        List<Long> clusterList = planner.orderClusters(vmProfile, plan, avoids);
+
+        // Validations.
+        // Check cluster 1 and 3 are not in the cluster list.
+        // Host 5 and 7 should also be in avoid list.
+        assertFalse("Cluster list should not be null/empty", (clusterList == null || clusterList.isEmpty()));
+        boolean foundNeededCluster = false;
+        for (Long cluster : clusterList) {
+            if (cluster != 2) {
+                fail("Found a cluster that shouldn't have been present, cluster id : " + cluster);
+            }else {
+                foundNeededCluster = true;
+            }
+        }
+        assertTrue("Didn't find cluster 2 in the list. It should have been present", foundNeededCluster);
+
+        Set<Long> hostsInAvoidList = avoids.getHostsToAvoid();
+        assertFalse("Host 6 shouldn't have be in the avoid list, but it is present", hostsInAvoidList.contains(6L));
+        Set<Long> hostsThatShouldBeInAvoidList = new HashSet<Long>();
+        hostsThatShouldBeInAvoidList.add(5L);
+        hostsThatShouldBeInAvoidList.add(7L);
+        assertTrue("Hosts 5 and 7 that should have been present were not found in avoid list" ,
+                hostsInAvoidList.containsAll(hostsThatShouldBeInAvoidList));
+    }
+
+    @Test
+    public void checkStrictModeNoHostsAvailable() throws InsufficientServerCapacityException {
+        @SuppressWarnings("unchecked")
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = mock(VirtualMachineProfileImpl.class);
+        DataCenterDeployment plan = mock(DataCenterDeployment.class);
+        ExcludeList avoids = new ExcludeList();
+
+        initializeForTest(vmProfile, plan);
+
+        initializeForImplicitPlannerTest(false);
+
+        // Mark the host 5 and 6 to be in avoid list.
+        avoids.addHost(5L);
+        avoids.addHost(6L);
+        List<Long> clusterList = planner.orderClusters(vmProfile, plan, avoids);
+
+        // Validations.
+        // Check cluster list is empty.
+        assertTrue("Cluster list should not be null/empty", (clusterList == null || clusterList.isEmpty()));
+    }
+
+    @Test
+    public void checkPreferredModePreferredHostAvailable() throws InsufficientServerCapacityException {
+        @SuppressWarnings("unchecked")
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = mock(VirtualMachineProfileImpl.class);
+        DataCenterDeployment plan = mock(DataCenterDeployment.class);
+        ExcludeList avoids = new ExcludeList();
+
+        initializeForTest(vmProfile, plan);
+
+        initializeForImplicitPlannerTest(true);
+
+        // Mark the host 5 and 6 to be in avoid list.
+        avoids.addHost(5L);
+        avoids.addHost(6L);
+        List<Long> clusterList = planner.orderClusters(vmProfile, plan, avoids);
+
+        // Validations.
+        // Check cluster 1 and 2 are not in the cluster list.
+        // Host 5 and 6 should also be in avoid list.
+        assertFalse("Cluster list should not be null/empty", (clusterList == null || clusterList.isEmpty()));
+        boolean foundNeededCluster = false;
+        for (Long cluster : clusterList) {
+            if (cluster != 3) {
+                fail("Found a cluster that shouldn't have been present, cluster id : " + cluster);
+            } else {
+                foundNeededCluster = true;
+            }
+        }
+        assertTrue("Didn't find cluster 3 in the list. It should have been present", foundNeededCluster);
+
+        Set<Long> hostsInAvoidList = avoids.getHostsToAvoid();
+        assertFalse("Host 7 shouldn't have be in the avoid list, but it is present", hostsInAvoidList.contains(7L));
+        Set<Long> hostsThatShouldBeInAvoidList = new HashSet<Long>();
+        hostsThatShouldBeInAvoidList.add(5L);
+        hostsThatShouldBeInAvoidList.add(6L);
+        assertTrue("Hosts 5 and 6 that should have been present were not found in avoid list" ,
+                hostsInAvoidList.containsAll(hostsThatShouldBeInAvoidList));
+    }
+
+    @Test
+    public void checkPreferredModeNoHostsAvailable() throws InsufficientServerCapacityException {
+        @SuppressWarnings("unchecked")
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = mock(VirtualMachineProfileImpl.class);
+        DataCenterDeployment plan = mock(DataCenterDeployment.class);
+        ExcludeList avoids = new ExcludeList();
+
+        initializeForTest(vmProfile, plan);
+
+        initializeForImplicitPlannerTest(false);
+
+        // Mark the host 5, 6 and 7 to be in avoid list.
+        avoids.addHost(5L);
+        avoids.addHost(6L);
+        avoids.addHost(7L);
+        List<Long> clusterList = planner.orderClusters(vmProfile, plan, avoids);
+
+        // Validations.
+        // Check cluster list is empty.
+        assertTrue("Cluster list should not be null/empty", (clusterList == null || clusterList.isEmpty()));
+    }
+
+    private void initializeForTest(VirtualMachineProfileImpl<VMInstanceVO> vmProfile, DataCenterDeployment plan) {
+        DataCenterVO mockDc = mock(DataCenterVO.class);
+        VMInstanceVO vm = mock(VMInstanceVO.class);
+        UserVmVO userVm = mock(UserVmVO.class);
+        ServiceOfferingVO offering = mock(ServiceOfferingVO.class);
+
+        AccountVO account = mock(AccountVO.class);
+        when(account.getId()).thenReturn(accountId);
+        when(account.getAccountId()).thenReturn(accountId);
+        when(vmProfile.getOwner()).thenReturn(account);
+        when(vmProfile.getVirtualMachine()).thenReturn(vm);
+        when(vmProfile.getId()).thenReturn(12L);
+        when(vmDao.findById(12L)).thenReturn(userVm);
+        when(userVm.getAccountId()).thenReturn(accountId);
+
+        when(vm.getDataCenterId()).thenReturn(dataCenterId);
+        when(dcDao.findById(1L)).thenReturn(mockDc);
+        when(plan.getDataCenterId()).thenReturn(dataCenterId);
+        when(plan.getClusterId()).thenReturn(null);
+        when(plan.getPodId()).thenReturn(null);
+        when(configDao.getValue(anyString())).thenReturn("false").thenReturn("CPU");
+
+        // Mock offering details.
+        when(vmProfile.getServiceOffering()).thenReturn(offering);
+        when(offering.getId()).thenReturn(offeringId);
+        when(vmProfile.getServiceOfferingId()).thenReturn(offeringId);
+        when(offering.getCpu()).thenReturn(noOfCpusInOffering);
+        when(offering.getSpeed()).thenReturn(cpuSpeedInOffering);
+        when(offering.getRamSize()).thenReturn(ramInOffering);
+
+        List<Long> clustersWithEnoughCapacity = new ArrayList<Long>();
+        clustersWithEnoughCapacity.add(1L);
+        clustersWithEnoughCapacity.add(2L);
+        clustersWithEnoughCapacity.add(3L);
+        when(capacityDao.listClustersInZoneOrPodByHostCapacities(dataCenterId, noOfCpusInOffering * cpuSpeedInOffering,
+                ramInOffering * 1024L * 1024L, CapacityVO.CAPACITY_TYPE_CPU, true)).thenReturn(clustersWithEnoughCapacity);
+
+        Map<Long, Double> clusterCapacityMap = new HashMap<Long, Double>();
+        clusterCapacityMap.put(1L, 2048D);
+        clusterCapacityMap.put(2L, 2048D);
+        clusterCapacityMap.put(3L, 2048D);
+        Pair<List<Long>, Map<Long, Double>> clustersOrderedByCapacity =
+                new Pair<List<Long>, Map<Long, Double>>(clustersWithEnoughCapacity, clusterCapacityMap);
+        when(capacityDao.orderClustersByAggregateCapacity(dataCenterId, CapacityVO.CAPACITY_TYPE_CPU,
+                true)).thenReturn(clustersOrderedByCapacity);
+
+        List<Long> disabledClusters = new ArrayList<Long>();
+        List<Long> clustersWithDisabledPods = new ArrayList<Long>();
+        when(clusterDao.listDisabledClusters(dataCenterId, null)).thenReturn(disabledClusters);
+        when(clusterDao.listClustersWithDisabledPods(dataCenterId)).thenReturn(clustersWithDisabledPods);
+    }
+
+    private void initializeForImplicitPlannerTest(boolean preferred) {
+        String plannerMode = new String("Strict");
+        if (preferred) {
+            plannerMode = new String("Preferred");
+        }
+
+        Map<String, String> details = new HashMap<String, String>();
+        details.put("ImplicitDedicationMode", plannerMode);
+        when(serviceOfferingDetailsDao.findDetails(offeringId)).thenReturn(details);
+
+        // Initialize hosts in clusters
+        HostVO host1 = mock(HostVO.class);
+        when(host1.getId()).thenReturn(5L);
+        HostVO host2 = mock(HostVO.class);
+        when(host2.getId()).thenReturn(6L);
+        HostVO host3 = mock(HostVO.class);
+        when(host3.getId()).thenReturn(7L);
+        List<HostVO> hostsInCluster1 = new ArrayList<HostVO>();
+        List<HostVO> hostsInCluster2 = new ArrayList<HostVO>();
+        List<HostVO> hostsInCluster3 = new ArrayList<HostVO>();
+        hostsInCluster1.add(host1);
+        hostsInCluster2.add(host2);
+        hostsInCluster3.add(host3);
+        when(resourceMgr.listAllHostsInCluster(1)).thenReturn(hostsInCluster1);
+        when(resourceMgr.listAllHostsInCluster(2)).thenReturn(hostsInCluster2);
+        when(resourceMgr.listAllHostsInCluster(3)).thenReturn(hostsInCluster3);
+
+        // Mock vms on each host.
+        long offeringIdForVmsOfThisAccount = 15L;
+        long offeringIdForVmsOfOtherAccount = 16L;
+        UserVmVO vm1 = mock(UserVmVO.class);
+        when(vm1.getAccountId()).thenReturn(accountId);
+        when(vm1.getServiceOfferingId()).thenReturn(offeringIdForVmsOfThisAccount);
+        UserVmVO vm2 = mock(UserVmVO.class);
+        when(vm2.getAccountId()).thenReturn(accountId);
+        when(vm2.getServiceOfferingId()).thenReturn(offeringIdForVmsOfThisAccount);
+        // Vm from different account
+        UserVmVO vm3 = mock(UserVmVO.class);
+        when(vm3.getAccountId()).thenReturn(201L);
+        when(vm3.getServiceOfferingId()).thenReturn(offeringIdForVmsOfOtherAccount);
+        List<UserVmVO> userVmsForHost1 = new ArrayList<UserVmVO>();
+        List<UserVmVO> userVmsForHost2 = new ArrayList<UserVmVO>();
+        List<UserVmVO> userVmsForHost3 = new ArrayList<UserVmVO>();
+        List<UserVmVO> stoppedVmsForHost = new ArrayList<UserVmVO>();
+        // Host 2 is empty.
+        userVmsForHost1.add(vm1);
+        userVmsForHost1.add(vm2);
+        userVmsForHost3.add(vm3);
+        when(vmDao.listUpByHostId(5L)).thenReturn(userVmsForHost1);
+        when(vmDao.listUpByHostId(6L)).thenReturn(userVmsForHost2);
+        when(vmDao.listUpByHostId(7L)).thenReturn(userVmsForHost3);
+        when(vmDao.listByLastHostId(5L)).thenReturn(stoppedVmsForHost);
+        when(vmDao.listByLastHostId(6L)).thenReturn(stoppedVmsForHost);
+        when(vmDao.listByLastHostId(7L)).thenReturn(stoppedVmsForHost);
+
+        // Mock the offering with which the vm was created.
+        ServiceOfferingVO offeringForVmOfThisAccount = mock(ServiceOfferingVO.class);
+        when(serviceOfferingDao.findByIdIncludingRemoved(offeringIdForVmsOfThisAccount)).thenReturn(offeringForVmOfThisAccount);
+        when(offeringForVmOfThisAccount.getDeploymentPlanner()).thenReturn(planner.getName());
+
+        ServiceOfferingVO offeringForVMOfOtherAccount = mock(ServiceOfferingVO.class);
+        when(serviceOfferingDao.findByIdIncludingRemoved(offeringIdForVmsOfOtherAccount)).thenReturn(offeringForVMOfOtherAccount);
+        when(offeringForVMOfOtherAccount.getDeploymentPlanner()).thenReturn("FirstFitPlanner");
+    }
+
+    @Configuration
+    @ComponentScan(basePackageClasses = { ImplicitDedicationPlanner.class },
+        includeFilters = {@Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)},
+        useDefaultFilters = false)
+    public static class TestConfiguration extends SpringUtils.CloudStackTestConfiguration {
+
+        @Bean
+        public HostDao hostDao() {
+            return Mockito.mock(HostDao.class);
+        }
+
+        @Bean
+        public DataCenterDao dcDao() {
+            return Mockito.mock(DataCenterDao.class);
+        }
+
+        @Bean
+        public HostPodDao hostPodDao() {
+            return Mockito.mock(HostPodDao.class);
+        }
+
+        @Bean
+        public ClusterDao clusterDao() {
+            return Mockito.mock(ClusterDao.class);
+        }
+
+        @Bean
+        public GuestOSDao guestOsDao() {
+            return Mockito.mock(GuestOSDao.class);
+        }
+
+        @Bean
+        public GuestOSCategoryDao guestOsCategoryDao() {
+            return Mockito.mock(GuestOSCategoryDao.class);
+        }
+
+        @Bean
+        public DiskOfferingDao diskOfferingDao() {
+            return Mockito.mock(DiskOfferingDao.class);
+        }
+
+        @Bean
+        public StoragePoolHostDao storagePoolHostDao() {
+            return Mockito.mock(StoragePoolHostDao.class);
+        }
+
+        @Bean
+        public UserVmDao userVmDao() {
+            return Mockito.mock(UserVmDao.class);
+        }
+
+        @Bean
+        public VMInstanceDao vmInstanceDao() {
+            return Mockito.mock(VMInstanceDao.class);
+        }
+
+        @Bean
+        public VolumeDao volumeDao() {
+            return Mockito.mock(VolumeDao.class);
+        }
+
+        @Bean
+        public CapacityManager capacityManager() {
+            return Mockito.mock(CapacityManager.class);
+        }
+
+        @Bean
+        public ConfigurationDao configurationDao() {
+            return Mockito.mock(ConfigurationDao.class);
+        }
+
+        @Bean
+        public PrimaryDataStoreDao primaryDataStoreDao() {
+            return Mockito.mock(PrimaryDataStoreDao.class);
+        }
+
+        @Bean
+        public CapacityDao capacityDao() {
+            return Mockito.mock(CapacityDao.class);
+        }
+
+        @Bean
+        public AccountManager accountManager() {
+            return Mockito.mock(AccountManager.class);
+        }
+
+        @Bean
+        public StorageManager storageManager() {
+            return Mockito.mock(StorageManager.class);
+        }
+
+        @Bean
+        public DataStoreManager dataStoreManager() {
+            return Mockito.mock(DataStoreManager.class);
+        }
+
+        @Bean
+        public ClusterDetailsDao clusterDetailsDao() {
+            return Mockito.mock(ClusterDetailsDao.class);
+        }
+
+        @Bean
+        public ServiceOfferingDao serviceOfferingDao() {
+            return Mockito.mock(ServiceOfferingDao.class);
+        }
+
+        @Bean
+        public ServiceOfferingDetailsDao serviceOfferingDetailsDao() {
+            return Mockito.mock(ServiceOfferingDetailsDao.class);
+        }
+
+        @Bean
+        public ResourceManager resourceManager() {
+            return Mockito.mock(ResourceManager.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);
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/plugins/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/pom.xml b/plugins/pom.xml
index e49fac9..2efa248 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -38,6 +38,7 @@
 	<module>affinity-group-processors/host-anti-affinity</module>
     <module>deployment-planners/user-concentrated-pod</module>
     <module>deployment-planners/user-dispersing</module>
+    <module>deployment-planners/implicit-dedication</module>
     <module>host-allocators/random</module>
     <module>hypervisors/ovm</module>
     <module>hypervisors/xen</module>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/server/src/com/cloud/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java
index d0ae914..8db037b 100755
--- a/server/src/com/cloud/configuration/ConfigurationManager.java
+++ b/server/src/com/cloud/configuration/ConfigurationManager.java
@@ -80,10 +80,11 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
      * @param id
      * @param useVirtualNetwork
      * @param deploymentPlanner
+     * @param details
      * @return ID
      */
     ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired,
-            boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner);
+            boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner, Map<String, String> details);
 
     /**
      * Creates a new disk offering

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index 9e0c847..52d6176 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -39,7 +39,6 @@ import javax.naming.NamingException;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.InitialDirContext;
 
-
 import com.cloud.dc.*;
 import com.cloud.dc.dao.*;
 import com.cloud.user.*;
@@ -105,7 +104,6 @@ import com.cloud.dc.dao.DcDetailsDao;
 import com.cloud.dc.dao.HostPodDao;
 import com.cloud.dc.dao.PodVlanMapDao;
 import com.cloud.dc.dao.VlanDao;
-
 import com.cloud.deploy.DataCenterDeployment;
 import com.cloud.domain.Domain;
 import com.cloud.domain.DomainVO;
@@ -165,6 +163,7 @@ import com.cloud.server.ConfigurationServer;
 import com.cloud.server.ManagementService;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.service.dao.ServiceOfferingDetailsDao;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.SwiftVO;
 import com.cloud.storage.dao.DiskOfferingDao;
@@ -277,6 +276,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
     @Inject
     ServiceOfferingDao _serviceOfferingDao;
     @Inject
+    ServiceOfferingDetailsDao _serviceOfferingDetailsDao;
+    @Inject
     DiskOfferingDao _diskOfferingDao;
     @Inject
     NetworkOfferingDao _networkOfferingDao;
@@ -2050,19 +2051,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
             }
         }
 
-        return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber.intValue(), memory.intValue(), cpuSpeed.intValue(), cmd.getDisplayText(),
-                localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate(), cmd.getDeploymentPlanner());
+        return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(),
+                cpuNumber.intValue(), memory.intValue(), cpuSpeed.intValue(), cmd.getDisplayText(),
+                localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(),
+                cmd.getHostTag(), cmd.getNetworkRate(), cmd.getDeploymentPlanner(), cmd.getDetails());
     }
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CREATE, eventDescription = "creating service offering")
-    public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_type, String name, int cpu, int ramSize, int speed, String displayText,
-            boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm,  String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner) {
+    public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_type,
+            String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired,
+            boolean offerHA, boolean limitResourceUse, boolean volatileVm,  String tags, Long domainId, String hostTag,
+            Integer networkRate, String deploymentPlanner, Map<String, String> details) {
         tags = cleanupTags(tags);
         ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, localStorageRequired, false, tags, isSystem, vm_type,
                 domainId, hostTag, deploymentPlanner);
 
         if ((offering = _serviceOfferingDao.persist(offering)) != null) {
+            if (details != null) {
+                _serviceOfferingDetailsDao.persist(offering.getId(), details);
+            }
             UserContext.current().setEventDetails("Service offering id=" + offering.getId());
             return offering;
         } else {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
index ba18fa1..4fb182a 100755
--- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -431,7 +431,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
      */
     @Override
     public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA,
-            boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner) {
+            boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner, Map<String, String> details) {
         // TODO Auto-generated method stub
         return null;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
----------------------------------------------------------------------
diff --git a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
index 7ffbe32..a825699 100644
--- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
+++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
@@ -19,14 +19,8 @@ package org.apache.cloudstack.networkoffering;
 
 import java.io.IOException;
 
-import com.cloud.dc.ClusterDetailsDao;
-import com.cloud.dc.dao.*;
-import com.cloud.server.ConfigurationServer;
-import com.cloud.user.*;
 import org.apache.cloudstack.acl.SecurityChecker;
-import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
-import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
 import org.apache.cloudstack.test.utils.SpringUtils;
 import org.mockito.Mockito;
 import org.springframework.context.annotation.Bean;
@@ -44,6 +38,18 @@ import com.cloud.api.query.dao.UserAccountJoinDaoImpl;
 import com.cloud.capacity.dao.CapacityDaoImpl;
 import com.cloud.cluster.agentlb.dao.HostTransferMapDaoImpl;
 import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.dao.AccountVlanMapDaoImpl;
+import com.cloud.dc.dao.ClusterDaoImpl;
+import com.cloud.dc.dao.DataCenterDaoImpl;
+import com.cloud.dc.dao.DataCenterIpAddressDaoImpl;
+import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDao;
+import com.cloud.dc.dao.DataCenterVnetDaoImpl;
+import com.cloud.dc.dao.DcDetailsDaoImpl;
+import com.cloud.dc.dao.HostPodDaoImpl;
+import com.cloud.dc.dao.PodVlanDaoImpl;
+import com.cloud.dc.dao.PodVlanMapDaoImpl;
+import com.cloud.dc.dao.VlanDaoImpl;
 import com.cloud.domain.dao.DomainDaoImpl;
 import com.cloud.event.dao.UsageEventDaoImpl;
 import com.cloud.host.dao.HostDaoImpl;
@@ -80,10 +86,11 @@ import com.cloud.network.vpc.dao.PrivateIpDaoImpl;
 import com.cloud.network.vpn.RemoteAccessVpnService;
 import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
-import com.cloud.offerings.dao.NetworkOfferingServiceMapDaoImpl;
 import com.cloud.projects.ProjectManager;
+import com.cloud.server.ConfigurationServer;
 import com.cloud.server.ManagementService;
 import com.cloud.service.dao.ServiceOfferingDaoImpl;
+import com.cloud.service.dao.ServiceOfferingDetailsDaoImpl;
 import com.cloud.storage.dao.DiskOfferingDaoImpl;
 import com.cloud.storage.dao.S3DaoImpl;
 import com.cloud.storage.dao.SnapshotDaoImpl;
@@ -94,6 +101,11 @@ import com.cloud.storage.s3.S3Manager;
 import com.cloud.storage.secondary.SecondaryStorageVmManager;
 import com.cloud.storage.swift.SwiftManager;
 import com.cloud.tags.dao.ResourceTagsDaoImpl;
+import com.cloud.user.AccountDetailsDao;
+import com.cloud.user.AccountManager;
+import com.cloud.user.ResourceLimitService;
+import com.cloud.user.UserContext;
+import com.cloud.user.UserContextInitializer;
 import com.cloud.user.dao.AccountDaoImpl;
 import com.cloud.user.dao.UserDaoImpl;
 import com.cloud.vm.dao.InstanceGroupDaoImpl;
@@ -110,6 +122,7 @@ import com.cloud.vm.dao.VMInstanceDaoImpl;
         DomainDaoImpl.class,
         SwiftDaoImpl.class,
         ServiceOfferingDaoImpl.class,
+        ServiceOfferingDetailsDaoImpl.class,
         VlanDaoImpl.class,
         IPAddressDaoImpl.class,
         ResourceTagsDaoImpl.class,

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/setup/db/db/schema-410to420.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql
index 442a544..fe66207 100644
--- a/setup/db/db/schema-410to420.sql
+++ b/setup/db/db/schema-410to420.sql
@@ -393,7 +393,16 @@ CREATE TABLE `cloud`.`vm_snapshots` (
 ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `vm_snapshot_enabled` tinyint(1) DEFAULT 0 NOT NULL COMMENT 'Whether VM snapshot is supported by hypervisor';
 UPDATE `cloud`.`hypervisor_capabilities` SET `vm_snapshot_enabled`=1 WHERE `hypervisor_type` in ('VMware', 'XenServer');
 
-      
+CREATE TABLE `cloud`.`service_offering_details` (
+  `id` bigint unsigned NOT NULL auto_increment,
+  `service_offering_id` bigint unsigned NOT NULL COMMENT 'service offering id',
+  `name` varchar(255) NOT NULL,
+  `value` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`),
+  CONSTRAINT `fk_service_offering_details__service_offering_id` FOREIGN KEY (`service_offering_id`) REFERENCES `service_offering`(`id`) ON DELETE CASCADE,
+  CONSTRAINT UNIQUE KEY `uk_service_offering_id_name` (`service_offering_id`, `name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
 DROP VIEW IF EXISTS `cloud`.`user_vm_view`;
 CREATE VIEW `cloud`.`user_vm_view` AS
     select 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/test/integration/component/test_implicit_planner.py
----------------------------------------------------------------------
diff --git a/test/integration/component/test_implicit_planner.py b/test/integration/component/test_implicit_planner.py
new file mode 100644
index 0000000..ffcd248
--- /dev/null
+++ b/test/integration/component/test_implicit_planner.py
@@ -0,0 +1,232 @@
+# 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.
+""" P1 tests for Storage motion
+"""
+#Import Local Modules
+import marvin
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.remoteSSHClient import remoteSSHClient
+from marvin.integration.lib.utils import *
+from marvin.integration.lib.base import *
+from marvin.integration.lib.common import *
+from nose.plugins.attrib import attr
+#Import System modules
+import time
+
+_multiprocess_shared_ = True
+class Services:
+    """Test VM Life Cycle Services
+    """
+
+    def __init__(self):
+        self.services = {
+                "disk_offering":{
+                    "displaytext": "Small",
+                    "name": "Small",
+                    "disksize": 1
+                },
+                "account": {
+                    "email": "test@test.com",
+                    "firstname": "Test",
+                    "lastname": "User",
+                    "username": "test",
+                    # Random characters are appended in create account to
+                    # ensure unique username generated each time
+                    "password": "password",
+                },
+                "small":
+                # Create a small virtual machine instance with disk offering
+                {
+                    "displayname": "testserver",
+                    "username": "root", # VM creds for SSH
+                    "password": "password",
+                    "ssh_port": 22,
+                    "hypervisor": 'XenServer',
+                    "privateport": 22,
+                    "publicport": 22,
+                    "protocol": 'TCP',
+                },
+                "service_offerings":
+                {
+                 "implicitplanner":
+                    {
+                     # Small service offering ID to for change VM
+                     # service offering from medium to small
+                        "name": "Implicit Strict",
+                        "displaytext": "Implicit Strict",
+                        "cpunumber": 1,
+                        "cpuspeed": 500,
+                        "memory": 512,
+                        "deploymentplanner": "ImplicitDedicationPlanner"
+                    }
+                },
+                "template": {
+                    "displaytext": "Cent OS Template",
+                    "name": "Cent OS Template",
+                    "passwordenabled": True,
+                },
+            "diskdevice": '/dev/xvdd',
+            # Disk device where ISO is attached to instance
+            "mount_dir": "/mnt/tmp",
+            "sleep": 60,
+            "timeout": 10,
+            #Migrate VM to hostid
+            "ostype": 'CentOS 5.3 (64-bit)',
+            # CentOS 5.3 (64-bit)
+        }
+
+class TestImplicitPlanner(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.api_client = super(TestImplicitPlanner, cls).getClsTestClient().getApiClient()
+        cls.services = Services().services
+
+        # Get Zone, Domain and templates
+        domain = get_domain(cls.api_client, cls.services)
+        cls.zone = get_zone(cls.api_client, cls.services)
+        cls.services['mode'] = cls.zone.networktype
+
+        template = get_template(
+                            cls.api_client,
+                            cls.zone.id,
+                            cls.services["ostype"]
+                            )
+        # Set Zones and disk offerings
+        cls.services["small"]["zoneid"] = cls.zone.id
+        cls.services["small"]["template"] = template.id
+
+        # Create VMs, NAT Rules etc
+        cls.account = Account.create(
+                            cls.api_client,
+                            cls.services["account"],
+                            domainid=domain.id
+                            )
+
+        cls.small_offering = ServiceOffering.create(
+                                    cls.api_client,
+                                    cls.services["service_offerings"]["implicitplanner"]
+                                    )
+
+        cls._cleanup = [
+                        cls.small_offering,
+                        cls.account
+                        ]
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.api_client = super(TestImplicitPlanner, cls).getClsTestClient().getApiClient()
+        cleanup_resources(cls.api_client, cls._cleanup)
+        return
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+
+    def tearDown(self):
+        #Clean up, terminate the created ISOs
+        cleanup_resources(self.apiclient, self.cleanup)
+        return
+
+    # This test requires multi host and at least one host which is empty (no vms should
+    # be running on that host). It uses an implicit planner to deploy instances and the
+    # instances of a new account should go to an host that doesn't have vms of any other
+    # account.
+    @attr(tags = ["advanced", "basic", "multihosts", "implicitplanner"])
+    def test_01_deploy_vm_with_implicit_planner(self):
+        """Test implicit planner is placing vms of an account on implicitly dedicated hosts.
+        """
+        # Validate the following
+        # 1. Deploy a vm using implicit planner. It should go on to a
+        #    host that is empty (not running vms of any other account)
+        # 2. Deploy another vm it should get deployed on the same host.
+
+        #create a virtual machine
+        virtual_machine_1 = VirtualMachine.create(
+                                        self.api_client,
+                                        self.services["small"],
+                                        accountid=self.account.name,
+                                        domainid=self.account.domainid,
+                                        serviceofferingid=self.small_offering.id,
+                                        mode=self.services["mode"]
+                                        )
+
+        list_vm_response_1 = list_virtual_machines(
+                                            self.apiclient,
+                                            id=virtual_machine_1.id
+                                            )
+        self.assertEqual(
+                        isinstance(list_vm_response_1, list),
+                        True,
+                        "Check list response returns a valid list"
+                        )
+
+        self.assertNotEqual(
+                            list_vm_response_1,
+                            None,
+                            "Check virtual machine is listVirtualMachines"
+                            )
+
+        vm_response_1 = list_vm_response_1[0]
+
+        self.assertEqual(
+                        vm_response_1.id,
+                        virtual_machine_1.id,
+                        "Check virtual machine ID of VM"
+                        )
+
+        virtual_machine_2 = VirtualMachine.create(
+                                                self.api_client,
+                                                self.services["small"],
+                                                accountid=self.account.name,
+                                                domainid=self.account.domainid,
+                                                serviceofferingid=self.small_offering.id,
+                                                mode=self.services["mode"]
+                                                )
+
+        list_vm_response_2 = list_virtual_machines(
+                                            self.apiclient,
+                                            id=virtual_machine_2.id
+                                            )
+        self.assertEqual(
+                isinstance(list_vm_response_2, list),
+                True,
+                "Check list response returns a valid list"
+                )
+
+        self.assertNotEqual(
+                            list_vm_response_2,
+                            None,
+                            "Check virtual machine is listVirtualMachines"
+                            )
+
+        vm_response_2 = list_vm_response_2[0]
+
+        self.assertEqual(
+                vm_response_2.id,
+                virtual_machine_2.id,
+                "Check virtual machine ID of VM"
+                )
+
+        self.assertEqual(
+                vm_response_1.hostid,
+                vm_response_2.hostid,
+                "Check both vms have the same host id"
+                )
+        return
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/adbebc18/tools/marvin/marvin/integration/lib/base.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py
index ecdc841..a811f14 100755
--- a/tools/marvin/marvin/integration/lib/base.py
+++ b/tools/marvin/marvin/integration/lib/base.py
@@ -1268,6 +1268,10 @@ class ServiceOffering:
 
         if "tags" in services:
             cmd.tags = services["tags"]
+
+        if "deploymentplanner" in services:
+            cmd.deploymentplanner = services["deploymentplanner"]
+
         # Service Offering private to that domain
         if domainid:
             cmd.domainid = domainid


Mime
View raw message