You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by de...@apache.org on 2013/12/11 12:59:28 UTC

git commit: updated refs/heads/4.3 to 5dea772

Updated Branches:
  refs/heads/4.3 db4e0d688 -> 5dea7728a


CLOUDSTACK-5248: Fixed creation of mount point when running as non root (cloud) user.
The systemvm iso file is copied only when a systemvm or router vm is to be started on
a host. The file gets copied to the secondary storage. The mount point used is the one
that has permissions for regular user to mount a share.
CLOUDSTACK-5275: The failure was because a secondary storage wasn't available when the
host was added. When a setup is done through wizard the hosts get added before the
secondary storage. CS was tying to copy yhe systemvm iso to secondary and it used to
fail if it wasn't available. Made a change to copy the iso only when a systemvm is
being started on a host.
CLOUDSTACK-5202: Made changes to clean up mount points on stop and start.

All the three are related fixes; so putting a fix in one commit.


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

Branch: refs/heads/4.3
Commit: 5dea7728a3f8da4d2af21ad117ba052cb3f788fc
Parents: db4e0d6
Author: Devdeep Singh <de...@gmail.com>
Authored: Wed Dec 11 17:22:45 2013 +0530
Committer: Devdeep Singh <de...@gmail.com>
Committed: Wed Dec 11 17:22:45 2013 +0530

----------------------------------------------------------------------
 core/src/com/cloud/agent/api/SetupCommand.java  |  20 -
 core/src/com/cloud/agent/api/StartCommand.java  |  10 +
 .../HypervResource/HypervResourceController.cs  |  50 ++-
 .../ServerResource/HypervResource/WmiCallsV2.cs |   5 +-
 .../core/spring-hyperv-core-context.xml         |  32 ++
 .../discoverer/HypervServerDiscoverer.java      | 201 ----------
 .../hyperv/manager/HypervManager.java           |  24 ++
 .../hyperv/manager/HypervManagerImpl.java       | 367 +++++++++++++++++++
 .../resource/HypervDirectConnectResource.java   |  67 +++-
 9 files changed, 520 insertions(+), 256 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5dea7728/core/src/com/cloud/agent/api/SetupCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/SetupCommand.java b/core/src/com/cloud/agent/api/SetupCommand.java
