cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From raj...@apache.org
Subject [1/2] git commit: updated refs/heads/master to c9e7ccf
Date Thu, 27 Oct 2016 06:19:58 GMT
Repository: cloudstack
Updated Branches:
  refs/heads/master 33518257b -> c9e7ccf46


CLOUDSTACK-9438: Fix for CLOUDSTACK-9252 - Make NFS version changeable in UI


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

Branch: refs/heads/master
Commit: 2e77496601ab5420723ce8b955b3960faaba7d5c
Parents: 3a82636
Author: nvazquez <nicovazquez90@gmail.com>
Authored: Tue Jul 12 11:41:52 2016 -0300
Committer: nvazquez <nicolas.m.vazquez@gmail.com>
Committed: Wed Sep 28 08:51:37 2016 -0700

----------------------------------------------------------------------
 .../api/command/admin/config/ListCfgsByCmd.java |  14 ++
 .../api/command/admin/config/UpdateCfgCmd.java  |  14 +-
 .../src/com/cloud/capacity/CapacityManager.java |  10 ++
 .../spring-engine-schema-core-daos-context.xml  |   4 +-
 .../storage/datastore/db/ImageStoreDaoImpl.java | 127 ++++++++++++++
 .../datastore/db/ImageStoreDetailVO.java        |  34 ++--
 .../datastore/db/ImageStoreDetailsDao.java      |   4 +-
 .../datastore/db/ImageStoreDetailsDaoImpl.java  | 119 +++++++++++++
 .../test/resource/fakeDriverTestContext.xml     |   4 +-
 .../test/resources/storageContext.xml           |   4 +-
 .../storage/image/NfsImageStoreDriverImpl.java  |  11 +-
 .../image/datastore/ImageStoreHelper.java       |   5 +-
 .../storage/image/db/ImageStoreDaoImpl.java     | 129 --------------
 .../image/db/ImageStoreDetailsDaoImpl.java      |  94 ----------
 .../cloudstack/framework/config/ConfigKey.java  |   2 +-
 .../framework/config/impl/ConfigDepotImpl.java  |   1 +
 .../IntegrationTestConfiguration.java           |   2 +-
 .../com/cloud/capacity/CapacityManagerImpl.java |   2 +-
 .../configuration/ConfigurationManagerImpl.java |  21 +++
 .../com/cloud/server/ManagementServerImpl.java  |   6 +
 .../cloud/storage/ImageStoreDetailsUtil.java    |  48 +++--
 .../storage/ImageStoreDetailsUtilTest.java      |  30 +++-
 .../networkoffering/ChildTestConfiguration.java |   4 +-
 setup/db/db/schema-481to490.sql                 |   3 +
 test/integration/smoke/test_ssvm.py             | 174 ++++++++++++++++++-
 ui/scripts/system.js                            |  72 +++++---
 26 files changed, 631 insertions(+), 307 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
index a34bc3e..8f71f48 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
@@ -28,6 +28,7 @@ import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.response.AccountResponse;
 import org.apache.cloudstack.api.response.ClusterResponse;
 import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.apache.cloudstack.api.response.ImageStoreResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.api.response.StoragePoolResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
@@ -76,6 +77,12 @@ public class ListCfgsByCmd extends BaseListCmd {
                description = "the ID of the Account to update the parameter value for corresponding account")
     private Long accountId;
 
+    @Parameter(name = ApiConstants.IMAGE_STORE_UUID,
+            type = CommandType.UUID,
+            entityType = ImageStoreResponse.class,
+            description = "the ID of the Image Store to update the parameter value for corresponding image store")
+    private Long imageStoreId;
+
     // ///////////////////////////////////////////////////
     // ///////////////// Accessors ///////////////////////
     // ///////////////////////////////////////////////////
@@ -104,6 +111,10 @@ public class ListCfgsByCmd extends BaseListCmd {
         return accountId;
     }
 
