You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by bh...@apache.org on 2015/03/12 07:04:59 UTC

[07/12] git commit: updated refs/heads/master to c27c694

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c27c6943/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3StoragePool.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3StoragePool.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3StoragePool.java
new file mode 100644
index 0000000..1f7726a
--- /dev/null
+++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3StoragePool.java
@@ -0,0 +1,749 @@
+/*******************************************************************************
+ * 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.ovm3.resources.helpers;
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+import org.apache.xmlrpc.XmlRpcException;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CreateStoragePoolCommand;
+import com.cloud.agent.api.DeleteStoragePoolCommand;
+import com.cloud.agent.api.GetStorageStatsAnswer;
+import com.cloud.agent.api.GetStorageStatsCommand;
+import com.cloud.agent.api.ModifyStoragePoolAnswer;
+import com.cloud.agent.api.ModifyStoragePoolCommand;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.hypervisor.ovm3.objects.CloudstackPlugin;
+import com.cloud.hypervisor.ovm3.objects.Connection;
+import com.cloud.hypervisor.ovm3.objects.Linux;
+import com.cloud.hypervisor.ovm3.objects.Ovm3ResourceException;
+import com.cloud.hypervisor.ovm3.objects.OvmObject;
+import com.cloud.hypervisor.ovm3.objects.Pool;
+import com.cloud.hypervisor.ovm3.objects.PoolOCFS2;
+import com.cloud.hypervisor.ovm3.objects.Repository;
+import com.cloud.hypervisor.ovm3.objects.StoragePlugin;
+import com.cloud.hypervisor.ovm3.objects.StoragePlugin.FileProperties;
+import com.cloud.hypervisor.ovm3.objects.StoragePlugin.StorageDetails;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.storage.template.TemplateProp;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+import com.cloud.utils.ssh.SshHelper;
+
+public class Ovm3StoragePool {
+    private static final Logger LOGGER = Logger
+            .getLogger(Ovm3StoragePool.class);
+    private Connection c;
+    private Ovm3Configuration config;
+    private OvmObject ovmObject = new OvmObject();
+
+    public Ovm3StoragePool(Connection conn, Ovm3Configuration ovm3config) {
+        c = conn;
+        config = ovm3config;
+    }
+
+    /**
+     * Setting up the roles on a host, we set all roles on all hosts!
+     *
+     * @param pool
+     * @throws ConfigurationException
+     */
+    private void setRoles(Pool pool) throws ConfigurationException {
+        try {
+            pool.setServerRoles(pool.getValidRoles());
+        } catch (Ovm3ResourceException e) {
+            String msg = "Failed to set server role for host "
+                    + config.getAgentHostname() + ": " + e.getMessage();
+            LOGGER.error(msg);
+            throw new ConfigurationException(msg);
+        }
+    }
+
+    /**
+     * If you don't own the host you can't fiddle with it.
+     *
+     * @param pool
+     * @throws ConfigurationException
+     */
+    private void takeOwnership(Pool pool) throws ConfigurationException {
+        try {
+            LOGGER.debug("Take ownership of host " + config.getAgentHostname());
+            pool.takeOwnership(config.getAgentOwnedByUuid(), "");
+        } catch (Ovm3ResourceException e) {
+            String msg = "Failed to take ownership of host "
+                    + config.getAgentHostname();
+            LOGGER.error(msg);
+            throw new ConfigurationException(msg);
+        }
+    }
+
+    /**
+     * If you don't own the host you can't fiddle with it.
+     *
+     * @param pool
+     * @throws ConfigurationException
+     */
+    /* FIXME: Placeholders for now, implement later!!!! */
+    private void takeOwnership33x(Pool pool) throws ConfigurationException {
+        try {
+            LOGGER.debug("Take ownership of host " + config.getAgentHostname());
+            String event = "http://localhost:10024/event";
+            String stats = "http://localhost:10024/stats";
+            String mgrCert = "None";
+            String signCert = "None";
+            pool.takeOwnership33x(config.getAgentOwnedByUuid(),
+                    event,
+                    stats,
+                    mgrCert,
+                    signCert);
+        } catch (Ovm3ResourceException e) {
+            String msg = "Failed to take ownership of host "
+                    + config.getAgentHostname();
+            LOGGER.error(msg);
+            throw new ConfigurationException(msg);
+        }
+    }
+    /**
+     * Prepare a host to become part of a pool, the roles and ownership are
+     * important here.
+     *
+     * @return
+     * @throws ConfigurationException
+     */
+    public boolean prepareForPool() throws ConfigurationException {
+        /* need single master uuid */
+        try {
+            Linux host = new Linux(c);
+            Pool pool = new Pool(c);
+
+            /* setup pool and role, needs utility to be able to do things */
+            if (host.getServerRoles().contentEquals(
+                    pool.getValidRoles().toString())) {
+                LOGGER.info("Server role for host " + config.getAgentHostname()
+                        + " is ok");
+            } else {
+                setRoles(pool);
+            }
+            if (host.getMembershipState().contentEquals("Unowned")) {
+                if (host.getOvmVersion().startsWith("3.2.")) {
+                    takeOwnership(pool);
+                } else if (host.getOvmVersion().startsWith("3.3.")) {
+                    takeOwnership33x(pool);
+                }
+            } else {
+                if (host.getManagerUuid().equals(config.getAgentOwnedByUuid())) {
+                    String msg = "Host " + config.getAgentHostname()
+                            + " owned by us";
+                    LOGGER.debug(msg);
+                    return true;
+                } else {
+                    String msg = "Host " + config.getAgentHostname()
+                            + " already part of a pool, and not owned by us";
+                    LOGGER.error(msg);
+                    throw new ConfigurationException(msg);
+                }
+            }
+        } catch (ConfigurationException | Ovm3ResourceException es) {
+            String msg = "Failed to prepare " + config.getAgentHostname()
+                    + " for pool: " + es.getMessage();
+            LOGGER.error(msg);
+            throw new ConfigurationException(msg);
+        }
+        return true;
+    }
+
+    /**
+     * Setup a pool in general, this creates a repo if it doesn't exist yet, if
+     * it does however we mount it.
+     *
+     * @param cmd
+     * @return
+     * @throws Ovm3ResourceException
+     */
+    private Boolean setupPool(StorageFilerTO cmd) throws Ovm3ResourceException {
+        String primUuid = cmd.getUuid();
+        String ssUuid = ovmObject.deDash(primUuid);
+        String fsType = "nfs";
+        String clusterUuid = config.getAgentOwnedByUuid().substring(0, 15);
+        String managerId = config.getAgentOwnedByUuid();
+        String poolAlias = cmd.getHost() + ":" + cmd.getPath();
+        String mountPoint = String.format("%1$s:%2$s", cmd.getHost(),
+                cmd.getPath())
+                + "/VirtualMachines";
+        Integer poolSize = 0;
+
+        Pool poolHost = new Pool(c);
+        PoolOCFS2 poolFs = new PoolOCFS2(c);
+        if (config.getAgentIsMaster()) {
+            try {
+                LOGGER.debug("Create poolfs on " + config.getAgentHostname()
+                        + " for repo " + primUuid);
+                /* double check if we're not overwritting anything here!@ */
+                poolFs.createPoolFs(fsType, mountPoint, clusterUuid, primUuid,
+                        ssUuid, managerId);
+            } catch (Ovm3ResourceException e) {
+                throw e;
+            }
+            try {
+                poolHost.createServerPool(poolAlias, primUuid,
+                        config.getOvm3PoolVip(), poolSize + 1,
+                        config.getAgentHostname(), c.getIp());
+            } catch (Ovm3ResourceException e) {
+                throw e;
+            }
+        } else if (config.getAgentHasMaster()) {
+            try {
+                poolHost.joinServerPool(poolAlias, primUuid,
+                        config.getOvm3PoolVip(), poolSize + 1,
+                        config.getAgentHostname(), c.getIp());
+            } catch (Ovm3ResourceException e) {
+                throw e;
+            }
+        }
+        try {
+            /* should contain check if we're in an OVM pool or not */
+            CloudstackPlugin csp = new CloudstackPlugin(c);
+            Boolean vip = csp.dom0CheckPort(config.getOvm3PoolVip(), 22, 60, 1);
+            if (!vip) {
+                throw new Ovm3ResourceException(
+                        "Unable to reach Ovm3 Pool VIP "
+                                + config.getOvm3PoolVip());
+            }
+            /*
+             * should also throw exception, we need to stop pool creation here,
+             * or is the manual addition fine?
+             */
+            if (!addMembers()) {
+                return false;
+            }
+        } catch (Ovm3ResourceException e) {
+            throw new Ovm3ResourceException("Unable to add members to pool"
+                    + e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * Adding members to a pool, this is seperate from cluster configuration in
+     * OVM.
+     *
+     * @return
+     * @throws Ovm3ResourceException
+     */
+    private Boolean addMembers() throws Ovm3ResourceException {
+        List<String> members = new ArrayList<String>();
+        try {
+            Connection m = new Connection(config.getOvm3PoolVip(), c.getPort(),
+                    c.getUserName(), c.getPassword());
+            Pool poolMaster = new Pool(m);
+            if (poolMaster.isInAPool()) {
+                members.addAll(poolMaster.getPoolMemberList());
+                if (!poolMaster.getPoolMemberList().contains(c.getIp())
+                        && c.getIp().equals(config.getOvm3PoolVip())) {
+                    members.add(c.getIp());
+                }
+            } else {
+                LOGGER.warn(c.getIp() + " noticed master "
+                        + config.getOvm3PoolVip() + " is not part of pool");
+                return false;
+            }
+            /* a cluster shares usernames and passwords */
+            for (String member : members) {
+                Connection x = new Connection(member, c.getPort(),
+                        c.getUserName(), c.getPassword());
+                Pool poolM = new Pool(x);
+                if (poolM.isInAPool()) {
+                    poolM.setPoolMemberList(members);
+                    LOGGER.debug("Added " + members + " to pool "
+                            + poolM.getPoolId() + " on member " + member);
+                } else {
+                    LOGGER.warn(member
+                            + " unable to be member of a pool it's not in");
+                    return false;
+                }
+            }
+        } catch (Exception e) {
+            throw new Ovm3ResourceException("Unable to add members: "
+                    + e.getMessage(), e);
+        }
+        return true;
+    }
+
+    /**
+     * Get a host out of a pool/cluster, this should unmount all FSs though.
+     *
+     * @param cmd
+     * @return
+     */
+    public Answer execute(DeleteStoragePoolCommand cmd) {
+        try {
+            Pool pool = new Pool(c);
+            pool.leaveServerPool(cmd.getPool().getUuid());
+            /* also connect to the master and update the pool list ? */
+        } catch (Ovm3ResourceException e) {
+            LOGGER.debug(
+                    "Delete storage pool on host "
+                            + config.getAgentHostname()
+                            + " failed, however, we leave to user for cleanup and tell managment server it succeeded",
+                    e);
+        }
+
+        return new Answer(cmd);
+    }
+
+    /**
+     * Create primary storage, which is a repository in OVM. Pooling is part of
+     * this too and clustering should be in the future.
+     *
+     * @param cmd
+     * @return
+     * @throws XmlRpcException
+     */
+    private boolean createRepo(StorageFilerTO cmd) throws XmlRpcException {
+        String basePath = config.getAgentOvmRepoPath();
+        Repository repo = new Repository(c);
+        String primUuid = repo.deDash(cmd.getUuid());
+        String ovsRepo = basePath + "/" + primUuid;
+        /* should add port ? */
+        String mountPoint = String.format("%1$s:%2$s", cmd.getHost(),
+                cmd.getPath());
+        String msg;
+
+        if (cmd.getType() == StoragePoolType.NetworkFilesystem) {
+            Boolean repoExists = false;
+            /* base repo first */
+            try {
+                repo.mountRepoFs(mountPoint, ovsRepo);
+            } catch (Ovm3ResourceException e) {
+                LOGGER.debug("Unable to mount NFS repository " + mountPoint
+                        + " on " + ovsRepo + " requested for "
+                        + config.getAgentHostname() + ": " + e.getMessage());
+            }
+            try {
+                repo.addRepo(mountPoint, ovsRepo);
+                repoExists = true;
+            } catch (Ovm3ResourceException e) {
+                LOGGER.debug("NFS repository " + mountPoint + " on " + ovsRepo
+                        + " not found creating repo: " + e.getMessage());
+            }
+            if (!repoExists) {
+                try {
+                    /*
+                     * a mount of the NFS fs by the createrepo actually
+                     * generates a null if it is already mounted... -sigh-
+                     */
+                    repo.createRepo(mountPoint, ovsRepo, primUuid,
+                            "OVS Repository");
+                } catch (Ovm3ResourceException e) {
+                    msg = "NFS repository " + mountPoint + " on " + ovsRepo
+                            + " create failed!";
+                    LOGGER.debug(msg);
+                    throw new CloudRuntimeException(msg + " " + e.getMessage(),
+                            e);
+                }
+            }
+
+            /* add base pooling first */
+            if (config.getAgentInOvm3Pool()) {
+                try {
+                    msg = "Configuring " + config.getAgentHostname() + "("
+                            + config.getAgentIp() + ") for pool";
+                    LOGGER.debug(msg);
+                    setupPool(cmd);
+                    msg = "Configured host for pool";
+                    /* add clustering after pooling */
+                    if (config.getAgentInOvm3Cluster()) {
+                        msg = "Setup " + config.getAgentHostname() + "("
+                                + config.getAgentIp() + ")  for cluster";
+                        LOGGER.debug(msg);
+                        /* setup cluster */
+                        /*
+                         * From cluster.java
+                         * configure_server_for_cluster(cluster conf, fs, mount,
+                         * fsuuid, poolfsbaseuuid)
+                         */
+                        /* create_cluster(poolfsuuid,) */
+                    }
+                } catch (Ovm3ResourceException e) {
+                    msg = "Unable to setup pool on  "
+                            + config.getAgentHostname() + "("
+                            + config.getAgentIp() + ") for " + ovsRepo;
+                    throw new CloudRuntimeException(msg + " " + e.getMessage(),
+                            e);
+                }
+            } else {
+                msg = "no way dude I can't stand for this";
+                LOGGER.debug(msg);
+            }
+            /*
+             * this is to create the .generic_fs_stamp else we're not allowed to
+             * create any data\disks on this thing
+             */
+            try {
+                URI uri = new URI(cmd.getType() + "://" + cmd.getHost() + ":"
+                        + +cmd.getPort() + cmd.getPath() + "/VirtualMachines");
+                setupNfsStorage(uri, cmd.getUuid());
+            } catch (Exception e) {
+                msg = "NFS mount " + mountPoint + " on "
+                        + config.getAgentSecStoragePath() + "/" + cmd.getUuid()
+                        + " create failed!";
+                throw new CloudRuntimeException(msg + " " + e.getMessage(), e);
+            }
+        } else {
+            msg = "NFS repository " + mountPoint + " on " + ovsRepo
+                    + " create failed, was type " + cmd.getType();
+            LOGGER.debug(msg);
+            return false;
+        }
+
+        try {
+            /* systemvm iso is imported here */
+            prepareSecondaryStorageStore(ovsRepo, cmd.getUuid(), cmd.getHost());
+        } catch (Exception e) {
+            msg = "systemvm.iso copy failed to " + ovsRepo;
+            LOGGER.debug(msg, e);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Copy the systemvm.iso in if it doesn't exist or the size differs.
+     *
+     * @param storageUrl
+     * @param poolUuid
+     * @param host
+     */
+    private void prepareSecondaryStorageStore(String storageUrl,
+            String poolUuid, String host) {
+        String mountPoint = storageUrl;
+
+        GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm");
+        try {
+            /* double check */
+            if (config.getAgentHasMaster() && config.getAgentInOvm3Pool()) {
+                LOGGER.debug("Skip systemvm iso copy, leave it to the master");
+                return;
+            }
+            if (lock.lock(3600)) {
+                try {
+                    /*
+                     * save src iso real name for reuse, so we don't depend on
+                     * other happy little accidents.
+                     */
+                    File srcIso = getSystemVMPatchIsoFile();
+                    String destPath = mountPoint + "/ISOs/";
+                    try {
+                        StoragePlugin sp = new StoragePlugin(c);
+                        FileProperties fp = sp.storagePluginGetFileInfo(
+                                poolUuid, host, destPath + File.separator
+                                        + srcIso.getName());
+                        if (fp.getSize() != srcIso.getTotalSpace()) {
+                            LOGGER.info(" System VM patch ISO file already exists: "
+                                    + srcIso.getAbsolutePath().toString()
+                                    + ", destination: " + destPath);
+                        }
+                    } catch (Exception e) {
+                        LOGGER.info("Copy System VM patch ISO file to secondary storage. source ISO: "
+                                + srcIso.getAbsolutePath()
+                                + ", destination: "
+                                + destPath);
+                        try {
+                            /* Perhaps use a key instead ? */
+                            SshHelper
+                                    .scpTo(c.getIp(), 22, config
+                                            .getAgentSshUserName(), null,
+                                            config.getAgentSshPassword(),
+                                            destPath, srcIso.getAbsolutePath()
+                                                    .toString(), "0644");
+                        } catch (Exception es) {
+                            LOGGER.error("Unexpected exception ", es);
+                            String msg = "Unable to copy systemvm ISO on secondary storage. src location: "
+                                    + srcIso.toString()
+                                    + ", dest location: "
+                                    + destPath;
+                            LOGGER.error(msg);
+                            throw new CloudRuntimeException(msg, es);
+                        }
+                    }
+                } finally {
+                    lock.unlock();
+                }
+            }
+        } finally {
+            lock.releaseRef();
+        }
+    }
+
+    /**
+     * The secondary storage mountpoint is a uuid based on the host combined
+     * with the path.
+     *
+     * @param url
+     * @return
+     * @throws Ovm3ResourceException
+     */
+    public String setupSecondaryStorage(String url)
+            throws Ovm3ResourceException {
+        URI uri = URI.create(url);
+        if (uri.getHost() == null) {
+            throw new Ovm3ResourceException(
+                    "Secondary storage host can not be empty!");
+        }
+        String uuid = ovmObject.newUuid(uri.getHost() + ":" + uri.getPath());
+        LOGGER.info("Secondary storage with uuid: " + uuid);
+        return setupNfsStorage(uri, uuid);
+    }
+
+    /**
+     * Sets up NFS Storage
+     *
+     * @param uri
+     * @param uuid
+     * @return
+     * @throws Ovm3ResourceException
+     */
+    private String setupNfsStorage(URI uri, String uuid)
+            throws Ovm3ResourceException {
+        String fsUri = "nfs";
+        String msg = "";
+        String mountPoint = config.getAgentSecStoragePath() + "/" + uuid;
+        Linux host = new Linux(c);
+
+        Map<String, Linux.FileSystem> fsList = host.getFileSystemMap(fsUri);
+        Linux.FileSystem fs = fsList.get(uuid);
+        if (fs == null || !fs.getRemoteDir().equals(mountPoint)) {
+            try {
+                StoragePlugin sp = new StoragePlugin(c);
+                sp.storagePluginMountNFS(uri.getHost(), uri.getPath(), uuid,
+                        mountPoint);
+                msg = "Nfs storage " + uri + " mounted on " + mountPoint;
+                return uuid;
+            } catch (Ovm3ResourceException ec) {
+                msg = "Nfs storage " + uri + " mount on " + mountPoint
+                        + " FAILED " + ec.getMessage();
+                LOGGER.error(msg);
+                throw ec;
+            }
+        } else {
+            msg = "NFS storage " + uri + " already mounted on " + mountPoint;
+            return uuid;
+        }
+    }
+
+    /**
+     * Gets statistics for storage.
+     *
+     * @param cmd
+     * @return
+     */
+    public GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) {
+        LOGGER.debug("Getting stats for: " + cmd.getStorageId());
+        try {
+            Linux host = new Linux(c);
+            Linux.FileSystem fs = host.getFileSystemByUuid(cmd.getStorageId(),
+                    "nfs");
+            StoragePlugin store = new StoragePlugin(c);
+            String propUuid = store.deDash(cmd.getStorageId());
+            String mntUuid = cmd.getStorageId();
+            if (store == null || propUuid == null || mntUuid == null
+                    || fs == null) {
+                String msg = "Null returned when retrieving stats for "
+                        + cmd.getStorageId();
+                LOGGER.error(msg);
+                return new GetStorageStatsAnswer(cmd, msg);
+            }
+            /* or is it mntUuid ish ? */
+            StorageDetails sd = store.storagePluginGetFileSystemInfo(propUuid,
+                    mntUuid, fs.getHost(), fs.getDevice());
+            /*
+             * FIXME: cure me or kill me, this needs to trigger a reinit of
+             * primary storage, actually the problem is more deeprooted, as when
+             * the hypervisor reboots it looses partial context and needs to be
+             * reinitiated.... actually a full configure round... how to trigger
+             * that ?
+             */
+            if ("".equals(sd.getSize())) {
+                String msg = "No size when retrieving stats for "
+                        + cmd.getStorageId();
+                LOGGER.debug(msg);
+                return new GetStorageStatsAnswer(cmd, msg);
+            }
+            long total = Long.parseLong(sd.getSize());
+            long used = total - Long.parseLong(sd.getFreeSize());
+            return new GetStorageStatsAnswer(cmd, total, used);
+        } catch (Ovm3ResourceException e) {
+            LOGGER.debug("GetStorageStatsCommand for " + cmd.getStorageId()
+                    + " failed", e);
+            return new GetStorageStatsAnswer(cmd, e.getMessage());
+        }
+    }
+
+    /**
+     * Try to figure out where the systemvm.iso resides on the fs of the
+     * management server
+     *
+     * @return
+     */
+    public File getSystemVMPatchIsoFile() {
+        String iso = "systemvm.iso";
+        String systemVmIsoPath = Script.findScript("", "vms/" + iso);
+        File isoFile = null;
+        if (systemVmIsoPath != null) {
+            LOGGER.debug("found systemvm patch iso " + systemVmIsoPath);
+            isoFile = new File(systemVmIsoPath);
+        }
+        if (isoFile == null || !isoFile.exists()) {
+            String svm = "client/target/generated-webapp/WEB-INF/classes/vms/"
+                    + iso;
+            LOGGER.debug("last resort for systemvm patch iso " + svm);
+            isoFile = new File(svm);
+        }
+        assert isoFile != null;
+        if (!isoFile.exists()) {
+            LOGGER.error("Unable to locate " + iso + " in your setup at "
+                    + isoFile.toString());
+        }
+        return isoFile;
+    }
+
+    /**
+     * Create and OCFS2 filesystem (not implemented)
+     *
+     * @param pool
+     * @return
+     * @throws XmlRpcException
+     */
+    private Boolean createOCFS2Sr(StorageFilerTO pool) throws XmlRpcException {
+        LOGGER.debug("OCFS2 Not implemented yet");
+        return false;
+    }
+
+    /**
+     * Gets the details of a storage pool, size etc
+     *
+     * @param cmd
+     * @return
+     */
+    public Answer execute(ModifyStoragePoolCommand cmd) {
+        StorageFilerTO pool = cmd.getPool();
+        LOGGER.debug("modifying pool " + pool);
+        try {
+            if (config.getAgentInOvm3Cluster()) {
+                // no native ovm cluster for now, I got to break it in horrible
+                // ways
+            }
+            if (pool.getType() == StoragePoolType.NetworkFilesystem) {
+                createRepo(pool);
+                StoragePlugin store = new StoragePlugin(c);
+                String propUuid = store.deDash(pool.getUuid());
+                String mntUuid = pool.getUuid();
+                String nfsHost = pool.getHost();
+                String nfsPath = pool.getPath();
+                StorageDetails ss = store.storagePluginGetFileSystemInfo(
+                        propUuid, mntUuid, nfsHost, nfsPath);
+
+                Map<String, TemplateProp> tInfo = new HashMap<String, TemplateProp>();
+                return new ModifyStoragePoolAnswer(cmd, Long.parseLong(ss
+                        .getSize()), Long.parseLong(ss.getFreeSize()), tInfo);
+            } else if (pool.getType() == StoragePoolType.OCFS2) {
+                createOCFS2Sr(pool);
+            }
+            return new Answer(cmd, false, "The pool type: "
+                    + pool.getType().name() + " is not supported.");
+        } catch (Exception e) {
+            LOGGER.debug("ModifyStoragePoolCommand failed", e);
+            return new Answer(cmd, false, e.getMessage());
+        }
+    }
+
+    /**
+     * Create the primary storage pool, should add iSCSI and OCFS2
+     *
+     * @param cmd
+     * @return
+     */
+    public Answer execute(CreateStoragePoolCommand cmd) {
+        StorageFilerTO pool = cmd.getPool();
+        LOGGER.debug("creating pool " + pool);
+        try {
+            if (pool.getType() == StoragePoolType.NetworkFilesystem) {
+                createRepo(pool);
+            } else if (pool.getType() == StoragePoolType.IscsiLUN) {
+                return new Answer(cmd, false,
+                        "iSCSI is unsupported at the moment");
+                /*
+                 * iScsi like so: getIscsiSR(conn, pool.getUuid(),
+                 * pool.getHost(), pool.getPath(), null, null, false);
+                 */
+            } else if (pool.getType() == StoragePoolType.OCFS2) {
+                return new Answer(cmd, false,
+                        "OCFS2 is unsupported at the moment");
+            } else if (pool.getType() == StoragePoolType.PreSetup) {
+                LOGGER.warn("pre setup for pool " + pool);
+            } else {
+                return new Answer(cmd, false, "The pool type: "
+                        + pool.getType().name() + " is not supported.");
+            }
+        } catch (Exception e) {
+            String msg = "Catch Exception " + e.getClass().getName()
+                    + ", create StoragePool failed due to " + e.toString()
+                    + " on host:" + config.getAgentHostname() + " pool: "
+                    + pool.getHost() + pool.getPath();
+            LOGGER.warn(msg, e);
+            return new Answer(cmd, false, msg);
+        }
+        return new Answer(cmd, true, "success");
+    }
+
+    /**
+     * Download from template url into primary storage ?.. is this relevant ?
+     *
+     * @param cmd
+     * @return
+     */
+    public PrimaryStorageDownloadAnswer execute(
+            final PrimaryStorageDownloadCommand cmd) {
+        try {
+            Repository repo = new Repository(c);
+            String tmplturl = cmd.getUrl();
+            String poolName = cmd.getPoolUuid();
+            String image = repo.deDash(repo.newUuid()) + ".raw";
+
+            /* url to download from, image name, and repo to copy it to */
+            repo.importVirtualDisk(tmplturl, image, poolName);
+            return new PrimaryStorageDownloadAnswer(image);
+        } catch (Exception e) {
+            LOGGER.debug("PrimaryStorageDownloadCommand failed", e);
+            return new PrimaryStorageDownloadAnswer(e.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c27c6943/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VirtualRoutingSupport.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VirtualRoutingSupport.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VirtualRoutingSupport.java
new file mode 100644
index 0000000..72578fa
--- /dev/null
+++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VirtualRoutingSupport.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * 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.ovm3.resources.helpers;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.NetworkRulesSystemVmCommand;
+import com.cloud.agent.api.NetworkUsageAnswer;
+import com.cloud.agent.api.NetworkUsageCommand;
+import com.cloud.agent.api.check.CheckSshAnswer;
+import com.cloud.agent.api.check.CheckSshCommand;
+import com.cloud.hypervisor.ovm3.objects.CloudstackPlugin;
+import com.cloud.hypervisor.ovm3.objects.Connection;
+import com.cloud.hypervisor.ovm3.resources.Ovm3VirtualRoutingResource;
+import com.cloud.utils.ExecutionResult;
+
+public class Ovm3VirtualRoutingSupport {
+    private static final Logger LOGGER = Logger
+            .getLogger(Ovm3VirtualRoutingSupport.class);
+    private static final String CREATE = "create";
+    private static final String SUCCESS = "success";
+    private Connection c;
+    private Ovm3VirtualRoutingResource vrr;
+    private Ovm3Configuration config;
+    public Ovm3VirtualRoutingSupport(Connection conn, Ovm3Configuration ovm3config, Ovm3VirtualRoutingResource ovm3vrr) {
+        c = conn;
+        vrr = ovm3vrr;
+        config = ovm3config;
+    }
+
+    /* copy paste, why isn't this just generic in the VirtualRoutingResource ? */
+    public Answer execute(NetworkUsageCommand cmd) {
+        if (cmd.isForVpc()) {
+            return vpcNetworkUsage(cmd);
+        }
+        if (LOGGER.isInfoEnabled()) {
+            LOGGER.info("Executing resource NetworkUsageCommand " + cmd);
+        }
+        if (cmd.getOption() != null && CREATE.equals(cmd.getOption())) {
+            String result = networkUsage(cmd.getPrivateIP(), CREATE, null);
+            return new NetworkUsageAnswer(cmd, result, 0L, 0L);
+        }
+        long[] stats = getNetworkStats(cmd.getPrivateIP());
+
+        return new NetworkUsageAnswer(cmd, "", stats[0], stats[1]);
+    }
+
+    /* copy paste, why isn't this just generic in the VirtualRoutingResource ? */
+    private String networkUsage(final String privateIpAddress,
+            final String option, final String ethName) {
+        String args = null;
+        if ("get".equals(option)) {
+            args = "-g";
+        } else if (CREATE.equals(option)) {
+            args = "-c";
+        } else if ("reset".equals(option)) {
+            args = "-r";
+        } else if ("addVif".equals(option)) {
+            args = "-a";
+            args += ethName;
+        } else if ("deleteVif".equals(option)) {
+            args = "-d";
+            args += ethName;
+        }
+        ExecutionResult result = vrr.executeInVR(privateIpAddress, "netusage.sh",
+                args);
+
+        if (result == null || !result.isSuccess()) {
+            return null;
+        }
+
+        return result.getDetails();
+    }
+
+    /* copy paste, why isn't this just generic in the VirtualRoutingResource ? */
+    private long[] getNetworkStats(String privateIP) {
+        String result = networkUsage(privateIP, "get", null);
+        long[] stats = new long[2];
+        if (result != null) {
+            try {
+                String[] splitResult = result.split(":");
+                int i = 0;
+                while (i < splitResult.length - 1) {
+                    stats[0] += (Long.valueOf(splitResult[i++])).longValue();
+                    stats[1] += (Long.valueOf(splitResult[i++])).longValue();
+                }
+            } catch (Exception e) {
+                LOGGER.warn(
+                        "Unable to parse return from script return of network usage command: "
+                                + e.toString(), e);
+            }
+        }
+        return stats;
+    }
+
+    /* copy paste, why isn't this just generic in the VirtualRoutingResource ? */
+    private NetworkUsageAnswer vpcNetworkUsage(NetworkUsageCommand cmd) {
+        String privateIp = cmd.getPrivateIP();
+        String option = cmd.getOption();
+        String publicIp = cmd.getGatewayIP();
+
+        String args = "-l " + publicIp + " ";
+        if ("get".equals(option)) {
+            args += "-g";
+        } else if (CREATE.equals(option)) {
+            args += "-c";
+            String vpcCIDR = cmd.getVpcCIDR();
+            args += " -v " + vpcCIDR;
+        } else if ("reset".equals(option)) {
+            args += "-r";
+        } else if ("vpn".equals(option)) {
+            args += "-n";
+        } else if ("remove".equals(option)) {
+            args += "-d";
+        } else {
+            return new NetworkUsageAnswer(cmd, SUCCESS, 0L, 0L);
+        }
+
+        ExecutionResult callResult = vrr.executeInVR(privateIp, "vpc_netusage.sh",
+                args);
+
+        if (!callResult.isSuccess()) {
+            LOGGER.error("Unable to execute NetworkUsage command on DomR ("
+                    + privateIp
+                    + "), domR may not be ready yet. failure due to "
+                    + callResult.getDetails());
+        }
+
+        if ("get".equals(option) || "vpn".equals(option)) {
+            String result = callResult.getDetails();
+            if (result == null || result.isEmpty()) {
+                LOGGER.error(" vpc network usage get returns empty ");
+            }
+            long[] stats = new long[2];
+            if (result != null) {
+                String[] splitResult = result.split(":");
+                int i = 0;
+                while (i < splitResult.length - 1) {
+                    stats[0] += (Long.valueOf(splitResult[i++])).longValue();
+                    stats[1] += (Long.valueOf(splitResult[i++])).longValue();
+                }
+                return new NetworkUsageAnswer(cmd, SUCCESS, stats[0],
+                        stats[1]);
+            }
+        }
+        return new NetworkUsageAnswer(cmd, SUCCESS, 0L, 0L);
+    }
+
+    /*
+     * we don't for now, gave an error on migration though....
+     */
+    public Answer execute(NetworkRulesSystemVmCommand cmd) {
+        boolean success = true;
+        return new Answer(cmd, success, "");
+    }
+
+    public CheckSshAnswer execute(CheckSshCommand cmd) {
+        String vmName = cmd.getName();
+        String privateIp = cmd.getIp();
+        int cmdPort = cmd.getPort();
+        int interval = cmd.getInterval();
+        int retries = cmd.getRetries();
+
+        try {
+            CloudstackPlugin cSp = new CloudstackPlugin(c);
+            if (!cSp.dom0CheckPort(privateIp, cmdPort, retries, interval)) {
+                String msg = "Port " + cmdPort + " not reachable for " + vmName
+                        + ": " + config.getAgentHostname();
+                LOGGER.info(msg);
+                return new CheckSshAnswer(cmd, msg);
+            }
+        } catch (Exception e) {
+            String msg = "Can not reach port " + cmdPort + " on System vm "
+                    + vmName + ": " + config.getAgentHostname()
+                    + " due to exception: " + e;
+            LOGGER.error(msg);
+            return new CheckSshAnswer(cmd, msg);
+        }
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Ping " + cmdPort + " succeeded for vm " + vmName
+                    + ": " + config.getAgentHostname() + " " + cmd);
+        }
+        return new CheckSshAnswer(cmd);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c27c6943/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VmGuestTypes.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VmGuestTypes.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VmGuestTypes.java
new file mode 100755
index 0000000..e2906e6
--- /dev/null
+++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VmGuestTypes.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http:www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+// 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.ovm3.resources.helpers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Ovm3VmGuestTypes {
+    /* /usr/lib64/python2.4/site-packages/agent/lib/assembly */
+    private static final Map<String, String> OVMHELPERMAP = new HashMap<String, String>();
+    private static final String HVM = "hvm";
+    private static final String PV = "xen_pvm";
+    private static final String DOMSOL = "ldoms_pvm";
+    {
+        OVMHELPERMAP.put("Oracle Enterprise Linux 6.0 (32-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 6.0 (64-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.0 (32-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.0 (64-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.1 (32-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.1 (64-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.2 (32-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.2 (64-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.3 (32-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.3 (64-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.4 (32-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.4 (64-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.5 (32-bit)", PV);
+        OVMHELPERMAP.put("Oracle Enterprise Linux 5.5 (64-bit)", PV);
+        OVMHELPERMAP.put("Other Linux (32-bit)", PV);
+        OVMHELPERMAP.put("Other Linux (64-bit)", PV);
+        OVMHELPERMAP.put("Other PV (32-bit)", PV);
+        OVMHELPERMAP.put("Other PV (64-bit)", PV);
+        OVMHELPERMAP.put("Debian GNU/Linux 7(32-bit)", PV);
+        OVMHELPERMAP.put("Debian GNU/Linux 7(64-bit)", PV);
+        OVMHELPERMAP.put("Linux HVM (32-bit)", HVM);
+        OVMHELPERMAP.put("Linux HVM (64-bit)", HVM);
+        OVMHELPERMAP.put("Dos", HVM);
+        OVMHELPERMAP.put("Windows 7 (32-bit)", HVM);
+        OVMHELPERMAP.put("Windows 7 (64-bit)", HVM);
+        OVMHELPERMAP.put("Windows 8 (64-bit)", HVM);
+        OVMHELPERMAP.put("Windows Server 2003 (32-bit)", HVM);
+        OVMHELPERMAP.put("Windows Server 2003 (64-bit)", HVM);
+        OVMHELPERMAP.put("Windows Server 2008 (32-bit)", HVM);
+        OVMHELPERMAP.put("Windows Server 2008 (64-bit)", HVM);
+        OVMHELPERMAP.put("Windows Server 2008 R2 (64-bit)", HVM);
+        OVMHELPERMAP.put("Windows Server 2012 (64-bit)", HVM);
+        OVMHELPERMAP.put("Windows 2000 SP4 (32-bit)", HVM);
+        OVMHELPERMAP.put("Windows Vista (32-bit)", HVM);
+        OVMHELPERMAP.put("Windows XP SP2 (32-bit)", HVM);
+        OVMHELPERMAP.put("Windows XP SP3 (32-bit)", HVM);
+        OVMHELPERMAP.put("Sun Solaris 10(32-bit)", HVM);
+        OVMHELPERMAP.put("Sun Solaris 10(64-bit)", HVM);
+        OVMHELPERMAP.put("Sun Solaris 9(Experimental)", HVM);
+        OVMHELPERMAP.put("Sun Solaris 8(Experimental)", HVM);
+        OVMHELPERMAP.put("Sun Solaris 11 (32-bit)", HVM);
+        OVMHELPERMAP.put("Sun Solaris 11 (64-bit)", HVM);
+        OVMHELPERMAP.put("Sun Solaris PV (32-bit)", PV);
+        OVMHELPERMAP.put("Sun Solaris PV (64-bit)", PV);
+        OVMHELPERMAP.put("Sun Solaris Sparc (32-bit)", DOMSOL);
+        OVMHELPERMAP.put("Sun Solaris Sparc (64-bit)", DOMSOL);
+    }
+
+    public String getOvm3GuestType(String stdType) {
+        return OVMHELPERMAP.get(stdType);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c27c6943/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VmSupport.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VmSupport.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VmSupport.java
new file mode 100644
index 0000000..fcff316
--- /dev/null
+++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/helpers/Ovm3VmSupport.java
@@ -0,0 +1,475 @@
+/*******************************************************************************
+ * 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.ovm3.resources.helpers;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.log4j.Logger;
+import org.apache.xmlrpc.XmlRpcException;
+
+import com.cloud.agent.api.Answer;
+// import com.cloud.agent.api.AttachVolumeAnswer;
+// import com.cloud.agent.api.AttachVolumeCommand;
+import com.cloud.agent.api.GetVmStatsAnswer;
+import com.cloud.agent.api.GetVmStatsCommand;
+import com.cloud.agent.api.GetVncPortAnswer;
+import com.cloud.agent.api.GetVncPortCommand;
+import com.cloud.agent.api.MigrateAnswer;
+import com.cloud.agent.api.MigrateCommand;
+import com.cloud.agent.api.PlugNicAnswer;
+import com.cloud.agent.api.PlugNicCommand;
+import com.cloud.agent.api.PrepareForMigrationAnswer;
+import com.cloud.agent.api.PrepareForMigrationCommand;
+import com.cloud.agent.api.UnPlugNicAnswer;
+import com.cloud.agent.api.UnPlugNicCommand;
+import com.cloud.agent.api.VmStatsEntry;
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.agent.api.to.DiskTO;
+import com.cloud.agent.api.to.NfsTO;
+import com.cloud.agent.api.to.NicTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.HostVO;
+import com.cloud.hypervisor.ovm3.objects.CloudstackPlugin;
+import com.cloud.hypervisor.ovm3.objects.Connection;
+import com.cloud.hypervisor.ovm3.objects.Ovm3ResourceException;
+import com.cloud.hypervisor.ovm3.objects.OvmObject;
+import com.cloud.hypervisor.ovm3.objects.Xen;
+import com.cloud.hypervisor.ovm3.resources.Ovm3StorageProcessor;
+import com.cloud.resource.ResourceManager;
+import com.cloud.storage.Volume;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.VirtualMachine.State;
+
+public class Ovm3VmSupport {
+    private final Logger LOGGER = Logger.getLogger(Ovm3VmSupport.class);
+    private OvmObject ovmObject = new OvmObject();
+    private ResourceManager resourceMgr;
+    private Connection c;
+    private Ovm3HypervisorNetwork network;
+    private Ovm3Configuration config;
+    private Ovm3HypervisorSupport hypervisor;
+    private Ovm3StorageProcessor processor;
+    private Ovm3StoragePool pool;
+    private final Map<String, Map<String, String>> vmStats = new ConcurrentHashMap<String, Map<String, String>>();
+    public Ovm3VmSupport(Connection conn,
+            Ovm3Configuration ovm3config,
+            Ovm3HypervisorSupport ovm3hyper,
+            Ovm3StorageProcessor ovm3stp,
+            Ovm3StoragePool ovm3sp,
+            Ovm3HypervisorNetwork ovm3hvn) {
+        c = conn;
+        config = ovm3config;
+        hypervisor = ovm3hyper;
+        pool = ovm3sp;
+        processor = ovm3stp;
+        network = ovm3hvn;
+    }
+    public Boolean createVifs(Xen.Vm vm, VirtualMachineTO spec)
+            throws Ovm3ResourceException {
+        if (spec.getNics() != null) {
+            NicTO[] nics = spec.getNics();
+            return createVifs(vm, nics);
+        } else {
+            LOGGER.info("No nics for vm " + spec.getName());
+            return false;
+        }
+    }
+
+    private Boolean createVifs(Xen.Vm vm, NicTO[] nics)
+            throws Ovm3ResourceException {
+        for (NicTO nic : nics) {
+            if (!createVif(vm, nic)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /* should add bitrates and latency... */
+    private Boolean createVif(Xen.Vm vm, NicTO nic)
+            throws Ovm3ResourceException {
+        try {
+            String net = network.getNetwork(nic);
+            if (net != null) {
+                LOGGER.debug("Adding vif " + nic.getDeviceId() + " "
+                        + nic.getMac() + " " + net + " to " + vm.getVmName());
+                vm.addVif(nic.getDeviceId(), net, nic.getMac());
+            } else {
+                LOGGER.debug("Unable to add vif " + nic.getDeviceId()
+                        + " no network for " + vm.getVmName());
+                return false;
+            }
+        } catch (Exception e) {
+            String msg = "Unable to add vif " + nic.getType() + " for "
+                    + vm.getVmName() + " " + e.getMessage();
+            LOGGER.debug(msg);
+            throw new Ovm3ResourceException(msg);
+        }
+        return true;
+    }
+    private Boolean deleteVif(Xen.Vm vm, NicTO nic)
+            throws Ovm3ResourceException {
+        /* here we should use the housekeeping of VLANs/Networks etc..
+         * so we can clean after the last VM is gone
+         */
+        try {
+            String net = network.getNetwork(nic);
+            if (net != null) {
+                LOGGER.debug("Removing vif " + nic.getDeviceId() + " " + " "
+                        + nic.getMac() + " " + net + " from " + vm.getVmName());
+                vm.removeVif(net, nic.getMac());
+            } else {
+                LOGGER.debug("Unable to remove vif " + nic.getDeviceId()
+                        + " no network for " + vm.getVmName());
+                return false;
+            }
+        } catch (Exception e) {
+            String msg = "Unable to remove vif " + nic.getType() + " for "
+                    + vm.getVmName() + " " + e.getMessage();
+            LOGGER.debug(msg);
+            throw new Ovm3ResourceException(msg);
+        }
+        return true;
+    }
+/*
+    public AttachVolumeAnswer execute(AttachVolumeCommand cmd) {
+        return new AttachVolumeAnswer(cmd, "You must stop " + cmd.getVmName()
+                + " first, Ovm3 doesn't support hotplug datadisk");
+    }
+*/
+    /* Migration should make sure both HVs are the same ? */
+    public PrepareForMigrationAnswer execute(PrepareForMigrationCommand cmd) {
+        VirtualMachineTO vm = cmd.getVirtualMachine();
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Preparing host for migrating " + vm.getName());
+        }
+        NicTO[] nics = vm.getNics();
+        try {
+            for (NicTO nic : nics) {
+                network.getNetwork(nic);
+            }
+            hypervisor.setVmState(vm.getName(), State.Migrating);
+            LOGGER.debug("VM " + vm.getName() + " is in Migrating state");
+            return new PrepareForMigrationAnswer(cmd);
+        } catch (Ovm3ResourceException e) {
+            LOGGER.error("Catch Exception " + e.getClass().getName()
+                    + " prepare for migration failed due to: " + e.getMessage());
+            return new PrepareForMigrationAnswer(cmd, e);
+        }
+    }
+
+    /* do migrations of VMs in a simple way just inside a cluster for now */
+    public MigrateAnswer execute(final MigrateCommand cmd) {
+        final String vmName = cmd.getVmName();
+        String destUuid = cmd.getHostGuid();
+        String destIp = cmd.getDestinationIp();
+        State state = State.Error;
+        /*
+         * TODO: figure out non pooled migration, works from CLI but not from
+         * the agent... perhaps pause the VM and then migrate it ? for now just
+         * stop the VM.
+         */
+        String msg = "Migrating " + vmName + " to " + destIp;
+        LOGGER.info(msg);
+        if (!config.getAgentInOvm3Cluster() && !config.getAgentInOvm3Pool()) {
+            try {
+                Xen xen = new Xen(c);
+                Xen.Vm vm = xen.getRunningVmConfig(vmName);
+                HostVO destHost = resourceMgr.findHostByGuid(destUuid);
+                if (destHost == null) {
+                    msg = "Unable to find migration target host in DB "
+                            + destUuid + " with ip " + destIp;
+                    LOGGER.info(msg);
+                    return new MigrateAnswer(cmd, false, msg, null);
+                }
+                xen.stopVm(ovmObject.deDash(vm.getVmRootDiskPoolId()),
+                        vm.getVmUuid());
+                msg = destHost.toString();
+                state = State.Stopping;
+                return new MigrateAnswer(cmd, false, msg, null);
+            } catch (Ovm3ResourceException e) {
+                msg = "Unpooled VM Migrate of " + vmName + " to " + destUuid
+                        + " failed due to: " + e.getMessage();
+                LOGGER.debug(msg, e);
+                return new MigrateAnswer(cmd, false, msg, null);
+            } finally {
+                /* shouldn't we just reinitialize completely as a last resort ? */
+                hypervisor.setVmState(vmName, state);
+            }
+        } else {
+            try {
+                Xen xen = new Xen(c);
+                Xen.Vm vm = xen.getRunningVmConfig(vmName);
+                if (vm == null) {
+                    state = State.Stopped;
+                    msg = vmName + " is no running on " + config.getAgentHostname();
+                    return new MigrateAnswer(cmd, false, msg, null);
+                }
+                /* not a storage migration!!! */
+                xen.migrateVm(ovmObject.deDash(vm.getVmRootDiskPoolId()),
+                        vm.getVmUuid(), destIp);
+                state = State.Stopping;
+                msg = "Migration of " + vmName + " successfull";
+                return new MigrateAnswer(cmd, true, msg, null);
+            } catch (Ovm3ResourceException e) {
+                msg = "Pooled VM Migrate" + ": Migration of " + vmName + " to "
+                        + destIp + " failed due to " + e.getMessage();
+                LOGGER.debug(msg, e);
+                return new MigrateAnswer(cmd, false, msg, null);
+            } finally {
+                hypervisor.setVmState(vmName, state);
+            }
+        }
+    }
+
+    /*
+     */
+    public GetVncPortAnswer execute(GetVncPortCommand cmd) {
+        try {
+            Xen host = new Xen(c);
+            Xen.Vm vm = host.getRunningVmConfig(cmd.getName());
+            Integer vncPort = vm.getVncPort();
+            LOGGER.debug("get vnc port for " + cmd.getName() + ": " + vncPort);
+            return new GetVncPortAnswer(cmd, c.getIp(), vncPort);
+        } catch (Ovm3ResourceException e) {
+            LOGGER.debug("get vnc port for " + cmd.getName() + " failed", e);
+            return new GetVncPortAnswer(cmd, e.getMessage());
+        }
+    }
+
+    private VmStatsEntry getVmStat(String vmName) {
+        CloudstackPlugin cSp = new CloudstackPlugin(c);
+        Map<String, String> oldVmStats = null;
+        Map<String, String> newVmStats = null;
+        VmStatsEntry stats = new VmStatsEntry();
+        try {
+            if (vmStats.containsKey(vmName)) {
+                oldVmStats = new HashMap<String, String>();
+                oldVmStats.putAll(vmStats.get(vmName));
+            }
+            newVmStats = cSp.ovsDomUStats(vmName);
+        } catch (Ovm3ResourceException e) {
+            LOGGER.info("Unable to retrieve stats from " + vmName, e);
+            return stats;
+        }
+        if (oldVmStats == null) {
+            LOGGER.debug("No old stats retrieved stats from " + vmName);
+            stats.setNumCPUs(1);
+            stats.setNetworkReadKBs(0);
+            stats.setNetworkWriteKBs(0);
+            stats.setDiskReadKBs(0);
+            stats.setDiskWriteKBs(0);
+            stats.setDiskReadIOs(0);
+            stats.setDiskWriteIOs(0);
+            stats.setCPUUtilization(0);
+            stats.setEntityType("vm");
+        } else {
+            LOGGER.debug("Retrieved new stats from " + vmName);
+            int cpus = Integer.parseInt(newVmStats.get("vcpus"));
+            stats.setNumCPUs(cpus);
+            stats.setNetworkReadKBs(doubleMin(newVmStats.get("rx_bytes"), oldVmStats.get("rx_bytes")));
+            stats.setNetworkWriteKBs(doubleMin(newVmStats.get("tx_bytes"), oldVmStats.get("tx_bytes")));
+            stats.setDiskReadKBs(doubleMin(newVmStats.get("rd_bytes"), oldVmStats.get("rd_bytes")));
+            stats.setDiskWriteKBs(doubleMin(newVmStats.get("rw_bytes"), oldVmStats.get("rw_bytes")));
+            stats.setDiskReadIOs(doubleMin(newVmStats.get("rd_ops"), oldVmStats.get("rd_ops")));
+            stats.setDiskWriteIOs(doubleMin(newVmStats.get("rw_ops"), oldVmStats.get("rw_ops")));
+            Double dCpu = doubleMin(newVmStats.get("cputime"), oldVmStats.get("cputime"));
+            Double dTime = doubleMin(newVmStats.get("uptime"), oldVmStats.get("uptime"));
+            Double cpupct = dCpu / dTime * 100 * cpus;
+            stats.setCPUUtilization(cpupct);
+            stats.setEntityType("vm");
+        }
+        ((ConcurrentHashMap<String, Map<String, String>>) vmStats).put(
+                vmName, newVmStats);
+        return stats;
+    }
+    private Double doubleMin(String x, String y) {
+        try {
+            return (Double.parseDouble(x) - Double.parseDouble(y));
+        } catch (NullPointerException e) {
+            return 0D;
+        }
+    }
+
+    public GetVmStatsAnswer execute(GetVmStatsCommand cmd) {
+        List<String> vmNames = cmd.getVmNames();
+        Map<String, VmStatsEntry> vmStatsNameMap = new HashMap<String, VmStatsEntry>();
+        for (String vmName : vmNames) {
+            VmStatsEntry e = getVmStat(vmName);
+            vmStatsNameMap.put(vmName, e);
+        }
+        return new GetVmStatsAnswer(cmd,
+                (HashMap<String, VmStatsEntry>) vmStatsNameMap);
+    }
+
+    /* This is not create for us, but really start */
+/*
+    public boolean startVm(String repoId, String vmId) throws XmlRpcException {
+        Xen host = new Xen(c);
+        try {
+            if (host.getRunningVmConfig(vmId) == null) {
+                LOGGER.error("Create VM " + vmId + " first on " + c.getIp());
+                return false;
+            } else {
+                LOGGER.info("VM " + vmId + " exists on " + c.getIp());
+            }
+            host.startVm(repoId, vmId);
+        } catch (Exception e) {
+            LOGGER.error("Failed to start VM " + vmId + " on " + c.getIp()
+                    + " " + e.getMessage());
+            return false;
+        }
+        return true;
+    }
+*/
+    /*
+     * TODO: OVM already cleans stuff up, just not the extra bridges which we
+     * don't want right now, as we'd have to keep a state table of which vlans
+     * need to stay on the host!? A map with vlanid -> list-o-hosts
+     */
+    private void cleanupNetwork(List<String> vifs) throws XmlRpcException {
+        /* peel out vif info for vlan stuff */
+    }
+
+    public void cleanup(Xen.Vm vm) {
+        try {
+            cleanupNetwork(vm.getVmVifs());
+        } catch (XmlRpcException e) {
+            LOGGER.info("Clean up network for " + vm.getVmName() + " failed", e);
+        }
+        String vmName = vm.getVmName();
+        /* should become a single entity */
+        vmStats.remove(vmName);
+    }
+
+    /*
+     * Add rootdisk, datadisk and iso's
+     */
+    public Boolean createVbds(Xen.Vm vm, VirtualMachineTO spec) {
+        if (spec.getDisks() == null) {
+            LOGGER.info("No disks defined for " + vm.getVmName());
+            return false;
+        }
+        for (DiskTO disk : spec.getDisks()) {
+            try {
+                if (disk.getType() == Volume.Type.ROOT) {
+                    VolumeObjectTO vol = (VolumeObjectTO) disk.getData();
+                    String diskFile = processor.getVirtualDiskPath(vol.getUuid(),  vol.getDataStore().getUuid());
+                    vm.addRootDisk(diskFile);
+                    vm.setPrimaryPoolUuid(vol.getDataStore().getUuid());
+                    LOGGER.debug("Adding root disk: " + diskFile);
+                } else if (disk.getType() == Volume.Type.ISO) {
+                    DataTO isoTO = disk.getData();
+                    if (isoTO.getPath() != null) {
+                        TemplateObjectTO template = (TemplateObjectTO) isoTO;
+                        DataStoreTO store = template.getDataStore();
+                        if (!(store instanceof NfsTO)) {
+                            throw new CloudRuntimeException(
+                                    "unsupported protocol");
+                        }
+                        NfsTO nfsStore = (NfsTO) store;
+                        String secPoolUuid = pool.setupSecondaryStorage(nfsStore
+                                .getUrl());
+                        String isoPath = config.getAgentSecStoragePath() + File.separator
+                                + secPoolUuid + File.separator
+                                + template.getPath();
+                        vm.addIso(isoPath);
+                        /* check if secondary storage is mounted */
+                        LOGGER.debug("Adding ISO: " + isoPath);
+                    }
+                } else if (disk.getType() == Volume.Type.DATADISK) {
+                    VolumeObjectTO vol = (VolumeObjectTO) disk.getData();
+                    String diskFile = processor.getVirtualDiskPath(vol.getUuid(),  vol.getDataStore().getUuid());
+                    vm.addDataDisk(diskFile);
+                    LOGGER.debug("Adding data disk: "
+                            + diskFile);
+                } else {
+                    throw new CloudRuntimeException("Unknown disk type: "
+                            + disk.getType());
+                }
+            } catch (Exception e) {
+                LOGGER.debug("CreateVbds failed", e);
+                throw new CloudRuntimeException("Exception" + e.getMessage(), e);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Implements the unplug and plug feature for Nics, the boolan decides
+     * to either plug (true) or unplug (false)
+     *
+     * @param nic
+     * @param vmName
+     * @param plug
+     * @return
+     */
+    private Answer plugNunplugNic(NicTO nic, String vmName, Boolean plug) {
+        try {
+            Xen xen = new Xen(c);
+            Xen.Vm vm = xen.getVmConfig(vmName);
+            /* check running */
+            if (vm == null) {
+                return new Answer(null, false,
+                        "Unable to execute command due to missing VM");
+            }
+            // setup the NIC in the VM config.
+            if (plug) {
+                createVif(vm, nic);
+                vm.setupVifs();
+            } else {
+                deleteVif(vm, nic);
+            }
+            // execute the change
+            xen.configureVm(ovmObject.deDash(vm.getPrimaryPoolUuid()),
+                    vm.getVmUuid());
+        } catch (Ovm3ResourceException e) {
+            String msg = "Unable to execute command due to " + e.toString();
+            LOGGER.debug(msg);
+            return new Answer(null, false, msg);
+        }
+        return new Answer(null, true, "success");
+    }
+    /**
+     * PlugNicAnswer: plug a network interface into a VM
+     * @param cmd
+     * @return
+     */
+    public PlugNicAnswer execute(PlugNicCommand cmd) {
+        Answer ans = plugNunplugNic(cmd.getNic(), cmd.getVmName(), true);
+        return new PlugNicAnswer(cmd, ans.getResult(), ans.getDetails());
+    }
+
+    /**
+     * UnPlugNicAnswer: remove a nic from a VM
+     * @param cmd
+     * @return
+     */
+    public UnPlugNicAnswer execute(UnPlugNicCommand cmd) {
+        Answer ans = plugNunplugNic(cmd.getNic(), cmd.getVmName(), false);
+        return new UnPlugNicAnswer(cmd, ans.getResult(), ans.getDetails());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c27c6943/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-compute/module.properties
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-compute/module.properties b/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-compute/module.properties
new file mode 100644
index 0000000..69e6469
--- /dev/null
+++ b/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-compute/module.properties
@@ -0,0 +1,18 @@
+# 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.
+name=ovm3-compute
+parent=compute

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c27c6943/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-compute/spring-ovm3-compute-context.xml
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-compute/spring-ovm3-compute-context.xml b/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-compute/spring-ovm3-compute-context.xml
new file mode 100644
index 0000000..308015e
--- /dev/null
+++ b/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-compute/spring-ovm3-compute-context.xml
@@ -0,0 +1,41 @@
+<!--
+  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="Ovm3Fencer" class="com.cloud.hypervisor.ovm3.resources.Ovm3FenceBuilder">
+        <property name="name" value="Ovm3FenceBuilder" />
+    </bean>
+
+    <bean id="Ovm3Guru" class="com.cloud.hypervisor.ovm3.resources.Ovm3HypervisorGuru">
+        <property name="name" value="Ovm3Guru" />
+    </bean>
+
+    <bean id="Ovm3Investigator" class="com.cloud.ha.Ovm3Investigator">
+        <property name="name" value="Ovm3Investigator" />
+    </bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c27c6943/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-discoverer/module.properties
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-discoverer/module.properties b/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-discoverer/module.properties
new file mode 100644
index 0000000..025d4cf
--- /dev/null
+++ b/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-discoverer/module.properties
@@ -0,0 +1,18 @@
+# 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.
+name=ovm3-discoverer
+parent=discoverer

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c27c6943/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-discoverer/spring-ovm3-discoverer-context.xml
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-discoverer/spring-ovm3-discoverer-context.xml b/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-discoverer/spring-ovm3-discoverer-context.xml
new file mode 100644
index 0000000..a28a2fc
--- /dev/null
+++ b/plugins/hypervisors/ovm3/src/main/resources/META-INF/cloudstack/ovm3-discoverer/spring-ovm3-discoverer-context.xml
@@ -0,0 +1,34 @@
+<!--
+  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="Ovm3Discoverer" class="com.cloud.hypervisor.ovm3.resources.Ovm3Discoverer">
+        <property name="name" value="Ovm3Discover" />
+    </bean>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c27c6943/plugins/hypervisors/ovm3/src/test/java/com/cloud/hypervisor/ovm3/objects/CloudStackPluginTest.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm3/src/test/java/com/cloud/hypervisor/ovm3/objects/CloudStackPluginTest.java b/plugins/hypervisors/ovm3/src/test/java/com/cloud/hypervisor/ovm3/objects/CloudStackPluginTest.java
new file mode 100644
index 0000000..87e0580
--- /dev/null
+++ b/plugins/hypervisors/ovm3/src/test/java/com/cloud/hypervisor/ovm3/objects/CloudStackPluginTest.java
@@ -0,0 +1,323 @@
+/*******************************************************************************
+ * 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.ovm3.objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+import com.cloud.hypervisor.ovm3.objects.CloudstackPlugin.ReturnCode;
+
+public class CloudStackPluginTest {
+    private static final String VMNAME = "test";
+    String domrIp = "169.254.3.2";
+    public String getDomrIp() {
+        return domrIp;
+    }
+
+    public String getDom0Ip() {
+        return dom0Ip;
+    }
+
+    public Integer getDomrPort() {
+        return domrPort;
+    }
+
+    String dom0Ip = "192.168.1.64";
+    Integer domrPort = 3922;
+    String host = "ovm-1";
+    String path = "/tmp";
+    String dirpath = "/tmp/testing";
+    String filename = "test.txt";
+    String content = "This is some content";
+    String bridge = "xenbr0";
+    String vncPort = "5900";
+    Integer port = 8899;
+    Integer retries = 1;
+    Integer interval = 1;
+    Integer timeout = 120;
+
+    ConnectionTest con = new ConnectionTest();
+    CloudstackPlugin cSp = new CloudstackPlugin(con);
+    XmlTestResultTest results = new XmlTestResultTest();
+
+    String domrExecXml = "<?xml version='1.0'?>"
+            + "<methodResponse>"
+            + "<params>"
+            + "<param>"
+            + "<value><struct>"
+            + "<member>"
+            + "<name>out</name>"
+            + "<value><string>clearUsageRules.sh func.sh hv-kvp-daemon_3.1_amd64.deb monitorServices.py reconfigLB.sh redundant_router</string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>err</name>"
+            + "<value><string></string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>rc</name>"
+            + "<value><i8>0</i8></value>"
+            + "</member>"
+            + "</struct></value>"
+            + "</param>"
+            + "</params>"
+            + "</methodResponse>";
+    String dom0StatsXml = "<?xml version='1.0'?>\n" +
+            "<methodResponse>\n" +
+            "<params>\n" +
+            "<param>\n" +
+            "<value><struct>\n" +
+            "<member>\n" +
+            "<name>rx</name>\n" +
+            "<value><string>11631523\n" +
+            "</string></value>\n" +
+            "</member>\n" +
+            "<member>\n" +
+            "<name>total</name>\n" +
+            "<value><string>4293918720</string></value>\n" +
+            "</member>\n" +
+            "<member>\n" +
+            "<name>tx</name>\n" +
+            "<value><string>16927399\n" +
+            "</string></value>\n" +
+            "</member>\n" +
+            "<member>\n" +
+            "<name>cpu</name>\n" +
+            "<value><string>1.5</string></value>\n" +
+            "</member>\n" +
+            "<member>\n" +
+            "<name>free</name>\n" +
+            "<value><string>3162505216</string></value>\n" +
+            "</member>\n" +
+            "</struct></value>\n" +
+            "</param>\n" +
+            "</params>\n" +
+            "</methodResponse>";
+    String domuStatsXml = "<?xml version='1.0'?>"
+            + "<methodResponse>"
+            + "<params>"
+            + "<param>"
+            + "<value><struct>"
+            + "<member>"
+            + "<name>uptime</name>"
+            + "<value><string>862195495455</string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>rx_bytes</name>"
+            + "<value><string>52654010</string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>wr_ops</name>"
+            + "<value><string>521674</string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>vcpus</name>"
+            + "<value><string>1</string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>cputime</name>"
+            + "<value><string>295303661496</string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>rd_ops</name>"
+            + "<value><string>14790</string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>rd_bytes</name>"
+            + "<value><string>250168320</string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>tx_bytes</name>"
+            + "<value><string>161389183</string></value>"
+            + "</member>"
+            + "<member>"
+            + "<name>wr_bytes</name>"
+            + "<value><string>1604468736</string></value>"
+            + "</member>"
+            + "</struct></value>"
+            + "</param>"
+            + "</params>"
+            + "</methodResponse>";
+    private String dom0StorageCheckXml = "<?xml version='1.0'?>"
+            + "<methodResponse>"
+            + "<params>"
+            + "<param>"
+            + "<value><array><data>"
+            + "<value><boolean>1</boolean></value>"
+            + "<value><boolean>0</boolean></value>"
+            + "</data></array></value>"
+            + "</param>"
+            + "</params>"
+            + "</methodResponse>";
+    public String getDom0StorageCheckXml() {
+        return dom0StorageCheckXml;
+    }
+    public String getDomrExecXml() {
+        return domrExecXml;
+    }
+
+    public String getDom0StatsXml() {
+        return dom0StatsXml;
+    }
+
+    public String getDomuStatsXml() {
+        return domuStatsXml;
+    }
+
+    @Test
+    public void testDom0CheckStorageHealthCheck() throws Ovm3ResourceException {
+        con.setResult(dom0StorageCheckXml);
+        results.basicBooleanTest(cSp.dom0CheckStorageHealthCheck("", "", "", 120, 1));
+        results.basicBooleanTest(cSp.dom0CheckStorageHealthCheck(), false);
+    }
+    @Test
+    public void testOvsUploadFile() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.ovsUploadFile(path, filename, content));
+    }
+
+    @Test
+    public void testOvsUploadSshKey() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.ovsUploadSshKey(path, content));
+    }
+
+    @Test
+    public void testOvsDomrUploadFile() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.ovsDomrUploadFile(VMNAME, path, filename, content));
+    }
+
+    @Test
+    public void testGetVncPort() throws Ovm3ResourceException {
+        con.setResult(results.getString(vncPort));
+        results.basicStringTest(cSp.getVncPort(VMNAME), vncPort);
+    }
+
+    @Test
+    public void testDom0CheckPort() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.dom0CheckPort(host, port, retries, interval));
+        /* test nothing */
+        con.setNull();
+        results.basicBooleanTest(
+                cSp.dom0CheckPort(host, port, retries, interval), false);
+        /* for the last test we need to fake the timeout... */
+    }
+
+    @Test
+    public void testDom0Ip() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.dom0HasIp(dom0Ip));
+        con.setResult(results.getBoolean(false));
+        results.basicBooleanTest(cSp.dom0HasIp(dom0Ip), false);
+    }
+
+    @Test
+    public void testDomrExec() throws Ovm3ResourceException {
+        con.setResult(domrExecXml);
+        ReturnCode x = cSp.domrExec(domrIp, "ls");
+        assertNotNull(x);
+        assertEquals(x.getExit(), (Integer) 0);
+        assertEquals(x.getRc(), true);
+        assertEquals(x.getExit(), (Integer) 0);
+        assertNotNull(x.getStdOut());
+
+        /* failed */
+        domrExecXml = domrExecXml.replace("<i8>0</i8>", "<i8>1</i8>");
+        domrExecXml = domrExecXml.replace("<value><string></string></value>", "<value><string>Something went wrong!</string></value>");
+        con.setResult(domrExecXml);
+        ReturnCode y = cSp.domrExec(domrIp, "ls");
+        assertNotNull(y);
+        assertEquals(y.getRc(), false);
+        assertEquals(y.getExit(), (Integer) 1);
+        assertNotNull(x.getStdErr());
+    }
+
+    @Test
+    public void testOvsDom0Stats() throws Ovm3ResourceException {
+        con.setResult(dom0StatsXml);
+        Map<String, String> stats = cSp.ovsDom0Stats(bridge);
+        results.basicStringTest(stats.get("cpu"), "1.5");
+    }
+
+    @Test
+    public void TestOvsDomUStats() throws Ovm3ResourceException {
+        con.setResult(domuStatsXml);
+        Map<String, String> stats = cSp.ovsDomUStats(VMNAME);
+        results.basicStringTest(stats.get("cputime"), "295303661496");
+    }
+
+    @Test
+    public void TestDomrCheckPort() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.domrCheckPort(domrIp, domrPort));
+    }
+
+    @Test
+    public void TestDomrCheckSsh() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.domrCheckSsh(domrIp));
+    }
+
+    @Test
+    public void TestOvsControlInterface() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.ovsControlInterface("control0", "169.254.0.1/16"));
+    }
+
+    @Test
+    public void TestPing() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.ping(host));
+    }
+
+    @Test
+    public void TestOvsCheckFile() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.ovsCheckFile(filename));
+    }
+
+    @Test
+    public void dom0CheckStorageHealth() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.dom0CheckStorageHealth("", "", "", 120));
+        con.setResult(results.getBoolean(false));
+        results.basicBooleanTest(cSp.dom0CheckStorageHealth("", "", "", 120), false);
+    }
+    @Test
+    public void TestovsMkdirs() throws Ovm3ResourceException {
+        con.setResult(results.getNil());
+        results.basicBooleanTest(cSp.ovsMkdirs(dirpath));
+    }
+    @Test
+    public void TestovsMkdirsDirExists() throws Ovm3ResourceException {
+        con.setResult(results.getBoolean(true));
+        results.basicBooleanTest(cSp.ovsMkdirs(dirpath), false);
+    }
+    @Test
+    public void TestovsMkdirs2() throws Ovm3ResourceException {
+            con.setResult(results.getNil());
+            results.basicBooleanTest(cSp.ovsMkdirs(dirpath, 755));
+    }
+
+}