index 65700e9..ee43c59 100644
--- a/core/src/com/cloud/agent/api/SetupCommand.java
+++ b/core/src/com/cloud/agent/api/SetupCommand.java
@@ -23,8 +23,6 @@ public class SetupCommand extends Command {
     HostEnvironment env;
     boolean multipath;
     boolean needSetup;
-    String secondaryStorage;
-    String systemVmIso;
 
     public boolean needSetup() {
         return needSetup;
@@ -38,8 +36,6 @@ public class SetupCommand extends Command {
         this.env = env;
         this.multipath = false;
         this.needSetup = false;
-        secondaryStorage = null;
-        systemVmIso = null;
     }
 
     public HostEnvironment getEnvironment() {
@@ -57,22 +53,6 @@ public class SetupCommand extends Command {
         return multipath;
     }
 
-    public void setSecondaryStorage(String secondaryStorage) {
-        this.secondaryStorage = secondaryStorage;
-    }
-
-    public String getSecondaryStorage() {
-        return this.secondaryStorage;
-    }
-
-    public void setSystemVmIso(String systemVmIso) {
-        this.systemVmIso = systemVmIso;
-    }
-
-    public String getSystemVmIso() {
-        return this.systemVmIso;
-    }
-
     @Override
     public boolean executeInSequence() {
         return true;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5dea7728/core/src/com/cloud/agent/api/StartCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/StartCommand.java b/core/src/com/cloud/agent/api/StartCommand.java
index 308730a..88810c6 100644
--- a/core/src/com/cloud/agent/api/StartCommand.java
+++ b/core/src/com/cloud/agent/api/StartCommand.java
@@ -25,6 +25,7 @@ public class StartCommand extends Command {
     VirtualMachineTO vm;
     String hostIp;
     boolean executeInSequence = false;
+    String secondaryStorage;
 
     public VirtualMachineTO getVirtualMachine() {
         return vm;
@@ -42,9 +43,18 @@ public class StartCommand extends Command {
         this.vm = vm;
         this.hostIp = host.getPrivateIpAddress();
         this.executeInSequence = executeInSequence;
+        this.secondaryStorage = null;
     }
 
     public String getHostIp() {
         return this.hostIp;
     }
+
+    public String getSecondaryStorage() {
+        return this.secondaryStorage;
+    }
+
+    public void setSecondaryStorage(String secondary) {
+        this.secondaryStorage = secondary;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5dea7728/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
index 201d580..f5a76cf 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
@@ -141,7 +141,7 @@ namespace HypervResource
         public static HypervResourceControllerConfig config = new HypervResourceControllerConfig();
 
         private static ILog logger = LogManager.GetLogger(typeof(HypervResourceController));
-        private static string systemVmIso;
+        private string systemVmIso  = "";
         Dictionary<String, String> contextMap = new Dictionary<String, String>();
 
         public static void Initialize()
@@ -179,19 +179,6 @@ namespace HypervResource
 
                 try
                 {
-                    NFSTO share = new NFSTO();
-                    String uriStr = (String)cmd.secondaryStorage;
-                    share.uri = new Uri(uriStr);
-
-                    string systemVmIso = (string)cmd.systemVmIso;
-                    string defaultDataPath = wmiCallsV2.GetDefaultDataRoot();
-                    string isoPath = Path.Combine(defaultDataPath, Path.GetFileName(systemVmIso));
-                    if (!File.Exists(isoPath))
-                    {
-                        logger.Info("File " + isoPath + " not found. Copying it from the secondary share.");
-                        Utils.DownloadCifsFileToLocalFile(systemVmIso, share, isoPath);
-                    }
-                    HypervResourceController.systemVmIso = isoPath;
                     result = true;
                 }
                 catch (Exception sysEx)
@@ -957,7 +944,40 @@ namespace HypervResource
 
                 try
                 {
-                    wmiCallsV2.DeployVirtualMachine(cmd, systemVmIso);
+                    string systemVmIsoPath = systemVmIso;
+                    lock (systemVmIso)
+                    {
+                        systemVmIsoPath = systemVmIso;
+                        String uriStr = (String)cmd.secondaryStorage;
+                        if (!String.IsNullOrEmpty(uriStr))
+                        {
+                            if (String.IsNullOrEmpty(systemVmIsoPath) || !File.Exists(systemVmIsoPath))
+                            {
+                                NFSTO share = new NFSTO();
+                                share.uri = new Uri(uriStr);
+                                string defaultDataPath = wmiCallsV2.GetDefaultDataRoot();
+
+                                string secondaryPath = Path.Combine(share.UncPath, "systemvm").Replace(@"/", @"\");
+                                string[] choices = choices = Directory.GetFiles(secondaryPath, "systemvm*.iso");
+                                if (choices.Length != 1)
+                                {
+                                    String errMsg = "Couldn't locate the systemvm iso on " + secondaryPath;
+                                    logger.Debug(errMsg);
+                                }
+                                else
+                                {
+                                    systemVmIsoPath = Path.Combine(defaultDataPath, Path.GetFileName(choices[0]));
+                                    if (!File.Exists(systemVmIsoPath))
+                                    {
+                                        Utils.DownloadCifsFileToLocalFile(choices[0], share, systemVmIsoPath);
+                                    }
+                                    systemVmIso = systemVmIsoPath;
+                                }
+                            }
+                        }
+                    }
+
+                    wmiCallsV2.DeployVirtualMachine(cmd, systemVmIsoPath);
                     result = true;
                 }
                 catch (Exception wmiEx)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5dea7728/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
index c6c039a..b2feab3 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
@@ -453,7 +453,10 @@ namespace HypervResource
             // call patch systemvm iso only for systemvms
             if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-"))
             {
-                patchSystemVmIso(vmName, systemVmIso);
+                if (systemVmIso != null && systemVmIso.Length != 0)
+                {
+                    patchSystemVmIso(vmName, systemVmIso);
+                }
             }
 
             logger.DebugFormat("Starting VM {0}", vmName);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5dea7728/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/core/spring-hyperv-core-context.xml
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/core/spring-hyperv-core-context.xml b/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/core/spring-hyperv-core-context.xml
new file mode 100644
index 0000000..84d50ca
--- /dev/null
+++ b/plugins/hypervisors/hyperv/resources/META-INF/cloudstack/core/spring-hyperv-core-context.xml
@@ -0,0 +1,32 @@
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+                      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
+                      http://www.springframework.org/schema/context
+                      http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+                      >
+
+    <bean id="HypervManager" class="com.cloud.hypervisor.hyperv.manager.HypervManagerImpl" />
+    <bean id="HypervDirectConnectResource" class="com.cloud.hypervisor.hyperv.resource.HypervDirectConnectResource" />
+</beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5dea7728/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java
index c5fb60a..2330da1 100644
--- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java
@@ -114,8 +114,6 @@ public class HypervServerDiscoverer extends DiscovererBase implements
     private HostPodDao _podDao;
     @Inject
     private DataCenterDao _dcDao;
-    @Inject
-    DataStoreManager _dataStoreMgr;
 
     // TODO: AgentManager and AlertManager not being used to transmit info,
     // may want to reconsider.
@@ -177,17 +175,8 @@ public class HypervServerDiscoverer extends DiscovererBase implements
             s_logger.debug("Setting up host " + agentId);
         }
 
-        String secondaryStorageUri = getSecondaryStorageStoreUrl(cluster.getDataCenterId());
-        if (secondaryStorageUri == null) {
-            s_logger.debug("Secondary storage uri for dc " + cluster.getDataCenterId() + " couldn't be obtained");
-        } else {
-            prepareSecondaryStorageStore(secondaryStorageUri);
-        }
-
         HostEnvironment env = new HostEnvironment();
         SetupCommand setup = new SetupCommand(env);
-        setup.setSecondaryStorage(secondaryStorageUri);
-        setup.setSystemVmIso("systemvm/" + getSystemVMIsoFileNameOnDatastore());
         if (!host.isSetup()) {
             setup.setNeedSetup(true);
         }
@@ -332,7 +321,6 @@ public class HypervServerDiscoverer extends DiscovererBase implements
             params.put("cluster", Long.toString(clusterId));
             params.put("guid", guidWithTail);
             params.put("ipaddress", agentIp);
-            params.put("sec.storage.url", getSecondaryStorageStoreUrl(dcId));
 
             // Hyper-V specific settings
             Map<String, String> details = new HashMap<String, String>();
@@ -383,177 +371,6 @@ public class HypervServerDiscoverer extends DiscovererBase implements
         }
         return null;
     }
-    
-
-    private void prepareSecondaryStorageStore(String storageUrl) {
-        String mountPoint = getMountPoint(storageUrl);
-
-        GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm");
-        try {
-            if(lock.lock(3600)) {
-                try {
-                    File patchFolder = new File(mountPoint + "/systemvm");
-                    if(!patchFolder.exists()) {
-                        if(!patchFolder.mkdirs()) {
-                            String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder.toString();
-                            s_logger.error(msg);
-                            throw new CloudRuntimeException(msg);
-                        }
-                    }
-
-                    File srcIso = getSystemVMPatchIsoFile();
-                    File destIso = new File(mountPoint + "/systemvm/" + getSystemVMIsoFileNameOnDatastore());
-                    if(!destIso.exists()) {
-                        s_logger.info("Copy System VM patch ISO file to secondary storage. source ISO: " +
-                                srcIso.getAbsolutePath() + ", destination: " + destIso.getAbsolutePath());
-                        try {
-                            FileUtil.copyfile(srcIso, destIso);
-                        } catch(IOException e) {
-                            s_logger.error("Unexpected exception ", e);
-
-                            String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso.toString() + ", dest location: " + destIso;
-                            s_logger.error(msg);
-                            throw new CloudRuntimeException(msg);
-                        }
-                    } else {
-                        if(s_logger.isTraceEnabled()) {
-                            s_logger.trace("SystemVM ISO file " + destIso.getPath() + " already exists");
-                        }
-                    }
-                } finally {
-                    lock.unlock();
-                }
-            }
-        } finally {
-            lock.releaseRef();
-        }
-    }
-
-    private String getMountPoint(String storageUrl) {
-        String mountPoint = null;
-        synchronized(_storageMounts) {
-            mountPoint = _storageMounts.get(storageUrl);
-            if(mountPoint != null) {
-                return mountPoint;
-            }
-
-            URI uri;
-            try {
-                uri = new URI(storageUrl);
-            } catch (URISyntaxException e) {
-                s_logger.error("Invalid storage URL format ", e);
-                throw new CloudRuntimeException("Unable to create mount point due to invalid storage URL format " + storageUrl);
-            }
-
-            mountPoint = mount(File.separator + File.separator + uri.getHost() + uri.getPath(), _mountParent,
-                    uri.getScheme(), uri.getQuery());
-            if(mountPoint == null) {
-                s_logger.error("Unable to create mount point for " + storageUrl);
-                return "/mnt/sec";
-            }
-
-            _storageMounts.put(storageUrl, mountPoint);
-            return mountPoint;
-        }
-    }
-
-    protected String mount(String path, String parent, String scheme, String query) {
-        String mountPoint = setupMountPoint(parent);
-        if (mountPoint == null) {
-            s_logger.warn("Unable to create a mount point");
-            return null;
-        }
-
-        Script script = null;
-        String result = null;
-        if (scheme.equals("cifs")) {
-            Script command = new Script(true, "mount", _timeout, s_logger);
-            command.add("-t", "cifs");
-            command.add(path);
-            command.add(mountPoint);
-
-            if (query != null) {
-                query = query.replace('&', ',');
-                command.add("-o", query);
-            }
-            result = command.execute();
-        }
-
-        if (result != null) {
-            s_logger.warn("Unable to mount " + path + " due to " + result);
-            File file = new File(mountPoint);
-            if (file.exists()) {
-                file.delete();
-            }
-            return null;
-        }
-
-        // Change permissions for the mountpoint
-        script = new Script(true, "chmod", _timeout, s_logger);
-        script.add("-R", "777", mountPoint);
-        result = script.execute();
-        if (result != null) {
-            s_logger.warn("Unable to set permissions for " + mountPoint + " due to " + result);
-        }
-        return mountPoint;
-    }
-
-    private String setupMountPoint(String parent) {
-        String mountPoint = null;
-        long mshostId = ManagementServerNode.getManagementServerId();
-        for (int i = 0; i < 10; i++) {
-            String mntPt = parent + File.separator + String.valueOf(mshostId) + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE));
-            File file = new File(mntPt);
-            if (!file.exists()) {
-                if (_storage.mkdir(mntPt)) {
-                    mountPoint = mntPt;
-                    break;
-                }
-            }
-            s_logger.error("Unable to create mount: " + mntPt);
-        }
-
-        return mountPoint;
-    }
-
-    private String getSystemVMIsoFileNameOnDatastore() {
-        String version = this.getClass().getPackage().getImplementationVersion();
-        String fileName = "systemvm-" + version + ".iso";
-        return fileName.replace(':', '-');
-    }
-
-    private File getSystemVMPatchIsoFile() {
-        // locate systemvm.iso
-        URL url = this.getClass().getClassLoader().getResource("vms/systemvm.iso");
-        File isoFile = null;
-        if (url != null) {
-            isoFile = new File(url.getPath());
-        }
-
-        if(isoFile == null || !isoFile.exists()) {
-            isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso");
-        }
-
-        assert(isoFile != null);
-        if(!isoFile.exists()) {
-            s_logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString());
-        }
-        return isoFile;
-    }
-
-    private String getSecondaryStorageStoreUrl(long zoneId) {
-        String secUrl = null;
-        DataStore secStore = _dataStoreMgr.getImageStore(zoneId);
-        if (secStore != null) {
-            secUrl = secStore.getUri();
-        }
-
-        if (secUrl == null) {
-            s_logger.warn("Secondary storage uri couldn't be retrieved");
-        }
-
-        return secUrl;
-    }
 
     /**
      * Encapsulate GUID calculation in public method to allow access to test
@@ -580,24 +397,6 @@ public class HypervServerDiscoverer extends DiscovererBase implements
     public final boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
         super.configure(name, params);
 
-        _mountParent = (String) params.get(Config.MountParent.key());
-        if (_mountParent == null) {
-            _mountParent = File.separator + "mnt";
-        }
-
-        if (_instance != null) {
-            _mountParent = _mountParent + File.separator + _instance;
-        }
-
-        String value = (String)params.get("scripts.timeout");
-        _timeout = NumbersUtil.parseInt(value, 30) * 1000;
-
-        _storage = (StorageLayer)params.get(StorageLayer.InstanceConfigKey);
-        if (_storage == null) {
-            _storage = new JavaStorageLayer();
-            _storage.configure("StorageLayer", params);
-        }
-
         // TODO: allow timeout on we HTTPRequests to be configured
         _agentMgr.registerForHostEvents(this, true, false, true);
         _resourceMgr.registerResourceStateAdapter(this.getClass()

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5dea7728/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java
new file mode 100644
index 0000000..9030e29
--- /dev/null
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManager.java
@@ -0,0 +1,24 @@
+// 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.hypervisor.hyperv.manager;
+
+import com.cloud.utils.component.Manager;
+
+public interface HypervManager extends Manager {
+    public String prepareSecondaryStorageStore(long zoneId);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5dea7728/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
new file mode 100644
index 0000000..f21683d
--- /dev/null
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/manager/HypervManagerImpl.java
@@ -0,0 +1,367 @@
+// 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.hypervisor.hyperv.manager;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.utils.identity.ManagementServerNode;
+import org.apache.log4j.Logger;
+
+import com.cloud.configuration.Config;
+import com.cloud.storage.JavaStorageLayer;
+import com.cloud.storage.StorageLayer;
+import com.cloud.utils.FileUtil;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+
+@Local(value = { HypervManager.class })
+public class HypervManagerImpl implements HypervManager {
+    public static final Logger s_logger = Logger.getLogger(HypervManagerImpl.class);
+
+    private String name;
+    private int runLevel;
+    private Map<String, Object> params;
+
+    private int _timeout;
+    Random _rand = new Random(System.currentTimeMillis());
+
+    Map<String, String> _storageMounts = new HashMap<String, String>();
+    StorageLayer _storage;
+
+    @Inject ConfigurationDao _configDao;
+    @Inject DataStoreManager _dataStoreMgr;
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+        if (params != null) {
+            String value = (String)params.get("scripts.timeout");
+            _timeout = NumbersUtil.parseInt(value, 30) * 1000;
+            _storage = (StorageLayer)params.get(StorageLayer.InstanceConfigKey);
+        }
+
+        if (_storage == null) {
+            _storage = new JavaStorageLayer();
+            _storage.configure("StorageLayer", params);
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean start() {
+        startupCleanup(getMountParent());
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        shutdownCleanup();
+        return true;
+    }
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setConfigParams(Map<String, Object> params) {
+        this.params = params;
+    }
+
+    @Override
+    public Map<String, Object> getConfigParams() {
+        return params;
+    }
+
+    @Override
+    public int getRunLevel() {
+        return runLevel;
+    }
+
+    @Override
+    public void setRunLevel(int level) {
+        runLevel = level;
+    }
+
+    public String prepareSecondaryStorageStore(long zoneId) {
+        String secondaryStorageUri = getSecondaryStorageStoreUrl(zoneId);
+        if (secondaryStorageUri == null) {
+            s_logger.debug("Secondary storage uri for dc " + zoneId + " couldn't be obtained");
+        } else {
+            prepareSecondaryStorageStore(secondaryStorageUri);
+        }
+
+        return secondaryStorageUri;
+    }
+
+    private String getSecondaryStorageStoreUrl(long zoneId) {
+        String secUrl = null;
+        DataStore secStore = _dataStoreMgr.getImageStore(zoneId);
+        if (secStore != null) {
+            secUrl = secStore.getUri();
+        }
+
+        if (secUrl == null) {
+            s_logger.warn("Secondary storage uri couldn't be retrieved");
+        }
+
+        return secUrl;
+    }
+
+    private void prepareSecondaryStorageStore(String storageUrl) {
+        String mountPoint = getMountPoint(storageUrl);
+
+        GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm");
+        try {
+            if(lock.lock(3600)) {
+                try {
+                    File patchFolder = new File(mountPoint + "/systemvm");
+                    if(!patchFolder.exists()) {
+                        if(!patchFolder.mkdirs()) {
+                            String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder.toString();
+                            s_logger.error(msg);
+                            throw new CloudRuntimeException(msg);
+                        }
+                    }
+
+                    File srcIso = getSystemVMPatchIsoFile();
+                    File destIso = new File(mountPoint + "/systemvm/" + getSystemVMIsoFileNameOnDatastore());
+                    if(!destIso.exists()) {
+                        s_logger.info("Copy System VM patch ISO file to secondary storage. source ISO: " +
+                                srcIso.getAbsolutePath() + ", destination: " + destIso.getAbsolutePath());
+                        try {
+                            FileUtil.copyfile(srcIso, destIso);
+                        } catch(IOException e) {
+                            s_logger.error("Unexpected exception ", e);
+
+                            String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso.toString() + ", dest location: " + destIso;
+                            s_logger.error(msg);
+                            throw new CloudRuntimeException(msg);
+                        }
+                    } else {
+                        if(s_logger.isTraceEnabled()) {
+                            s_logger.trace("SystemVM ISO file " + destIso.getPath() + " already exists");
+                        }
+                    }
+                } finally {
+                    lock.unlock();
+                }
+            }
+        } finally {
+            lock.releaseRef();
+        }
+    }
+
+    private String getMountPoint(String storageUrl) {
+        String mountPoint = null;
+        synchronized(_storageMounts) {
+            mountPoint = _storageMounts.get(storageUrl);
+            if(mountPoint != null) {
+                return mountPoint;
+            }
+
+            URI uri;
+            try {
+                uri = new URI(storageUrl);
+            } catch (URISyntaxException e) {
+                s_logger.error("Invalid storage URL format ", e);
+                throw new CloudRuntimeException("Unable to create mount point due to invalid storage URL format " + storageUrl);
+            }
+
+            mountPoint = mount(File.separator + File.separator + uri.getHost() + uri.getPath(), getMountParent(),
+                    uri.getScheme(), uri.getQuery());
+            if(mountPoint == null) {
+                s_logger.error("Unable to create mount point for " + storageUrl);
+                return "/mnt/sec";
+            }
+
+            _storageMounts.put(storageUrl, mountPoint);
+            return mountPoint;
+        }
+    }
+
+    protected String mount(String path, String parent, String scheme, String query) {
+        String mountPoint = setupMountPoint(parent);
+        if (mountPoint == null) {
+            s_logger.warn("Unable to create a mount point");
+            return null;
+        }
+
+        Script script = null;
+        String result = null;
+        if (scheme.equals("cifs")) {
+            Script command = new Script(true, "mount", _timeout, s_logger);
+            command.add("-t", "cifs");
+            command.add(path);
+            command.add(mountPoint);
+
+            if (query != null) {
+                query = query.replace('&', ',');
+                command.add("-o", query);
+            }
+            result = command.execute();
+        }
+
+        if (result != null) {
+            s_logger.warn("Unable to mount " + path + " due to " + result);
+            File file = new File(mountPoint);
+            if (file.exists()) {
+                file.delete();
+            }
+            return null;
+        }
+
+        // Change permissions for the mountpoint
+        script = new Script(true, "chmod", _timeout, s_logger);
+        script.add("-R", "777", mountPoint);
+        result = script.execute();
+        if (result != null) {
+            s_logger.warn("Unable to set permissions for " + mountPoint + " due to " + result);
+        }
+        return mountPoint;
+    }
+
+    private String setupMountPoint(String parent) {
+        String mountPoint = null;
+        long mshostId = ManagementServerNode.getManagementServerId();
+        for (int i = 0; i < 10; i++) {
+            String mntPt = parent + File.separator + String.valueOf(mshostId) + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE));
+            File file = new File(mntPt);
+            if (!file.exists()) {
+                if (_storage.mkdir(mntPt)) {
+                    mountPoint = mntPt;
+                    break;
+                }
+            }
+            s_logger.error("Unable to create mount: " + mntPt);
+        }
+
+        return mountPoint;
+    }
+
+    private String getSystemVMIsoFileNameOnDatastore() {
+        String version = this.getClass().getPackage().getImplementationVersion();
+        String fileName = "systemvm-" + version + ".iso";
+        return fileName.replace(':', '-');
+    }
+
+    private File getSystemVMPatchIsoFile() {
+        // locate systemvm.iso
+        URL url = this.getClass().getClassLoader().getResource("vms/systemvm.iso");
+        File isoFile = null;
+        if (url != null) {
+            isoFile = new File(url.getPath());
+        }
+
+        if(isoFile == null || !isoFile.exists()) {
+            isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso");
+        }
+
+        assert(isoFile != null);
+        if(!isoFile.exists()) {
+            s_logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString());
+        }
+        return isoFile;
+    }
+
+    private String getMountParent() {
+        String mountParent = _configDao.getValue(Config.MountParent.key());
+        if (mountParent == null) {
+            mountParent = File.separator + "mnt";
+        }
+
+        String instance = _configDao.getValue(Config.InstanceName.key());
+        if (instance == null) {
+            instance = "DEFAULT";
+        }
+
+        if (instance != null) {
+            mountParent = mountParent + File.separator + instance;
+        }
+
+        return mountParent;
+    }
+
+    private void startupCleanup(String parent) {
+        s_logger.info("Cleanup mounted mount points used in previous session");
+
+        long mshostId = ManagementServerNode.getManagementServerId();
+
+        // cleanup left-over NFS mounts from previous session
+        String[] mounts = _storage.listFiles(parent + File.separator + String.valueOf(mshostId) + ".*");
+        if(mounts != null && mounts.length > 0) {
+            for(String mountPoint : mounts) {
+                s_logger.info("umount NFS mount from previous session: " + mountPoint);
+
+                String result = null;
+                Script command = new Script(true, "umount", _timeout, s_logger);
+                command.add(mountPoint);
+                result = command.execute();
+                if (result != null) {
+                    s_logger.warn("Unable to umount " + mountPoint + " due to " + result);
+                }
+                File file = new File(mountPoint);
+                if (file.exists()) {
+                    file.delete();
+                }
+            }
+        }
+    }
+
+    private void shutdownCleanup() {
+        s_logger.info("Cleanup mounted mount points used in current session");
+
+        for(String mountPoint : _storageMounts.values()) {
+            s_logger.info("umount NFS mount: " + mountPoint);
+
+            String result = null;
+            Script command = new Script(true, "umount", _timeout, s_logger);
+            command.add(mountPoint);
+            result = command.execute();
+            if (result != null) {
+                s_logger.warn("Unable to umount " + mountPoint + " due to " + result);
+            }
+            File file = new File(mountPoint);
+            if (file.exists()) {
+                file.delete();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5dea7728/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
index cd622c7..e0a1158 100644
--- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
@@ -28,7 +28,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
+import javax.annotation.PostConstruct;
 import javax.ejb.Local;
+import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
 import org.apache.http.HttpResponse;
@@ -41,7 +43,6 @@ import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.util.EntityUtils;
 import org.apache.log4j.Logger;
 
-import com.google.gson.Gson;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckRouterAnswer;
 import com.cloud.agent.api.CheckRouterCommand;
@@ -56,6 +57,7 @@ import com.cloud.agent.api.NetworkUsageCommand;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.PingRoutingCommand;
 import com.cloud.agent.api.PingTestCommand;
+import com.cloud.agent.api.StartCommand;
 import com.cloud.agent.api.StartupCommand;
 import com.cloud.agent.api.StartupRoutingCommand;
 import com.cloud.agent.api.StartupRoutingCommand.VmState;
@@ -90,9 +92,11 @@ import com.cloud.agent.api.to.FirewallRuleTO;
 import com.cloud.agent.api.to.IpAddressTO;
 import com.cloud.agent.api.to.PortForwardingRuleTO;
 import com.cloud.agent.api.to.StaticNatRuleTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.dc.DataCenter.NetworkType;
 import com.cloud.host.Host.Type;
 import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.hyperv.manager.HypervManager;
 import com.cloud.network.HAProxyConfigurator;
 import com.cloud.network.LoadBalancerConfigurator;
 import com.cloud.network.Networks.RouterPrivateIpStrategy;
@@ -104,7 +108,9 @@ import com.cloud.utils.Pair;
 import com.cloud.utils.StringUtils;
 import com.cloud.utils.net.NetUtils;
 import com.cloud.utils.ssh.SshHelper;
+import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineName;
+import com.google.gson.Gson;
 
 /**
  * Implementation of dummy resource to be returned from discoverer.
@@ -112,8 +118,7 @@ import com.cloud.vm.VirtualMachineName;
 @Local(value = ServerResource.class)
 public class HypervDirectConnectResource extends ServerResourceBase implements ServerResource {
     public static final int DEFAULT_AGENT_PORT = 8250;
-    private static final Logger s_logger = Logger
-            .getLogger(HypervDirectConnectResource.class.getName());
+    private static final Logger s_logger = Logger.getLogger(HypervDirectConnectResource.class.getName());
 
     private static final Gson s_gson = GsonHelper.getGson();
     private String _zoneId;
@@ -137,6 +142,15 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
     private String _username;
     private String _password;
 
+    private static HypervManager s_hypervMgr;
+    @Inject HypervManager _hypervMgr;
+
+    @PostConstruct
+    void init() {
+        s_hypervMgr = _hypervMgr;
+    }
+
+
     @Override
     public final Type getType() {
         return Type.Routing;
@@ -411,9 +425,22 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
             answer = execute((CheckS2SVpnConnectionsCommand) cmd);
         } else if (clazz == SetStaticRouteCommand.class) {
             answer = execute((SetStaticRouteCommand) cmd);
-        }
-        else {
-            // Else send the cmd to hyperv agent.
+        } else {
+            if (clazz == StartCommand.class) {
+                VirtualMachineTO vmSpec = ((StartCommand)cmd).getVirtualMachine();
+                if (vmSpec.getType() != VirtualMachine.Type.User) {
+                    if (s_hypervMgr != null) {
+                        String secondary = s_hypervMgr.prepareSecondaryStorageStore(Long.parseLong(_zoneId));
+                        if (secondary != null) {
+                            ((StartCommand)cmd).setSecondaryStorage(secondary);
+                        }
+                    } else {
+                        s_logger.error("Hyperv manager isn't available. Couldn't check and copy the systemvm iso.");
+                    }
+                }
+            }
+
+            // Send the cmd to hyperv agent.
             String ansStr = postHttpRequest(s_gson.toJson(cmd), agentUri);
             if (ansStr == null) {
                 return Answer.createUnsupportedCommandAnswer(cmd);
@@ -1656,19 +1683,21 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
     public final boolean configure(final String name,
             final Map<String, Object> params) throws ConfigurationException {
         /* todo: update, make consistent with the xen server equivalent. */
-        _guid = (String) params.get("guid");
-        _zoneId = (String) params.get("zone");
-        _podId = (String) params.get("pod");
-        _clusterId = (String) params.get("cluster");
-        _agentIp = (String) params.get("ipaddress"); // was agentIp
-        _name = name;
-
-        _clusterGuid = (String) params.get("cluster.guid");
-        _username = (String) params.get("url");
-        _password = (String) params.get("password");
-        _username = (String) params.get("username");
-
-        _configureCalled = true;
+        if (params != null) {
+            _guid = (String) params.get("guid");
+            _zoneId = (String) params.get("zone");
+            _podId = (String) params.get("pod");
+            _clusterId = (String) params.get("cluster");
+            _agentIp = (String) params.get("ipaddress"); // was agentIp
+            _name = name;
+    
+            _clusterGuid = (String) params.get("cluster.guid");
+            _username = (String) params.get("url");
+            _password = (String) params.get("password");
+            _username = (String) params.get("username");
+            _configureCalled = true;
+        }
+
         return true;
     }