+    public Long getImageStoreId() {
+        return imageStoreId;
+    }
+
     @Override
     public Long getPageSizeVal() {
         Long defaultPageSize = 500L;
@@ -147,6 +158,9 @@ public class ListCfgsByCmd extends BaseListCmd {
             if (getAccountId() != null) {
                 cfgResponse.setScope("account");
             }
+            if (getImageStoreId() != null){
+                cfgResponse.setScope("imagestore");
+            }
             configResponses.add(cfgResponse);
         }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
index 45f790f..fa5e26e 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
@@ -19,8 +19,8 @@ package org.apache.cloudstack.api.command.admin.config;
 import com.google.common.base.Strings;
 import org.apache.cloudstack.acl.RoleService;
 import org.apache.log4j.Logger;
-
 import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
 import org.apache.cloudstack.api.BaseCmd;
@@ -29,6 +29,7 @@ import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.AccountResponse;
 import org.apache.cloudstack.api.response.ClusterResponse;
 import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.apache.cloudstack.api.response.ImageStoreResponse;
 import org.apache.cloudstack.api.response.StoragePoolResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.config.Configuration;
@@ -75,6 +76,13 @@ public class UpdateCfgCmd extends BaseCmd {
                description = "the ID of the Account to update the parameter value for corresponding account")
     private Long accountId;
 
+    @Parameter(name = ApiConstants.IMAGE_STORE_UUID,
+            type = CommandType.UUID,
+            entityType = ImageStoreResponse.class,
+            description = "the ID of the Image Store to update the parameter value for corresponding image store",
+            validations = ApiArgValidator.PositiveNumber)
+    private Long imageStoreId;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -107,6 +115,10 @@ public class UpdateCfgCmd extends BaseCmd {
         return accountId;
     }
 
+    public Long getImageStoreId() {
+        return imageStoreId;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/components-api/src/com/cloud/capacity/CapacityManager.java
----------------------------------------------------------------------
diff --git a/engine/components-api/src/com/cloud/capacity/CapacityManager.java b/engine/components-api/src/com/cloud/capacity/CapacityManager.java
index d190d78..98287bb 100644
--- a/engine/components-api/src/com/cloud/capacity/CapacityManager.java
+++ b/engine/components-api/src/com/cloud/capacity/CapacityManager.java
@@ -73,6 +73,16 @@ public interface CapacityManager {
                     "If set to true, creates VMs as full clones on ESX hypervisor",
                     true,
                     ConfigKey.Scope.StoragePool);
+    static final ConfigKey<Integer> ImageStoreNFSVersion =
+            new ConfigKey<Integer>(
+                    Integer.class,
+                    "secstorage.nfs.version",
+                    "Advanced",
+                    null,
+                    "Enforces specific NFS version when mounting Secondary Storage. If NULL default selection is performed",
+                    true,
+                    ConfigKey.Scope.ImageStore,
+                    null);
 
     public boolean releaseVmCapacity(VirtualMachine vm, boolean moveFromReserved, boolean moveToReservered, Long hostId);
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
----------------------------------------------------------------------
diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
index 6916478..884bb30 100644
--- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
+++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
@@ -176,8 +176,8 @@
   <bean id="hostTagsDaoImpl" class="com.cloud.host.dao.HostTagsDaoImpl" />
   <bean id="hostTransferMapDaoImpl" class="com.cloud.cluster.agentlb.dao.HostTransferMapDaoImpl" />
   <bean id="iPAddressDaoImpl" class="com.cloud.network.dao.IPAddressDaoImpl" />
-  <bean id="imageStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.ImageStoreDaoImpl" />
-  <bean id="imageStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.image.db.ImageStoreDetailsDaoImpl" />
+  <bean id="imageStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl" />
+  <bean id="imageStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDaoImpl" />
   <bean id="imageStoreJoinDaoImpl" class="com.cloud.api.query.dao.ImageStoreJoinDaoImpl" />
   <bean id="snapshotDataStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.SnapshotDataStoreDaoImpl" />
   <bean id="templateDataStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.TemplateDataStoreDaoImpl" />

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java
new file mode 100644
index 0000000..9d53262
--- /dev/null
+++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java
@@ -0,0 +1,127 @@
+/*
+ * 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.storage.datastore.db;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.springframework.stereotype.Component;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
+
+import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.ScopeType;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+@Component
+public class ImageStoreDaoImpl extends GenericDaoBase<ImageStoreVO, Long> implements ImageStoreDao {
+    private SearchBuilder<ImageStoreVO> nameSearch;
+    private SearchBuilder<ImageStoreVO> providerSearch;
+    private SearchBuilder<ImageStoreVO> regionSearch;
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+        super.configure(name, params);
+
+        nameSearch = createSearchBuilder();
+        nameSearch.and("name", nameSearch.entity().getName(), SearchCriteria.Op.EQ);
+        nameSearch.and("role", nameSearch.entity().getRole(), SearchCriteria.Op.EQ);
+        nameSearch.done();
+
+        providerSearch = createSearchBuilder();
+        providerSearch.and("providerName", providerSearch.entity().getProviderName(), SearchCriteria.Op.EQ);
+        providerSearch.and("role", providerSearch.entity().getRole(), SearchCriteria.Op.EQ);
+        providerSearch.done();
+
+        regionSearch = createSearchBuilder();
+        regionSearch.and("scope", regionSearch.entity().getScope(), SearchCriteria.Op.EQ);
+        regionSearch.and("role", regionSearch.entity().getRole(), SearchCriteria.Op.EQ);
+        regionSearch.done();
+
+        return true;
+    }
+
+    @Override
+    public ImageStoreVO findByName(String name) {
+        SearchCriteria<ImageStoreVO> sc = nameSearch.create();
+        sc.setParameters("name", name);
+        return findOneBy(sc);
+    }
+
+    @Override
+    public List<ImageStoreVO> findByProvider(String provider) {
+        SearchCriteria<ImageStoreVO> sc = providerSearch.create();
+        sc.setParameters("providerName", provider);
+        sc.setParameters("role", DataStoreRole.Image);
+        return listBy(sc);
+    }
+
+    @Override
+    public List<ImageStoreVO> findByScope(ZoneScope scope) {
+        SearchCriteria<ImageStoreVO> sc = createSearchCriteria();
+        sc.addAnd("role", SearchCriteria.Op.EQ, DataStoreRole.Image);
+        if (scope.getScopeId() != null) {
+            SearchCriteria<ImageStoreVO> scc = createSearchCriteria();
+            scc.addOr("scope", SearchCriteria.Op.EQ, ScopeType.REGION);
+            scc.addOr("dcId", SearchCriteria.Op.EQ, scope.getScopeId());
+            sc.addAnd("scope", SearchCriteria.Op.SC, scc);
+        }
+        // we should return all image stores if cross-zone scope is passed
+        // (scopeId = null)
+        return listBy(sc);
+    }
+
+    @Override
+    public List<ImageStoreVO> findRegionImageStores() {
+        SearchCriteria<ImageStoreVO> sc = regionSearch.create();
+        sc.setParameters("scope", ScopeType.REGION);
+        sc.setParameters("role", DataStoreRole.Image);
+        return listBy(sc);
+    }
+
+    @Override
+    public List<ImageStoreVO> findImageCacheByScope(ZoneScope scope) {
+        SearchCriteria<ImageStoreVO> sc = createSearchCriteria();
+        sc.addAnd("role", SearchCriteria.Op.EQ, DataStoreRole.ImageCache);
+        if (scope.getScopeId() != null) {
+            sc.addAnd("scope", SearchCriteria.Op.EQ, ScopeType.ZONE);
+            sc.addAnd("dcId", SearchCriteria.Op.EQ, scope.getScopeId());
+        }
+        return listBy(sc);
+    }
+
+    @Override
+    public List<ImageStoreVO> listImageStores() {
+        SearchCriteria<ImageStoreVO> sc = createSearchCriteria();
+        sc.addAnd("role", SearchCriteria.Op.EQ, DataStoreRole.Image);
+        return listBy(sc);
+    }
+
+    @Override
+    public List<ImageStoreVO> listImageCacheStores() {
+        SearchCriteria<ImageStoreVO> sc = createSearchCriteria();
+        sc.addAnd("role", SearchCriteria.Op.EQ, DataStoreRole.ImageCache);
+        return listBy(sc);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailVO.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailVO.java
index 6601437..fdfb734 100644
--- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailVO.java
+++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailVO.java
@@ -23,18 +23,18 @@ import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Table;
 
-import org.apache.cloudstack.api.InternalIdentity;
+import org.apache.cloudstack.api.ResourceDetail;
 
 @Entity
 @Table(name = "image_store_details")
-public class ImageStoreDetailVO implements InternalIdentity {
+public class ImageStoreDetailVO implements ResourceDetail {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     @Column(name = "id")
     long id;
 
     @Column(name = "store_id")
-    long storeId;
+    long resourceId;
 
     @Column(name = "name")
     String name;
@@ -42,13 +42,17 @@ public class ImageStoreDetailVO implements InternalIdentity {
     @Column(name = "value")
     String value;
 
+    @Column(name = "display")
+    private boolean display = true;
+
     public ImageStoreDetailVO() {
     }
 
-    public ImageStoreDetailVO(long storeId, String name, String value) {
-        this.storeId = storeId;
+    public ImageStoreDetailVO(long storeId, String name, String value, boolean display) {
+        this.resourceId = storeId;
         this.name = name;
         this.value = value;
+        this.display = display;
     }
 
     @Override
@@ -56,28 +60,24 @@ public class ImageStoreDetailVO implements InternalIdentity {
         return id;
     }
 
-    public long getStoreId() {
-        return storeId;
-    }
-
-    public void setStoreId(long storeId) {
-        this.storeId = storeId;
+    @Override
+    public long getResourceId() {
+        return resourceId;
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
-    public void setName(String name) {
-        this.name = name;
-    }
-
+    @Override
     public String getValue() {
         return value;
     }
 
-    public void setValue(String value) {
-        this.value = value;
+    @Override
+    public boolean isDisplay() {
+        return display;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailsDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailsDao.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailsDao.java
index 91fff28..04cd703 100644
--- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailsDao.java
+++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailsDao.java
@@ -18,9 +18,11 @@ package org.apache.cloudstack.storage.datastore.db;
 
 import java.util.Map;
 
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
+
 import com.cloud.utils.db.GenericDao;
 
-public interface ImageStoreDetailsDao extends GenericDao<ImageStoreDetailVO, Long> {
+public interface ImageStoreDetailsDao extends GenericDao<ImageStoreDetailVO, Long>, ResourceDetailsDao<ImageStoreDetailVO> {
 
     void update(long storeId, Map<String, String> details);
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailsDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailsDaoImpl.java
new file mode 100644
index 0000000..8e5ce77
--- /dev/null
+++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreDetailsDaoImpl.java
@@ -0,0 +1,119 @@
+// 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.storage.datastore.db;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.stereotype.Component;
+
+import com.cloud.utils.crypt.DBEncryptionUtil;
+import com.cloud.utils.db.QueryBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.TransactionLegacy;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.ConfigKey.Scope;
+import org.apache.cloudstack.framework.config.ScopedConfigStorage;
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
+
+@Component
+public class ImageStoreDetailsDaoImpl extends ResourceDetailsDaoBase<ImageStoreDetailVO> implements ImageStoreDetailsDao, ScopedConfigStorage {
+
+    protected final SearchBuilder<ImageStoreDetailVO> storeSearch;
+
+    public ImageStoreDetailsDaoImpl() {
+        super();
+        storeSearch = createSearchBuilder();
+        storeSearch.and("store", storeSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
+        storeSearch.done();
+    }
+
+    @Override
+    public void update(long storeId, Map<String, String> details) {
+        TransactionLegacy txn = TransactionLegacy.currentTxn();
+        SearchCriteria<ImageStoreDetailVO> sc = storeSearch.create();
+        sc.setParameters("store", storeId);
+
+        txn.start();
+        expunge(sc);
+        for (Map.Entry<String, String> entry : details.entrySet()) {
+            ImageStoreDetailVO detail = new ImageStoreDetailVO(storeId, entry.getKey(), entry.getValue(), true);
+            persist(detail);
+        }
+        txn.commit();
+    }
+
+    @Override
+    public Map<String, String> getDetails(long storeId) {
+        SearchCriteria<ImageStoreDetailVO> sc = storeSearch.create();
+        sc.setParameters("store", storeId);
+
+        List<ImageStoreDetailVO> details = listBy(sc);
+        Map<String, String> detailsMap = new HashMap<String, String>();
+        for (ImageStoreDetailVO detail : details) {
+            String name = detail.getName();
+            String value = detail.getValue();
+            if (name.equals(ApiConstants.KEY) || name.equals(ApiConstants.S3_SECRET_KEY)) {
+                value = DBEncryptionUtil.decrypt(value);
+            }
+            detailsMap.put(name, value);
+        }
+
+        return detailsMap;
+    }
+
+    @Override
+    public void deleteDetails(long storeId) {
+        SearchCriteria<ImageStoreDetailVO> sc = storeSearch.create();
+        sc.setParameters("store", storeId);
+
+        List<ImageStoreDetailVO> results = search(sc, null);
+        for (ImageStoreDetailVO result : results) {
+            remove(result.getId());
+        }
+    }
+
+    @Override
+    public Scope getScope() {
+        return ConfigKey.Scope.ImageStore;
+    }
+
+    @Override
+    public ImageStoreDetailVO findDetail(long storeId, String name) {
+        QueryBuilder<ImageStoreDetailVO> sc = QueryBuilder.create(ImageStoreDetailVO.class);
+        sc.and(sc.entity().getResourceId(), Op.EQ, storeId);
+        sc.and(sc.entity().getName(), Op.EQ, name);
+        return sc.find();
+    }
+
+    @Override
+    public String getConfigValue(long id, ConfigKey<?> key) {
+        ImageStoreDetailVO vo = findDetail(id, key.key());
+        return vo == null ? null : vo.getValue();
+    }
+
+    @Override
+    public void addDetail(long resourceId, String key, String value, boolean display) {
+        super.addDetail(new ImageStoreDetailVO(resourceId, key, value, display));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/storage/integration-test/test/resource/fakeDriverTestContext.xml
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/resource/fakeDriverTestContext.xml b/engine/storage/integration-test/test/resource/fakeDriverTestContext.xml
index b7ef363..c785f53 100644
--- a/engine/storage/integration-test/test/resource/fakeDriverTestContext.xml
+++ b/engine/storage/integration-test/test/resource/fakeDriverTestContext.xml
@@ -35,8 +35,8 @@
         </property>
     </bean>
 
-    <bean id="imageStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.ImageStoreDaoImpl" />
-    <bean id="imageStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.image.db.ImageStoreDetailsDaoImpl" />
+    <bean id="imageStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl" />
+    <bean id="imageStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDaoImpl" />
     <bean id="snapshotDataStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.SnapshotDataStoreDaoImpl" />
     <bean id="templateDataStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.TemplateDataStoreDaoImpl" />
     <bean id="volumeDataStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.VolumeDataStoreDaoImpl" />

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/storage/integration-test/test/resources/storageContext.xml
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/resources/storageContext.xml b/engine/storage/integration-test/test/resources/storageContext.xml
index c984515..667328f 100644
--- a/engine/storage/integration-test/test/resources/storageContext.xml
+++ b/engine/storage/integration-test/test/resources/storageContext.xml
@@ -35,8 +35,8 @@
     </property>
   </bean>
 
-<bean id="imageStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.ImageStoreDaoImpl" />
-  <bean id="imageStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.image.db.ImageStoreDetailsDaoImpl" /> 
+<bean id="imageStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl" />
+  <bean id="imageStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDaoImpl" /> 
   <bean id="snapshotDataStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.SnapshotDataStoreDaoImpl" /> 
   <bean id="templateDataStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.TemplateDataStoreDaoImpl" /> 
   <bean id="volumeDataStoreDaoImpl" class="org.apache.cloudstack.storage.image.db.VolumeDataStoreDaoImpl" />   

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java
index 28d9d46..c7aad89 100755
--- a/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java
@@ -24,22 +24,23 @@ import javax.inject.Inject;
 
 import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
 
+import com.cloud.capacity.CapacityManager;
+
 public abstract class NfsImageStoreDriverImpl extends BaseImageStoreDriverImpl {
 
     @Inject
     ImageStoreDetailsDao _imageStoreDetailsDao;
 
-    private static final String NFS_VERSION_DETAILS_KEY = "nfs.version";
-
     /**
      * Retrieve NFS version to be used for imgStoreId store, if provided in image_store_details table
      * @param imgStoreId store id
-     * @return "nfs.version" associated value for imgStoreId in image_store_details table if exists, null if not
+     * @return "secstorage.nfs.version" associated value for imgStoreId in image_store_details table if exists, null if not
      */
     protected Integer getNfsVersion(long imgStoreId){
         Map<String, String> imgStoreDetails = _imageStoreDetailsDao.getDetails(imgStoreId);
-        if (imgStoreDetails != null && imgStoreDetails.containsKey(NFS_VERSION_DETAILS_KEY)){
-            String nfsVersionParam = imgStoreDetails.get(NFS_VERSION_DETAILS_KEY);
+        String nfsVersionKey = CapacityManager.ImageStoreNFSVersion.key();
+        if (imgStoreDetails != null && imgStoreDetails.containsKey(nfsVersionKey)){
+            String nfsVersionParam = imgStoreDetails.get(nfsVersionKey);
             return (nfsVersionParam != null ? Integer.valueOf(nfsVersionParam) : null);
         }
         return null;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageStoreHelper.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageStoreHelper.java b/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageStoreHelper.java
index 5e29f71..dbb606b 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageStoreHelper.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageStoreHelper.java
@@ -129,15 +129,12 @@ public class ImageStoreHelper {
             Iterator<String> keyIter = details.keySet().iterator();
             while (keyIter.hasNext()) {
                 String key = keyIter.next().toString();
-                ImageStoreDetailVO detail = new ImageStoreDetailVO();
-                detail.setStoreId(store.getId());
-                detail.setName(key);
                 String value = details.get(key);
                 // encrypt swift key or s3 secret key
                 if (key.equals(ApiConstants.KEY) || key.equals(ApiConstants.S3_SECRET_KEY)) {
                     value = DBEncryptionUtil.encrypt(value);
                 }
-                detail.setValue(value);
+                ImageStoreDetailVO detail = new ImageStoreDetailVO(store.getId(), key, value, true);
                 imageStoreDetailsDao.persist(detail);
             }
         }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageStoreDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageStoreDaoImpl.java
deleted file mode 100644
index 13a7f47..0000000
--- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageStoreDaoImpl.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.storage.image.db;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.naming.ConfigurationException;
-
-import org.springframework.stereotype.Component;
-
-import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
-import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
-import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
-
-import com.cloud.storage.DataStoreRole;
-import com.cloud.storage.ScopeType;
-import com.cloud.utils.db.GenericDaoBase;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
-
-@Component
-public class ImageStoreDaoImpl extends GenericDaoBase<ImageStoreVO, Long> implements ImageStoreDao {
-    private SearchBuilder<ImageStoreVO> nameSearch;
-    private SearchBuilder<ImageStoreVO> providerSearch;
-    private SearchBuilder<ImageStoreVO> regionSearch;
-
-    @Override
-    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
-        super.configure(name, params);
-
-        nameSearch = createSearchBuilder();
-        nameSearch.and("name", nameSearch.entity().getName(), SearchCriteria.Op.EQ);
-        nameSearch.and("role", nameSearch.entity().getRole(), SearchCriteria.Op.EQ);
-        nameSearch.done();
-
-        providerSearch = createSearchBuilder();
-        providerSearch.and("providerName", providerSearch.entity().getProviderName(), SearchCriteria.Op.EQ);
-        providerSearch.and("role", providerSearch.entity().getRole(), SearchCriteria.Op.EQ);
-        providerSearch.done();
-
-        regionSearch = createSearchBuilder();
-        regionSearch.and("scope", regionSearch.entity().getScope(), SearchCriteria.Op.EQ);
-        regionSearch.and("role", regionSearch.entity().getRole(), SearchCriteria.Op.EQ);
-        regionSearch.done();
-
-        return true;
-    }
-
-    @Override
-    public ImageStoreVO findByName(String name) {
-        SearchCriteria<ImageStoreVO> sc = nameSearch.create();
-        sc.setParameters("name", name);
-        return findOneBy(sc);
-    }
-
-    @Override
-    public List<ImageStoreVO> findByProvider(String provider) {
-        SearchCriteria<ImageStoreVO> sc = providerSearch.create();
-        sc.setParameters("providerName", provider);
-        sc.setParameters("role", DataStoreRole.Image);
-        return listBy(sc);
-    }
-
-    @Override
-    public List<ImageStoreVO> findByScope(ZoneScope scope) {
-        SearchCriteria<ImageStoreVO> sc = createSearchCriteria();
-        sc.addAnd("role", SearchCriteria.Op.EQ, DataStoreRole.Image);
-        if (scope.getScopeId() != null) {
-            SearchCriteria<ImageStoreVO> scc = createSearchCriteria();
-            scc.addOr("scope", SearchCriteria.Op.EQ, ScopeType.REGION);
-            scc.addOr("dcId", SearchCriteria.Op.EQ, scope.getScopeId());
-            sc.addAnd("scope", SearchCriteria.Op.SC, scc);
-        }
-        // we should return all image stores if cross-zone scope is passed
-        // (scopeId = null)
-        return listBy(sc);
-    }
-
-    @Override
-    public List<ImageStoreVO> findRegionImageStores() {
-        SearchCriteria<ImageStoreVO> sc = regionSearch.create();
-        sc.setParameters("scope", ScopeType.REGION);
-        sc.setParameters("role", DataStoreRole.Image);
-        return listBy(sc);
-    }
-
-    @Override
-    public List<ImageStoreVO> findImageCacheByScope(ZoneScope scope) {
-        SearchCriteria<ImageStoreVO> sc = createSearchCriteria();
-        sc.addAnd("role", SearchCriteria.Op.EQ, DataStoreRole.ImageCache);
-        if (scope.getScopeId() != null) {
-            sc.addAnd("scope", SearchCriteria.Op.EQ, ScopeType.ZONE);
-            sc.addAnd("dcId", SearchCriteria.Op.EQ, scope.getScopeId());
-        }
-        return listBy(sc);
-    }
-
-    @Override
-    public List<ImageStoreVO> listImageStores() {
-        SearchCriteria<ImageStoreVO> sc = createSearchCriteria();
-        sc.addAnd("role", SearchCriteria.Op.EQ, DataStoreRole.Image);
-        return listBy(sc);
-    }
-
-    @Override
-    public List<ImageStoreVO> listImageCacheStores() {
-        SearchCriteria<ImageStoreVO> sc = createSearchCriteria();
-        sc.addAnd("role", SearchCriteria.Op.EQ, DataStoreRole.ImageCache);
-        return listBy(sc);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageStoreDetailsDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageStoreDetailsDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageStoreDetailsDaoImpl.java
deleted file mode 100644
index 2bfc38e..0000000
--- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageStoreDetailsDaoImpl.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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.storage.image.db;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-
-import org.springframework.stereotype.Component;
-
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailVO;
-import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
-
-import com.cloud.utils.crypt.DBEncryptionUtil;
-import com.cloud.utils.db.GenericDaoBase;
-import com.cloud.utils.db.SearchBuilder;
-import com.cloud.utils.db.SearchCriteria;
-import com.cloud.utils.db.TransactionLegacy;
-
-@Component
-public class ImageStoreDetailsDaoImpl extends GenericDaoBase<ImageStoreDetailVO, Long> implements ImageStoreDetailsDao {
-
-    protected final SearchBuilder<ImageStoreDetailVO> storeSearch;
-
-    protected ImageStoreDetailsDaoImpl() {
-        super();
-        storeSearch = createSearchBuilder();
-        storeSearch.and("store", storeSearch.entity().getStoreId(), SearchCriteria.Op.EQ);
-        storeSearch.done();
-    }
-
-    @Override
-    public void update(long storeId, Map<String, String> details) {
-        TransactionLegacy txn = TransactionLegacy.currentTxn();
-        SearchCriteria<ImageStoreDetailVO> sc = storeSearch.create();
-        sc.setParameters("store", storeId);
-
-        txn.start();
-        expunge(sc);
-        for (Map.Entry<String, String> entry : details.entrySet()) {
-            ImageStoreDetailVO detail = new ImageStoreDetailVO(storeId, entry.getKey(), entry.getValue());
-            persist(detail);
-        }
-        txn.commit();
-    }
-
-    @Override
-    public Map<String, String> getDetails(long storeId) {
-        SearchCriteria<ImageStoreDetailVO> sc = storeSearch.create();
-        sc.setParameters("store", storeId);
-
-        List<ImageStoreDetailVO> details = listBy(sc);
-        Map<String, String> detailsMap = new HashMap<String, String>();
-        for (ImageStoreDetailVO detail : details) {
-            String name = detail.getName();
-            String value = detail.getValue();
-            if (name.equals(ApiConstants.KEY) || name.equals(ApiConstants.S3_SECRET_KEY)) {
-                value = DBEncryptionUtil.decrypt(value);
-            }
-            detailsMap.put(name, value);
-        }
-
-        return detailsMap;
-    }
-
-    @Override
-    public void deleteDetails(long storeId) {
-        SearchCriteria<ImageStoreDetailVO> sc = storeSearch.create();
-        sc.setParameters("store", storeId);
-
-        List<ImageStoreDetailVO> results = search(sc, null);
-        for (ImageStoreDetailVO result : results) {
-            remove(result.getId());
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/framework/config/src/org/apache/cloudstack/framework/config/ConfigKey.java
----------------------------------------------------------------------
diff --git a/framework/config/src/org/apache/cloudstack/framework/config/ConfigKey.java b/framework/config/src/org/apache/cloudstack/framework/config/ConfigKey.java
index 09e143e..4a41306 100644
--- a/framework/config/src/org/apache/cloudstack/framework/config/ConfigKey.java
+++ b/framework/config/src/org/apache/cloudstack/framework/config/ConfigKey.java
@@ -31,7 +31,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
 public class ConfigKey<T> {
 
     public static enum Scope {
-        Global, Zone, Cluster, StoragePool, Account, ManagementServer
+        Global, Zone, Cluster, StoragePool, Account, ManagementServer, ImageStore
     }
 
     private final String _category;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
----------------------------------------------------------------------
diff --git a/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java b/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
index 4631bb9..e68fd3c 100644
--- a/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
+++ b/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
@@ -84,6 +84,7 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin {
         _scopeLevelConfigsMap.put(ConfigKey.Scope.Cluster, new HashSet<ConfigKey<?>>());
         _scopeLevelConfigsMap.put(ConfigKey.Scope.StoragePool, new HashSet<ConfigKey<?>>());
         _scopeLevelConfigsMap.put(ConfigKey.Scope.Account, new HashSet<ConfigKey<?>>());
+        _scopeLevelConfigsMap.put(ConfigKey.Scope.ImageStore, new HashSet<ConfigKey<?>>());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java
index 77abb65..7f1d5b8 100644
--- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java
+++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java
@@ -80,8 +80,8 @@ import org.apache.cloudstack.region.dao.RegionDaoImpl;
 import org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry;
 import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager;
 import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
-import org.apache.cloudstack.storage.image.db.ImageStoreDaoImpl;
 import org.apache.cloudstack.storage.image.db.TemplateDataStoreDaoImpl;
 import org.apache.cloudstack.usage.UsageService;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/server/src/com/cloud/capacity/CapacityManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java
index a3d2c3f..caf91a9 100644
--- a/server/src/com/cloud/capacity/CapacityManagerImpl.java
+++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java
@@ -1101,6 +1101,6 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
     @Override
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey<?>[] {CpuOverprovisioningFactor, MemOverprovisioningFactor, StorageCapacityDisableThreshold, StorageOverprovisioningFactor,
-            StorageAllocatedCapacityDisableThreshold, StorageOperationsExcludeCluster, VmwareCreateCloneFull};
+            StorageAllocatedCapacityDisableThreshold, StorageOperationsExcludeCluster, VmwareCreateCloneFull, ImageStoreNFSVersion};
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/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 2dd590c..06d8726 100644
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -81,6 +81,9 @@ import org.apache.cloudstack.region.PortableIpVO;
 import org.apache.cloudstack.region.Region;
 import org.apache.cloudstack.region.RegionVO;
 import org.apache.cloudstack.region.dao.RegionDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
@@ -216,6 +219,7 @@ import com.cloud.vm.dao.NicIpAliasDao;
 import com.cloud.vm.dao.NicIpAliasVO;
 import com.cloud.vm.dao.NicSecondaryIpDao;
 import com.cloud.vm.dao.VMInstanceDao;
+import com.google.common.base.Preconditions;
 
 public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable {
     public static final Logger s_logger = Logger.getLogger(ConfigurationManagerImpl.class);
@@ -335,6 +339,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
     AffinityGroupService _affinityGroupService;
     @Inject
     StorageManager _storageManager;
+    @Inject
+    ImageStoreDao _imageStoreDao;
+    @Inject
+    ImageStoreDetailsDao _imageStoreDetailsDao;
 
     // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao?
     @Inject
@@ -520,6 +528,13 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
                     _accountDetailsDao.update(accountDetailVO.getId(), accountDetailVO);
                 }
                 break;
+
+            case ImageStore:
+                final ImageStoreVO imgStore = _imageStoreDao.findById(resourceId);
+                Preconditions.checkState(imgStore != null);
+                _imageStoreDetailsDao.addDetail(resourceId, name, value, true);
+                break;
+
             default:
                 throw new InvalidParameterValueException("Scope provided is invalid");
             }
@@ -626,6 +641,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
         final Long clusterId = cmd.getClusterId();
         final Long storagepoolId = cmd.getStoragepoolId();
         final Long accountId = cmd.getAccountId();
+        final Long imageStoreId = cmd.getImageStoreId();
         CallContext.current().setEventDetails(" Name: " + name + " New Value: " + (name.toLowerCase().contains("password") ? "*****" : value == null ? "" : value));
         // check if config value exists
         final ConfigurationVO config = _configDao.findByName(name);
@@ -676,6 +692,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
             id = storagepoolId;
             paramCountCheck++;
         }
+        if (imageStoreId != null) {
+            scope = ConfigKey.Scope.ImageStore.toString();
+            id = imageStoreId;
+            paramCountCheck++;
+        }
 
         if (paramCountCheck > 1) {
             throw new InvalidParameterValueException("cannot handle multiple IDs, provide only one ID corresponding to the scope");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 82f8030..b6a2637 100644
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -1672,6 +1672,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         final Long clusterId = cmd.getClusterId();
         final Long storagepoolId = cmd.getStoragepoolId();
         final Long accountId = cmd.getAccountId();
+        final Long imageStoreId = cmd.getImageStoreId();
         String scope = null;
         Long id = null;
         int paramCountCheck = 0;
@@ -1696,6 +1697,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
             id = storagepoolId;
             paramCountCheck++;
         }
+        if (imageStoreId != null) {
+            scope = ConfigKey.Scope.ImageStore.toString();
+            id = imageStoreId;
+            paramCountCheck++;
+        }
 
         if (paramCountCheck > 1) {
             throw new InvalidParameterValueException("cannot handle multiple IDs, provide only one ID corresponding to the scope");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/server/src/com/cloud/storage/ImageStoreDetailsUtil.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java
index 7107650..3e27ce6 100755
--- a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java
+++ b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java
@@ -20,48 +20,64 @@ import java.util.Map;
 
 import javax.inject.Inject;
 
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
 import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
 import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
 import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
 
+import com.cloud.capacity.CapacityManager;
+import com.google.common.base.Preconditions;
+
 public class ImageStoreDetailsUtil {
 
     @Inject
     protected ImageStoreDao imageStoreDao;
     @Inject
     protected ImageStoreDetailsDao imageStoreDetailsDao;
+    @Inject
+    protected ConfigurationDao configurationDao;
 
     /**
-     * Obtain NFS protocol version (if provided) for a store id.<br/>
-     * It can be set by adding an entry in {@code image_store_details} table, providing {@code name=nfs.version} and {@code value=X} (e.g. 3)
+     * Retrieve global secondary storage NFS version default value
+     * @return global default value
+     */
+    protected Integer getGlobalDefaultNfsVersion(){
+        ConfigurationVO globalNfsVersion = configurationDao.findByName(CapacityManager.ImageStoreNFSVersion.key());
+        Preconditions.checkState(globalNfsVersion != null, "Unable to find global NFS version for version key " + CapacityManager.ImageStoreNFSVersion.key());
+        String value = globalNfsVersion.getValue();
+        return (value != null ? Integer.valueOf(value) : null);
+    }
+    /**
+     * Obtain NFS protocol version (if provided) for a store id, if not use default config value<br/>
      * @param storeId image store id
-     * @return {@code null} if {@code nfs.version} is not found for storeId <br/>
-     * {@code X} if {@code nfs.version} is found found for storeId
+     * @return {@code null} if {@code secstorage.nfs.version} is not found for storeId <br/>
+     * {@code X} if {@code secstorage.nfs.version} is found found for storeId
      */
     public Integer getNfsVersion(long storeId) throws NumberFormatException {
-        String nfsVersion = null;
-        if (imageStoreDetailsDao.getDetails(storeId) != null){
-            Map<String, String> storeDetails = imageStoreDetailsDao.getDetails(storeId);
-            if (storeDetails != null && storeDetails.containsKey("nfs.version")){
-                nfsVersion = storeDetails.get("nfs.version");
-            }
+
+        final Map<String, String> storeDetails = imageStoreDetailsDao.getDetails(storeId);
+        if (storeDetails != null && storeDetails.containsKey(CapacityManager.ImageStoreNFSVersion.key())) {
+            final String version = storeDetails.get(CapacityManager.ImageStoreNFSVersion.key());
+            return (version != null ? Integer.valueOf(version) : null);
         }
-        return (nfsVersion != null ? Integer.valueOf(nfsVersion) : null);
+
+        return getGlobalDefaultNfsVersion();
+
     }
 
     /**
      * Obtain NFS protocol version (if provided) for a store uuid.<br/>
-     * It can be set by adding an entry in {@code image_store_details} table, providing {@code name=nfs.version} and {@code value=X} (e.g. 3)
-     * @param storeId image store id
-     * @return {@code null} if {@code nfs.version} is not found for storeUuid <br/>
-     * {@code X} if {@code nfs.version} is found found for storeUuid
+     * @param resourceId image store id
+     * @return {@code null} if {@code secstorage.nfs.version} is not found for storeUuid <br/>
+     * {@code X} if {@code secstorage.nfs.version} is found found for storeUuid
      */
     public Integer getNfsVersionByUuid(String storeUuid){
         ImageStoreVO imageStore = imageStoreDao.findByUuid(storeUuid);
         if (imageStore != null){
             return getNfsVersion(imageStore.getId());
         }
-        return null;
+        return getGlobalDefaultNfsVersion();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java
index 4b3ce40..7efbe08 100755
--- a/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java
+++ b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java
@@ -17,42 +17,54 @@
 package com.cloud.storage;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
 import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
 import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
 import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.cloud.capacity.CapacityManager;
+
 public class ImageStoreDetailsUtilTest {
 
     private final static long STORE_ID = 1l;
     private final static String STORE_UUID = "aaaa-aaaa-aaaa-aaaa";
     private final static Integer NFS_VERSION = 3;
+    private final static Integer NFS_VERSION_DEFAULT = 2;
 
     ImageStoreDetailsUtil imageStoreDetailsUtil = new ImageStoreDetailsUtil();
 
     ImageStoreDao imgStoreDao = mock(ImageStoreDao.class);
     ImageStoreDetailsDao imgStoreDetailsDao = mock(ImageStoreDetailsDao.class);
+    ConfigurationDao configurationDao = mock(ConfigurationDao.class);
 
     @Before
     public void setup() throws Exception {
         Map<String, String> imgStoreDetails = new HashMap<String, String>();
-        imgStoreDetails.put("nfs.version", String.valueOf(NFS_VERSION));
+        String nfsVersionKey = CapacityManager.ImageStoreNFSVersion.key();
+        imgStoreDetails.put(nfsVersionKey, String.valueOf(NFS_VERSION));
         when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails);
 
         ImageStoreVO imgStoreVO = mock(ImageStoreVO.class);
         when(imgStoreVO.getId()).thenReturn(Long.valueOf(STORE_ID));
         when(imgStoreDao.findByUuid(STORE_UUID)).thenReturn(imgStoreVO);
 
+        ConfigurationVO confVO = mock(ConfigurationVO.class);
+        String defaultValue = (NFS_VERSION_DEFAULT == null ? null : String.valueOf(NFS_VERSION_DEFAULT));
+        when(confVO.getValue()).thenReturn(defaultValue);
+        when(configurationDao.findByName(nfsVersionKey)).thenReturn(confVO);
+
         imageStoreDetailsUtil.imageStoreDao = imgStoreDao;
         imageStoreDetailsUtil.imageStoreDetailsDao = imgStoreDetailsDao;
+        imageStoreDetailsUtil.configurationDao = configurationDao;
     }
 
     @Test
@@ -68,7 +80,7 @@ public class ImageStoreDetailsUtilTest {
         when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails);
 
         Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID);
-        assertNull(nfsVersion);
+        assertEquals(NFS_VERSION_DEFAULT, nfsVersion);
     }
 
     @Test
@@ -77,7 +89,7 @@ public class ImageStoreDetailsUtilTest {
         when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails);
 
         Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID);
-        assertNull(nfsVersion);
+        assertEquals(NFS_VERSION_DEFAULT, nfsVersion);
     }
 
     @Test
@@ -90,6 +102,12 @@ public class ImageStoreDetailsUtilTest {
     public void testGetNfsVersionByUuidNoImgStore(){
         when(imgStoreDao.findByUuid(STORE_UUID)).thenReturn(null);
         Integer nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID);
-        assertNull(nfsVersion);
+        assertEquals(NFS_VERSION_DEFAULT, nfsVersion);
+    }
+
+    @Test
+    public void testGetGlobalDefaultNfsVersion(){
+        Integer globalDefaultNfsVersion = imageStoreDetailsUtil.getGlobalDefaultNfsVersion();
+        assertEquals(NFS_VERSION_DEFAULT, globalDefaultNfsVersion);
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/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 343589c..0a38158 100644
--- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
+++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
@@ -41,6 +41,8 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.region.PortableIpDaoImpl;
 import org.apache.cloudstack.region.PortableIpRangeDaoImpl;
 import org.apache.cloudstack.region.dao.RegionDaoImpl;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDaoImpl;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
 import org.apache.cloudstack.test.utils.SpringUtils;
 
@@ -131,7 +133,7 @@ import com.cloud.vm.dao.VMInstanceDaoImpl;
     NetworkDomainDaoImpl.class, HostDetailsDaoImpl.class, HostTagsDaoImpl.class, ClusterDaoImpl.class, FirewallRulesDaoImpl.class,
     FirewallRulesCidrsDaoImpl.class, PhysicalNetworkDaoImpl.class, PhysicalNetworkTrafficTypeDaoImpl.class, PhysicalNetworkServiceProviderDaoImpl.class,
     LoadBalancerDaoImpl.class, NetworkServiceMapDaoImpl.class, PrimaryDataStoreDaoImpl.class, StoragePoolDetailsDaoImpl.class,
-    PortableIpRangeDaoImpl.class, RegionDaoImpl.class, PortableIpDaoImpl.class, AccountGuestVlanMapDaoImpl.class},
+    PortableIpRangeDaoImpl.class, RegionDaoImpl.class, PortableIpDaoImpl.class, AccountGuestVlanMapDaoImpl.class, ImageStoreDaoImpl.class, ImageStoreDetailsDaoImpl.class},
                includeFilters = {@Filter(value = ChildTestConfiguration.Library.class, type = FilterType.CUSTOM)},
                useDefaultFilters = false)
 public class

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/setup/db/db/schema-481to490.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql
index bd1dd82..0064d6f 100644
--- a/setup/db/db/schema-481to490.sql
+++ b/setup/db/db/schema-481to490.sql
@@ -545,3 +545,6 @@ INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervis
 INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 228, now(), 0);
 INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 228, now(), 0);
 INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 228, now(), 0);
+
+ALTER TABLE `cloud`.`image_store_details` CHANGE COLUMN `value` `value` VARCHAR(255) NULL DEFAULT NULL COMMENT 'value of the detail', ADD COLUMN `display` tinyint(1) NOT 
+NULL DEFAULT '1' COMMENT 'True if the detail can be displayed to the end user' AFTER `value`;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/test/integration/smoke/test_ssvm.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_ssvm.py b/test/integration/smoke/test_ssvm.py
index 81dba32..b14883c 100644
--- a/test/integration/smoke/test_ssvm.py
+++ b/test/integration/smoke/test_ssvm.py
@@ -20,12 +20,13 @@
 from marvin.cloudstackTestCase import cloudstackTestCase
 from marvin.cloudstackAPI import (stopSystemVm,
                                   rebootSystemVm,
-                                  destroySystemVm)
+                                  destroySystemVm, updateConfiguration)
 from marvin.lib.utils import (cleanup_resources,
                               get_process_status,
-                              get_host_credentials)
+                              get_host_credentials,
+                              wait_until)
 from marvin.lib.base import (PhysicalNetwork,
-                             NetScaler)
+                             NetScaler, ImageStore)
 from marvin.lib.common import (get_zone,
                                list_hosts,
                                list_ssvms,
@@ -33,6 +34,7 @@ from marvin.lib.common import (get_zone,
                                list_vlan_ipranges)
 from nose.plugins.attrib import attr
 import telnetlib
+import logging
 
 # Import System modules
 import time
@@ -42,12 +44,19 @@ _multiprocess_shared_ = True
 class TestSSVMs(cloudstackTestCase):
 
     def setUp(self):
+	test_case = super(TestSSVMs, self)
         self.apiclient = self.testClient.getApiClient()
         self.hypervisor = self.testClient.getHypervisorInfo()
         self.cleanup = []
+        self.config = test_case.getClsConfig()
         self.services = self.testClient.getParsedTestDataConfig()
         self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
 
+        self.logger = logging.getLogger('TestSSVMs')
+        self.stream_handler = logging.StreamHandler()
+        self.logger.setLevel(logging.DEBUG)
+        self.logger.addHandler(self.stream_handler)
+
         # Default sleep is set to 90 seconds, which is too long if the SSVM takes up to 2min to start.
         # Second sleep in the loop will waste test time.
         self.services["sleep"] = 30
@@ -1197,3 +1206,162 @@ class TestSSVMs(cloudstackTestCase):
         # Call to verify cloud process is running
         self.test_04_cpvm_internals()
         return
+
+    @attr(
+        tags=[
+            "advanced",
+            "advancedns",
+            "smoke",
+            "basic",
+            "sg"],
+        required_hardware="true")
+    def test_11_ss_nfs_version_on_ssvm(self):
+        """Test NFS Version on Secondary Storage mounted properly on SSVM
+        """
+
+        # 1) List SSVM in zone
+        # 2) Get id and url from mounted nfs store
+        # 3) Update NFS version for previous image store
+        # 4) Stop SSVM
+        # 5) Check NFS version of mounted nfs store after SSVM starts 
+
+        nfs_version = self.config.nfsVersion
+        if nfs_version == None:
+            self.skipTest('No NFS version provided in test data')
+
+        #List SSVM for zone id
+        list_ssvm_response = list_ssvms(
+            self.apiclient,
+            systemvmtype='secondarystoragevm',
+            state='Running',
+            zoneid=self.zone.id
+        )
+        self.assertNotEqual(
+            list_ssvm_response,
+            None
+        )
+        self.assertEqual(
+            isinstance(list_ssvm_response, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertEqual(
+            len(list_ssvm_response),
+            1,
+            "Check list System VMs response"
+        )
+
+        ssvm = list_ssvm_response[0]
+        image_stores_response = ImageStore.list(self.apiclient,zoneid=self.zone.id)
+
+        if self.hypervisor.lower() in ('vmware', 'hyperv'):
+            # SSH into SSVMs is done via management server for Vmware and Hyper-V
+            result = get_process_status(
+                self.apiclient.connection.mgtSvr,
+                22,
+                self.apiclient.connection.user,
+                self.apiclient.connection.passwd,
+                ssvm.privateip,
+                "mount | grep 'type nfs'",
+                hypervisor=self.hypervisor)
+
+        for res in result:
+            split_res = res.split("on")
+            mounted_img_store_url = split_res[0].strip()
+            for img_store in image_stores_response:
+                img_store_url = str(img_store.url)
+                if img_store_url.startswith("nfs://"):
+                    img_store_url = img_store_url[6:]
+                    #Add colon after ip address to match output from mount command
+                    first_slash = img_store_url.find('/')
+                    img_store_url = img_store_url[0:first_slash] + ':' + img_store_url[first_slash:]
+                    if img_store_url == mounted_img_store_url:
+                        img_store_id = img_store.id
+                        break
+
+        self.assertNotEqual(
+            img_store_id,
+            None,
+            "Check image store id mounted on SSVM"
+        )
+
+        #Update NFS version for image store mounted on SSVM
+        updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
+        updateConfigurationCmd.name = "secstorage.nfs.version"
+        updateConfigurationCmd.value = nfs_version
+        updateConfigurationCmd.imagestoreuuid = img_store_id
+
+        updateConfigurationResponse = self.apiclient.updateConfiguration(updateConfigurationCmd)
+        self.logger.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))
+
+        #Stop SSVM
+        self.debug("Stopping SSVM: %s" % ssvm.id)
+        cmd = stopSystemVm.stopSystemVmCmd()
+        cmd.id = ssvm.id
+        self.apiclient.stopSystemVm(cmd)
+
+        def checkForRunningSSVM():
+            new_list_ssvm_response = list_ssvms(
+                self.apiclient,
+                id=ssvm.id
+            )
+            if isinstance(new_list_ssvm_response, list):
+                return new_list_ssvm_response[0].state == 'Running', None                
+            
+        res, _ = wait_until(self.services["sleep"], self.services["timeout"], checkForRunningSSVM)
+        if not res:
+            self.fail("List SSVM call failed!")
+        
+        new_list_ssvm_response = list_ssvms(
+                self.apiclient,
+                id=ssvm.id
+        )
+
+        self.assertNotEqual(
+            new_list_ssvm_response,
+            None
+        )
+        self.assertEqual(
+            isinstance(new_list_ssvm_response, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        ssvm = new_list_ssvm_response[0]
+        self.debug("SSVM state after debug: %s" % ssvm.state)
+        self.assertEqual(
+            ssvm.state,
+            'Running',
+            "Check whether SSVM is running or not"
+        )
+        # Wait for the agent to be up
+        self.waitForSystemVMAgent(ssvm.name)
+
+        #Check NFS version on mounted image store
+        result = get_process_status(
+                self.apiclient.connection.mgtSvr,
+                22,
+                self.apiclient.connection.user,
+                self.apiclient.connection.passwd,
+                ssvm.privateip,
+                "mount | grep '%s'"%mounted_img_store_url,
+                hypervisor=self.hypervisor)
+
+        self.assertNotEqual(
+            result,
+            None
+        )
+        self.assertEqual(
+            len(result),
+            1,
+            "Check result length"
+        )
+
+        res = result[0]
+        mounted_nfs_version = res.split("vers=")[1][0:1]
+        self.assertEqual(
+            int(mounted_nfs_version),
+            int(nfs_version),
+            "Check mounted NFS version to be the same as provided"
+        )
+
+        return

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2e774966/ui/scripts/system.js
----------------------------------------------------------------------
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 7ffacd0..0ff633c 100644
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -19974,28 +19974,58 @@
                                                 }
                                             });
                                         }
-                                    }
-
-                                    // Granular settings for storage pool for secondary storage is not required
-                                    /*  settings: {
-                                    title: 'label.menu.global.settings',
-                                    custom: cloudStack.uiCustom.granularSettings({
-                                    dataProvider: function(args) {
-                                    args.response.success({
-                                    data: [
-                                    { name: 'config.param.1', value: 1 },
-                                    { name: 'config.param.2', value: 2 }
-                                    ]
-                                    });
                                     },
-                                    actions: {
-                                    edit: function(args) {
-                                    // call updateStorageLevelParameters
-                                    args.response.success();
-                                    }
-                                    }
-                                    })
-                                    } */
+
+                                    // Granular settings for image store
+									settings: {
+										title: 'label.settings',
+										custom: cloudStack.uiCustom.granularSettings({
+											dataProvider: function (args) {
+
+												$.ajax({
+													url: createURL('listConfigurations&imagestoreuuid=' + args.context.secondaryStorage[0].id),
+													data: listViewDataProvider(args, {
+													},
+													{
+														searchBy: 'name'
+													}),
+													success: function (json) {
+														args.response.success({
+															data: json.listconfigurationsresponse.configuration
+														});
+													},
+
+													error: function (json) {
+														args.response.error(parseXMLHttpResponse(json));
+													}
+												});
+											},
+											actions: {
+												edit: function (args) {
+													// call updateStorageLevelParameters
+													var data = {
+														name: args.data.jsonObj.name,
+														value: args.data.value
+													};
+
+													$.ajax({
+														url: createURL('updateConfiguration&imagestoreuuid=' + args.context.secondaryStorage[0].id),
+														data: data,
+														success: function (json) {
+															var item = json.updateconfigurationresponse.configuration;
+															args.response.success({
+																data: item
+															});
+														},
+
+														error: function (json) {
+															args.response.error(parseXMLHttpResponse(json));
+														}
+													});
+												}
+											}
+										})
+									}
                                 }
                             }
                         }


Mime
View raw message