cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wid...@apache.org
Subject [4/15] git commit: Add RBD support for primary storage
Date Mon, 02 Jul 2012 12:17:34 GMT
Add RBD support for primary storage

This patch adds RBD (RADOS Block Device) support for primary storage in combination with KVM.

To get this patch working you need:
- Modified libvirt-java bindings with (github.com/wido/libvirt-java)
- libvirt with RBD storage pool support (>0.9.12)
- Qemu with RBD support (>0.14)

The primary storage does not support all the functions of CloudStack yet, for example snapshotting is disabled
due to the fact that backupping up a RBD snapshot is not possible in the way CloudStack wants to do it.

Creating templates from RBD volumes goes well, creating a VM from a template however is still a hit-and-miss.

NFS primary storage is also still required, you are not able to run your System VM's from RBD, they will need
to run on NFS.

Other then these points you can run instances with RBD backed disks.


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

Branch: refs/heads/rbd
Commit: 2108dc5dacef0c054d68e4be339b7d1ab58996d9
Parents: 1a2f354
Author: Wido den Hollander <wido@widodh.nl>
Authored: Fri Jun 29 17:32:19 2012 +0200
Committer: Wido den Hollander <wido@widodh.nl>
Committed: Sun Jul 1 15:13:45 2012 +0200

----------------------------------------------------------------------
 .../computing/LibvirtComputingResource.java        |   80 ++++-
 .../agent/resource/computing/LibvirtSecretDef.java |  108 +++++++
 .../resource/computing/LibvirtStoragePoolDef.java  |   80 +++++-
 .../computing/LibvirtStoragePoolXMLParser.java     |   35 ++-
 .../agent/resource/computing/LibvirtVMDef.java     |   66 ++++-
 .../com/cloud/agent/storage/KVMPhysicalDisk.java   |   16 +
 .../com/cloud/agent/storage/KVMStoragePool.java    |   10 +
 .../cloud/agent/storage/KVMStoragePoolManager.java |   21 +-
 .../cloud/agent/storage/LibvirtStorageAdaptor.java |  229 +++++++++++++--
 .../cloud/agent/storage/LibvirtStoragePool.java    |   50 ++++
 .../com/cloud/agent/storage/StorageAdaptor.java    |    4 +-
 api/src/com/cloud/agent/api/to/StorageFilerTO.java |    6 +
 api/src/com/cloud/storage/Storage.java             |    1 +
 api/src/com/cloud/storage/StoragePool.java         |    5 +
 build/package.xml                                  |    2 +-
 core/src/com/cloud/storage/StoragePoolVO.java      |   22 ++
 debian/cloud-agent-deps.install                    |    2 +-
 deps/.classpath                                    |    2 +-
 deps/cloud-libvirt-0.4.5.jar                       |  Bin 68899 -> 0 bytes
 deps/cloud-libvirt-0.4.7.jar                       |  Bin 0 -> 68788 bytes
 .../src/com/cloud/storage/StorageManagerImpl.java  |   12 +-
 .../allocator/FirstFitStoragePoolAllocator.java    |   13 +
 .../storage/snapshot/SnapshotManagerImpl.java      |    8 +
 setup/db/create-schema.sql                         |    1 +
 ui/index.jsp                                       |    1 +
 ui/scripts/sharedFunctions.js                      |   18 ++
 ui/scripts/system.js                               |   52 ++++
 27 files changed, 773 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java
index 112ab61..347ff87 100755
--- a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java
+++ b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java
@@ -30,12 +30,15 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.text.DateFormat;
 import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -154,6 +157,7 @@ import com.cloud.agent.resource.computing.KVMHABase.NfsStoragePool;
 import com.cloud.agent.resource.computing.LibvirtVMDef.ConsoleDef;
 import com.cloud.agent.resource.computing.LibvirtVMDef.DevicesDef;
 import com.cloud.agent.resource.computing.LibvirtVMDef.DiskDef;
+import com.cloud.agent.resource.computing.LibvirtVMDef.DiskDef.diskProtocol;
 import com.cloud.agent.resource.computing.LibvirtVMDef.FeaturesDef;
 import com.cloud.agent.resource.computing.LibvirtVMDef.GraphicDef;
 import com.cloud.agent.resource.computing.LibvirtVMDef.GuestDef;
@@ -1298,6 +1302,13 @@ public class LibvirtComputingResource extends ServerResourceBase implements
 
             KVMStoragePool primaryPool = _storagePoolMgr.getStoragePool(cmd
                     .getPool().getUuid());
+
+            if (primaryPool.getType() == StoragePoolType.RBD) {
+                s_logger.debug("Snapshots are not supported on RBD volumes");
+                return new ManageSnapshotAnswer(cmd, false,
+                    "Snapshots are not supported on RBD volumes");
+            }
+
             KVMPhysicalDisk disk = primaryPool.getPhysicalDisk(cmd
                     .getVolumePath());
             if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING
@@ -1644,16 +1655,43 @@ public class LibvirtComputingResource extends ServerResourceBase implements
                     + templateInstallFolder;
             _storage.mkdirs(tmpltPath);
 
-            Script command = new Script(_createTmplPath, _cmdsTimeout, s_logger);
-            command.add("-f", disk.getPath());
-            command.add("-t", tmpltPath);
-            command.add("-n", cmd.getUniqueName() + ".qcow2");
+            if (primary.getType() != StoragePoolType.RBD) {
+                Script command = new Script(_createTmplPath, _cmdsTimeout, s_logger);
+                command.add("-f", disk.getPath());
+                command.add("-t", tmpltPath);
+                command.add("-n", cmd.getUniqueName() + ".qcow2");
 
-            String result = command.execute();
+                String result = command.execute();
 
-            if (result != null) {
-                s_logger.debug("failed to create template: " + result);
-                return new CreatePrivateTemplateAnswer(cmd, false, result);
+                if (result != null) {
+                    s_logger.debug("failed to create template: " + result);
+                    return new CreatePrivateTemplateAnswer(cmd, false, result);
+                }
+            } else {
+                s_logger.debug("Converting RBD disk " + disk.getPath() + " into template " + cmd.getUniqueName());
+                Script.runSimpleBashScript("qemu-img convert"
+                                + " -f raw -O qcow2 "
+                                + KVMPhysicalDisk.RBDStringBuilder(primary.getSourceHost(),
+                                                primary.getSourcePort(),
+                                                primary.getAuthUserName(),
+                                                primary.getAuthSecret(),
+                                                disk.getPath())
+                                + " " + tmpltPath + "/" + cmd.getUniqueName() + ".qcow2");
+                File templateProp = new File(tmpltPath + "/template.properties");
+                if (!templateProp.exists()) {
+                    templateProp.createNewFile();
+                }
+
+                String templateContent = "filename=" + cmd.getUniqueName() + ".qcow2" + System.getProperty("line.separator");
+
+                DateFormat dateFormat = new SimpleDateFormat("MM_dd_yyyy");
+                Date date = new Date();
+                templateContent += "snapshot.name=" + dateFormat.format(date) + System.getProperty("line.separator");
+
+                FileOutputStream templFo = new FileOutputStream(templateProp);
+                templFo.write(templateContent.getBytes());
+                templFo.flush();
+                templFo.close();
             }
 
             Map<String, Object> params = new HashMap<String, Object>();
@@ -1756,8 +1794,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements
 
     protected Answer execute(ModifyStoragePoolCommand cmd) {
         KVMStoragePool storagepool = _storagePoolMgr.createStoragePool(cmd
-                .getPool().getUuid(), cmd.getPool().getHost(), cmd.getPool()
-                .getPath(), cmd.getPool().getType());
+                .getPool().getUuid(), cmd.getPool().getHost(), cmd.getPool().getPort(),
+                cmd.getPool().getPath(), cmd.getPool().getUserInfo(), cmd.getPool().getType());
         if (storagepool == null) {
             return new Answer(cmd, false, " Failed to create storage pool");
         }
@@ -2624,10 +2662,19 @@ public class LibvirtComputingResource extends ServerResourceBase implements
             } else {
                 int devId = (int) volume.getDeviceId();
 
-                if (volume.getType() == Volume.Type.DATADISK) {
-                    disk.defFileBasedDisk(physicalDisk.getPath(), devId,
-                            DiskDef.diskBus.VIRTIO,
-                            DiskDef.diskFmtType.QCOW2);
+                if (pool.getType() == StoragePoolType.RBD) {
+                                        /*
+                                                For RBD pools we use the secret mechanism in libvirt.
+                                                We store the secret under the UUID of the pool, that's why
+                                                we pass the pool's UUID as the authSecret
+                                        */
+                                        disk.defNetworkBasedDisk(physicalDisk.getPath().replace("rbd:", ""), pool.getSourceHost(), pool.getSourcePort(),
+                                                                 pool.getAuthUserName(), pool.getUuid(),
+                                                                 devId, diskBusType, diskProtocol.RBD);
+                                } else if (volume.getType() == Volume.Type.DATADISK) {
+                                        disk.defFileBasedDisk(physicalDisk.getPath(), devId,
+                                                        DiskDef.diskBus.VIRTIO,
+                                                        DiskDef.diskFmtType.QCOW2);
                 } else {
                     disk.defFileBasedDisk(physicalDisk.getPath(), devId,
                             diskBusType, DiskDef.diskFmtType.QCOW2);
@@ -2982,8 +3029,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements
         try {
 
             KVMStoragePool localStoragePool = _storagePoolMgr
-                    .createStoragePool(_localStorageUUID, "localhost",
-                            _localStoragePath, StoragePoolType.Filesystem);
+                    .createStoragePool(_localStorageUUID, "localhost", -1,
+                            _localStoragePath, "", StoragePoolType.Filesystem);
             com.cloud.agent.api.StoragePoolInfo pi = new com.cloud.agent.api.StoragePoolInfo(
                     localStoragePool.getUuid(), cmd.getPrivateIpAddress(),
                     _localStoragePath, _localStoragePath,
@@ -4083,5 +4130,4 @@ public class LibvirtComputingResource extends ServerResourceBase implements
 
         return new Answer(cmd, success, "");
     }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/resource/computing/LibvirtSecretDef.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtSecretDef.java b/agent/src/com/cloud/agent/resource/computing/LibvirtSecretDef.java
new file mode 100644
index 0000000..c1d396c
--- /dev/null
+++ b/agent/src/com/cloud/agent/resource/computing/LibvirtSecretDef.java
@@ -0,0 +1,108 @@
+/**
+ *  Copyright (C) 2012 Wido den Hollander  All rights reserved.
+ *
+ * This software is licensed under the GNU General Public License v3 or later.
+ *
+ * It is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.cloud.agent.resource.computing;
+
+public class LibvirtSecretDef {
+
+	public enum usage {
+		VOLUME("volume"), CEPH("ceph");
+		String _usage;
+
+		usage(String usage) {
+			_usage = usage;
+		}
+
+		@Override
+		public String toString() {
+			return _usage;
+		}
+	}
+
+	private usage _usage;
+	private boolean _ephemeral;
+	private boolean _private;
+	private String _uuid;
+	private String _description;
+	private String _cephName;
+	private String _volumeVolume;
+
+	public LibvirtSecretDef (usage usage, String uuid) {
+		_usage = usage;
+		_uuid = uuid;
+	}
+
+	public LibvirtSecretDef (usage usage, String uuid, String description) {
+		_usage = usage;
+		_uuid = uuid;
+		_description = description;
+	}
+
+	public boolean getEphemeral() {
+		return _ephemeral;
+	}
+
+	public boolean getPrivate() {
+		return _private;
+	}
+
+	public String getUuid() {
+		return _uuid;
+	}
+
+	public String getDescription() {
+		return _description;
+	}
+
+	public String getVolumeVolume() {
+		return _volumeVolume;
+	}
+
+	public String getCephName() {
+		return _cephName;
+	}
+
+	public void setVolumeVolume(String volume) {
+		_volumeVolume = volume;
+	}
+
+	public void setCephName(String name) {
+		_cephName = name;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder secretBuilder = new StringBuilder();
+		secretBuilder.append("<secret ephemeral='" + (_ephemeral ? "yes" : "no") + "' private='" + (_private ? "yes" : "no") + "'>\n");
+		secretBuilder.append("<uuid>" + _uuid + "</uuid>\n");
+		if (_description != null) {
+			secretBuilder.append("<description>" + _description + "</description>\n");
+		}
+		secretBuilder.append("<usage type='" + _usage + "'>\n");
+		if (_usage == _usage.VOLUME) {
+			secretBuilder.append("<volume>" + _volumeVolume + "</volume>\n");
+		}
+		if (_usage == _usage.CEPH) {
+			secretBuilder.append("<name>" + _cephName + "</name>\n");
+		}
+		secretBuilder.append("</usage>\n");
+		secretBuilder.append("</secret>\n");
+		return secretBuilder.toString();
+	}
+	
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java
index 582cd2e..9c28528 100644
--- a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java
+++ b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java
@@ -18,7 +18,7 @@ package com.cloud.agent.resource.computing;
 
 public class LibvirtStoragePoolDef {
     public enum poolType {
-        ISCSI("iscsi"), NETFS("netfs"), LOGICAL("logical"), DIR("dir");
+        ISCSI("iscsi"), NETFS("netfs"), LOGICAL("logical"), DIR("dir"), RBD("rbd");
         String _poolType;
 
         poolType(String poolType) {
@@ -31,12 +31,41 @@ public class LibvirtStoragePoolDef {
         }
     }
 
+    public enum authType {
+        CHAP("chap"), CEPH("ceph");
+        String _authType;
+
+        authType(String authType) {
+            _authType = authType;
+        }
+
+        @Override
+        public String toString() {
+            return _authType;
+        }
+    }
+
     private poolType _poolType;
     private String _poolName;
     private String _uuid;
     private String _sourceHost;
+    private int _sourcePort;
     private String _sourceDir;
     private String _targetPath;
+    private String _authUsername;
+    private authType _authType;
+    private String _secretUuid;
+
+    public LibvirtStoragePoolDef(poolType type, String poolName, String uuid,
+            String host, int port, String dir, String targetPath) {
+        _poolType = type;
+        _poolName = poolName;
+        _uuid = uuid;
+        _sourceHost = host;
+        _sourcePort = port;
+        _sourceDir = dir;
+        _targetPath = targetPath;
+    }
 
     public LibvirtStoragePoolDef(poolType type, String poolName, String uuid,
             String host, String dir, String targetPath) {
@@ -48,6 +77,20 @@ public class LibvirtStoragePoolDef {
         _targetPath = targetPath;
     }
 
+    public LibvirtStoragePoolDef(poolType type, String poolName, String uuid,
+            String sourceHost, int sourcePort, String dir, String authUsername,
+            authType authType, String secretUuid) {
+        _poolType = type;
+        _poolName = poolName;
+        _uuid = uuid;
+        _sourceHost = sourceHost;
+        _sourcePort = sourcePort;
+        _sourceDir = dir;
+        _authUsername = authUsername;
+        _authType = authType;
+        _secretUuid = secretUuid;
+    }
+
     public String getPoolName() {
         return _poolName;
     }
@@ -60,6 +103,10 @@ public class LibvirtStoragePoolDef {
         return _sourceHost;
     }
 
+    public int getSourcePort() {
+        return _sourcePort;
+    }
+
     public String getSourceDir() {
         return _sourceDir;
     }
@@ -68,6 +115,18 @@ public class LibvirtStoragePoolDef {
         return _targetPath;
     }
 
+    public String getAuthUserName() {
+        return _authUsername;
+    }
+
+    public String getSecretUUID() {
+        return _secretUuid;
+    }
+
+    public authType getAuthType() {
+        return _authType;
+    }
+
     @Override
     public String toString() {
         StringBuilder storagePoolBuilder = new StringBuilder();
@@ -81,9 +140,22 @@ public class LibvirtStoragePoolDef {
             storagePoolBuilder.append("<dir path='" + _sourceDir + "'/>\n");
             storagePoolBuilder.append("</source>\n");
         }
-        storagePoolBuilder.append("<target>\n");
-        storagePoolBuilder.append("<path>" + _targetPath + "</path>\n");
-        storagePoolBuilder.append("</target>\n");
+        if (_poolType == poolType.RBD) {
+            storagePoolBuilder.append("<source>\n");
+            storagePoolBuilder.append("<host name='" + _sourceHost + "' port='" + _sourcePort + "'/>\n");
+            storagePoolBuilder.append("<name>" + _sourceDir + "</name>\n");
+            if (_authUsername != null) {
+                storagePoolBuilder.append("<auth username='" + _authUsername + "' type='" + _authType + "'>\n");
+                storagePoolBuilder.append("<secret uuid='" + _secretUuid + "'/>\n");
+                storagePoolBuilder.append("</auth>\n");
+            }
+            storagePoolBuilder.append("</source>\n");
+        }
+        if (_poolType != poolType.RBD) {
+            storagePoolBuilder.append("<target>\n");
+            storagePoolBuilder.append("<path>" + _targetPath + "</path>\n");
+            storagePoolBuilder.append("</target>\n");
+        }
         storagePoolBuilder.append("</pool>\n");
         return storagePoolBuilder.toString();
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolXMLParser.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolXMLParser.java b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolXMLParser.java
index 5c45d76..cff4c2b 100644
--- a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolXMLParser.java
+++ b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolXMLParser.java
@@ -51,15 +51,34 @@ public class LibvirtStoragePoolXMLParser {
             Element source = (Element) rootElement.getElementsByTagName(
                     "source").item(0);
             String host = getAttrValue("host", "name", source);
-            String path = getAttrValue("dir", "path", source);
 
-            Element target = (Element) rootElement.getElementsByTagName(
-                    "target").item(0);
-            String targetPath = getTagValue("path", target);
-
-            return new LibvirtStoragePoolDef(
-                    LibvirtStoragePoolDef.poolType.valueOf(type.toUpperCase()),
-                    poolName, uuid, host, path, targetPath);
+            if (type.equalsIgnoreCase("rbd")) {
+                int port = Integer.parseInt(getAttrValue("host", "port", source));
+                String pool = getTagValue("name", source);
+
+                Element auth = (Element) source.getElementsByTagName(
+                    "auth").item(0);
+
+                if (auth != null) {
+                    String authUsername = auth.getAttribute("username");
+                    String authType = auth.getAttribute("type");
+                    return new LibvirtStoragePoolDef(LibvirtStoragePoolDef.poolType.valueOf(type.toUpperCase()),
+                        poolName, uuid, host, port, pool, authUsername, LibvirtStoragePoolDef.authType.valueOf(authType.toUpperCase()), uuid);
+                } else {
+                    return new LibvirtStoragePoolDef(LibvirtStoragePoolDef.poolType.valueOf(type.toUpperCase()),
+                        poolName, uuid, host, port, pool, "");
+                }
+            } else {
+                String path = getAttrValue("dir", "path", source);
+
+                Element target = (Element) rootElement.getElementsByTagName(
+                        "target").item(0);
+                String targetPath = getTagValue("path", target);
+
+                return new LibvirtStoragePoolDef(
+                        LibvirtStoragePoolDef.poolType.valueOf(type.toUpperCase()),
+                        poolName, uuid, host, path, targetPath);
+            }
         } catch (ParserConfigurationException e) {
             s_logger.debug(e.toString());
         } catch (SAXException e) {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java b/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java
index 8fd7815..3b07bcd 100644
--- a/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java
+++ b/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java
@@ -338,7 +338,7 @@ public class LibvirtVMDef {
         }
 
         enum diskType {
-            FILE("file"), BLOCK("block"), DIRECTROY("dir");
+            FILE("file"), BLOCK("block"), DIRECTROY("dir"), NETWORK("network");
             String _diskType;
 
             diskType(String type) {
@@ -351,6 +351,20 @@ public class LibvirtVMDef {
             }
         }
 
+        enum diskProtocol {
+            RBD("rbd"), SHEEPDOG("sheepdog");
+            String _diskProtocol;
+
+            diskProtocol(String protocol) {
+                _diskProtocol = protocol;
+            }
+
+            @Override
+            public String toString() {
+                return _diskProtocol;
+            }
+        }
+
         enum diskBus {
             IDE("ide"), SCSI("scsi"), VIRTIO("virtio"), XEN("xen"), USB("usb"), UML(
                     "uml"), FDC("fdc");
@@ -382,7 +396,12 @@ public class LibvirtVMDef {
 
         private deviceType _deviceType; /* floppy, disk, cdrom */
         private diskType _diskType;
+        private diskProtocol _diskProtocol;
         private String _sourcePath;
+        private String _sourceHost;
+        private int _sourcePort;
+        private String _authUserName;
+        private String _authSecretUUID;
         private String _diskLabel;
         private diskBus _bus;
         private diskFmtType _diskFmtType; /* qcow2, raw etc. */
@@ -461,6 +480,38 @@ public class LibvirtVMDef {
             _bus = bus;
         }
 
+        public void defNetworkBasedDisk(String diskName, String sourceHost, int sourcePort,
+                                        String authUserName, String authSecretUUID,
+                                        int devId, diskBus bus, diskProtocol protocol) {
+            _diskType = diskType.NETWORK;
+            _deviceType = deviceType.DISK;
+            _diskFmtType = diskFmtType.RAW;
+            _sourcePath = diskName;
+            _sourceHost = sourceHost;
+            _sourcePort = sourcePort;
+            _authUserName = authUserName;
+            _authSecretUUID = authSecretUUID;
+            _diskLabel = getDevLabel(devId, bus);
+            _bus = bus;
+            _diskProtocol = protocol;
+        }
+
+        public void defNetworkBasedDisk(String diskName, String sourceHost, int sourcePort,
+                                        String authUserName, String authSecretUUID,
+                                        String diskLabel, diskBus bus, diskProtocol protocol) {
+            _diskType = diskType.NETWORK;
+            _deviceType = deviceType.DISK;
+            _diskFmtType = diskFmtType.RAW;
+            _sourcePath = diskName;
+            _sourceHost = sourceHost;
+            _sourcePort = sourcePort;
+            _authUserName = authUserName;
+            _authSecretUUID = authSecretUUID;
+            _diskLabel = diskLabel;
+            _bus = bus;
+            _diskProtocol = protocol;
+        }
+
         public void setReadonly() {
             _readonly = true;
         }
@@ -527,6 +578,18 @@ public class LibvirtVMDef {
                     diskBuilder.append(" dev='" + _sourcePath + "'");
                 }
                 diskBuilder.append("/>\n");
+            } else if (_diskType == diskType.NETWORK) {
+                diskBuilder.append("<source ");
+                diskBuilder.append(" protocol='" + _diskProtocol + "'");
+                diskBuilder.append(" name='" + _sourcePath + "'");
+                diskBuilder.append(">\n");
+                diskBuilder.append("<host name='" + _sourceHost + "' port='" + _sourcePort + "'/>\n");
+                diskBuilder.append("</source>\n");
+                if (_authUserName != null) {
+                    diskBuilder.append("<auth username='" + _authUserName + "'>\n");
+                    diskBuilder.append("<secret type='ceph' uuid='" + _authSecretUUID + "'/>\n");
+                    diskBuilder.append("</auth>\n");
+                }
             }
             diskBuilder.append("<target dev='" + _diskLabel + "'");
             if (_bus != null) {
@@ -898,5 +961,4 @@ public class LibvirtVMDef {
 
         System.out.println(vm.toString());
     }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java b/agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java
index d0e43df..bb5834c 100644
--- a/agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java
+++ b/agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java
@@ -34,6 +34,22 @@ public class KVMPhysicalDisk {
         }
     }
 
+    public static String RBDStringBuilder(String monHost, int monPort,
+                            String authUserName, String authSecret, String image) {
+        String rbdOpts;
+
+        rbdOpts = "rbd:" + image;
+        rbdOpts += ":mon_host=" + monHost + "\\\\:" + monPort;
+        if (authUserName.isEmpty()) {
+            rbdOpts += ":auth_supported=none";
+        } else {
+            rbdOpts += ":auth_supported=cephx";
+            rbdOpts += ":id=" + authUserName;
+            rbdOpts += ":key=" + authSecret;
+        }
+        return rbdOpts;
+    }
+
     private PhysicalDiskFormat format;
     private long size;
     private long virtualSize;

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/storage/KVMStoragePool.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/storage/KVMStoragePool.java b/agent/src/com/cloud/agent/storage/KVMStoragePool.java
index 9961088..f1192ed 100644
--- a/agent/src/com/cloud/agent/storage/KVMStoragePool.java
+++ b/agent/src/com/cloud/agent/storage/KVMStoragePool.java
@@ -45,6 +45,16 @@ public interface KVMStoragePool {
 
     public String getLocalPath();
 
+    public String getSourceHost();
+
+    public String getSourceDir();
+
+    public int getSourcePort();
+
+    public String getAuthUserName();
+
+    public String getAuthSecret();
+
     public StoragePoolType getType();
 
     public boolean delete();

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java b/agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java
index 53373e5..a82318d 100644
--- a/agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java
+++ b/agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java
@@ -52,10 +52,10 @@ public class KVMStoragePoolManager {
         return this._storageAdaptor.getStoragePoolByUri(uri);
     }
 
-    public KVMStoragePool createStoragePool(String name, String host,
-            String path, StoragePoolType type) {
+    public KVMStoragePool createStoragePool(String name, String host, int port, String path,
+                                            String userInfo, StoragePoolType type) {
         KVMStoragePool pool = this._storageAdaptor.createStoragePool(name,
-                host, path, type);
+                                host, port, path, userInfo, type);
         if (type == StoragePoolType.NetworkFilesystem) {
             KVMHABase.NfsStoragePool nfspool = new KVMHABase.NfsStoragePool(
                     pool.getUuid(), host, path, pool.getLocalPath(),
@@ -73,11 +73,16 @@ public class KVMStoragePoolManager {
         return true;
     }
 
-    public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template,
-            String name, KVMStoragePool destPool) {
-        return this._storageAdaptor.createDiskFromTemplate(template, name,
-                KVMPhysicalDisk.PhysicalDiskFormat.QCOW2,
-                template.getSize(), destPool);
+    public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name,
+                                                    KVMStoragePool destPool) {
+        if (destPool.getType() == StoragePoolType.RBD) {
+            return this._storageAdaptor.createDiskFromTemplate(template, name,
+                    KVMPhysicalDisk.PhysicalDiskFormat.RAW, template.getSize(), destPool);
+        } else {
+            return this._storageAdaptor.createDiskFromTemplate(template, name,
+                    KVMPhysicalDisk.PhysicalDiskFormat.QCOW2,
+            template.getSize(), destPool);
+        }
     }
 
     public KVMPhysicalDisk createTemplateFromDisk(KVMPhysicalDisk disk,

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java b/agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java
index e1e050f..3ce018a 100644
--- a/agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java
+++ b/agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java
@@ -23,8 +23,10 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 import org.apache.log4j.Logger;
+import org.apache.commons.codec.binary.Base64;
 import org.libvirt.Connect;
 import org.libvirt.LibvirtException;
+import org.libvirt.Secret;
 import org.libvirt.StoragePool;
 import org.libvirt.StoragePoolInfo;
 import org.libvirt.StorageVol;
@@ -32,10 +34,13 @@ import org.libvirt.StoragePoolInfo.StoragePoolState;
 
 import com.cloud.agent.api.ManageSnapshotCommand;
 import com.cloud.agent.resource.computing.LibvirtConnection;
+import com.cloud.agent.resource.computing.LibvirtSecretDef;
+import com.cloud.agent.resource.computing.LibvirtSecretDef.usage;
 import com.cloud.agent.resource.computing.LibvirtStoragePoolDef;
 import com.cloud.agent.resource.computing.LibvirtStoragePoolXMLParser;
 import com.cloud.agent.resource.computing.LibvirtStorageVolumeDef;
 import com.cloud.agent.resource.computing.LibvirtStoragePoolDef.poolType;
+import com.cloud.agent.resource.computing.LibvirtStoragePoolDef.authType;
 import com.cloud.agent.resource.computing.LibvirtStorageVolumeDef.volFormat;
 import com.cloud.agent.resource.computing.LibvirtStorageVolumeXMLParser;
 import com.cloud.agent.storage.KVMPhysicalDisk.PhysicalDiskFormat;
@@ -143,7 +148,6 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
 
                 synchronized (getStoragePool(uuid)) {
                     sp = conn.storagePoolDefineXML(spd.toString(), 0);
-
                     if (sp == null) {
                         s_logger.debug("Failed to define storage pool");
                         return null;
@@ -270,6 +274,60 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
 
     }
 
+    private StoragePool createRBDStoragePool(Connect conn, String uuid,
+        String host, int port, String userInfo, String path) {
+
+        LibvirtStoragePoolDef spd;
+        StoragePool sp = null;
+
+        String[] userInfoTemp = userInfo.split(":");
+        if (userInfoTemp.length == 2) {
+            s_logger.debug("libvirt secret information found. id: " + userInfoTemp[0] + " secret: " + userInfoTemp[1]);
+            LibvirtSecretDef sd = new LibvirtSecretDef(usage.CEPH, uuid);
+
+            Secret s = null;
+
+            sd.setCephName(userInfoTemp[0]);
+
+            try {
+                s_logger.debug(sd.toString());
+                s = conn.secretDefineXML(sd.toString());
+                s.setValue(Base64.decodeBase64(userInfoTemp[1]));
+            } catch (LibvirtException e) {
+                s_logger.debug(e.toString());
+                if (s != null) {
+                    try {
+                        s.undefine();
+                        s.free();
+                    } catch (LibvirtException l) {
+                        s_logger.debug("Failed to define secret with: " + l.toString());
+                        }
+                    }
+            }
+            spd = new LibvirtStoragePoolDef(poolType.RBD, uuid, uuid, host, port, path, userInfoTemp[0], authType.CEPH, uuid);
+        } else {
+            spd = new LibvirtStoragePoolDef(poolType.RBD, uuid, uuid, host, port, path, "");
+        }
+
+        try {
+            s_logger.debug(spd.toString());
+            sp = conn.storagePoolDefineXML(spd.toString(), 0);
+            sp.create(0);
+            return sp;
+        } catch (LibvirtException e) {
+            s_logger.debug(e.toString());
+            if (sp != null) {
+                try {
+                    sp.undefine();
+                    sp.free();
+                } catch (LibvirtException l) {
+                    s_logger.debug("Failed to define RBD storage pool with: " + l.toString());
+                }
+            }
+            return null;
+        }
+    }
+
     public StorageVol copyVolume(StoragePool destPool,
             LibvirtStorageVolumeDef destVol, StorageVol srcVol, int timeout)
             throws LibvirtException {
@@ -422,11 +480,36 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
             if (spd.getPoolType() == LibvirtStoragePoolDef.poolType.NETFS
                     || spd.getPoolType() == LibvirtStoragePoolDef.poolType.DIR) {
                 type = StoragePoolType.Filesystem;
+            } else if (spd.getPoolType() == LibvirtStoragePoolDef.poolType.RBD) {
+                type = StoragePoolType.RBD;
             }
-            LibvirtStoragePool pool = new LibvirtStoragePool(uuid,
-                    storage.getName(), type, this, storage);
-            pool.setLocalPath(spd.getTargetPath());
-            getStats(pool);
+
+            LibvirtStoragePool pool = new LibvirtStoragePool(uuid, storage.getName(),
+                                                            type, this, storage);
+
+            if (pool.getType() != StoragePoolType.RBD) {
+                pool.setLocalPath(spd.getTargetPath());
+            } else {
+                pool.setLocalPath("");
+                pool.setSourceHost(spd.getSourceHost());
+                pool.setSourcePort(spd.getSourcePort());
+                pool.setSourceDir(spd.getSourceDir());
+                String authUsername = spd.getAuthUserName();
+                if (authUsername != null) {
+                    Secret secret = conn.secretLookupByUUIDString(spd.getSecretUUID());
+                    String secretValue = new String(Base64.encodeBase64(secret.getValue()));
+                    pool.setAuthUsername(authUsername);
+                    pool.setAuthSecret(secretValue);
+                }
+            }
+
+            if (pool.getType() == StoragePoolType.RBD) {
+                pool.setCapacity(storage.getInfo().capacity);
+                pool.setUsed(storage.getInfo().allocation);
+            } else {
+                getStats(pool);
+            }
+
             return pool;
         } catch (LibvirtException e) {
             throw new CloudRuntimeException(e.toString());
@@ -448,6 +531,8 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
             disk.setVirtualSize(vol.getInfo().capacity);
             if (voldef.getFormat() == null) {
                 disk.setFormat(pool.getDefaultFormat());
+            } else if (pool.getType() == StoragePoolType.RBD) {
+                disk.setFormat(KVMPhysicalDisk.PhysicalDiskFormat.RAW);
             } else if (voldef.getFormat() == LibvirtStorageVolumeDef.volFormat.QCOW2) {
                 disk.setFormat(KVMPhysicalDisk.PhysicalDiskFormat.QCOW2);
             } else if (voldef.getFormat() == LibvirtStorageVolumeDef.volFormat.RAW) {
@@ -461,8 +546,8 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
     }
 
     @Override
-    public KVMStoragePool createStoragePool(String name, String host,
-            String path, StoragePoolType type) {
+    public KVMStoragePool createStoragePool(String name, String host, int port,
+                                            String path, String userInfo, StoragePoolType type) {
         StoragePool sp = null;
         Connect conn = null;
         try {
@@ -487,6 +572,8 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
             } else if (type == StoragePoolType.SharedMountPoint
                     || type == StoragePoolType.Filesystem) {
                 sp = CreateSharedStoragePool(conn, name, host, path);
+            } else if (type == StoragePoolType.RBD) {
+                sp = createRBDStoragePool(conn, name, host, port, userInfo, path);
             }
         }
 
@@ -499,15 +586,23 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
             LibvirtStoragePoolDef spd = getStoragePoolDef(conn, sp);
             LibvirtStoragePool pool = new LibvirtStoragePool(name,
                     sp.getName(), type, this, sp);
-            pool.setLocalPath(spd.getTargetPath());
 
-            getStats(pool);
-            
+            if (pool.getType() != StoragePoolType.RBD) {
+                pool.setLocalPath(spd.getTargetPath());
+            } else {
+                pool.setLocalPath("");
+            }
+
+            if (pool.getType() == StoragePoolType.RBD) {
+                pool.setCapacity(sp.getInfo().capacity);
+                pool.setUsed(sp.getInfo().allocation);
+            } else {
+                getStats(pool);
+            }
             return pool;
         } catch (LibvirtException e) {
             throw new CloudRuntimeException(e.toString());
         }
-
     }
 
     @Override
@@ -520,6 +615,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
         }
 
         StoragePool sp = null;
+        Secret s = null;
 
         try {
             sp = conn.storagePoolLookupByUUIDString(uuid);
@@ -527,10 +623,23 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
             return true;
         }
 
+        /*
+         * Some storage pools, like RBD also have 'secret' information stored in libvirt
+         * Destroy them if they exist
+        */
+        try {
+            s = conn.secretLookupByUUIDString(uuid);
+        } catch (LibvirtException e) {
+        }
+
         try {
             sp.destroy();
             sp.undefine();
             sp.free();
+            if (s != null) {
+                s.undefine();
+                s.free();
+            }
             return true;
         } catch (LibvirtException e) {
             throw new CloudRuntimeException(e.toString());
@@ -543,6 +652,11 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
         LibvirtStoragePool libvirtPool = (LibvirtStoragePool) pool;
         StoragePool virtPool = libvirtPool.getPool();
         LibvirtStorageVolumeDef.volFormat libvirtformat = null;
+
+        if (pool.getType() == StoragePoolType.RBD) {
+            format = PhysicalDiskFormat.RAW;
+        }
+
         if (format == PhysicalDiskFormat.QCOW2) {
             libvirtformat = LibvirtStorageVolumeDef.volFormat.QCOW2;
         } else if (format == PhysicalDiskFormat.RAW) {
@@ -580,19 +694,57 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
 
     @Override
     public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template,
-            String name, PhysicalDiskFormat format, long size,
-            KVMStoragePool destPool) {
-        KVMPhysicalDisk disk = destPool.createPhysicalDisk(UUID.randomUUID()
-                .toString(), format, template.getVirtualSize());
+            String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool) {
+
+        String newUuid = UUID.randomUUID().toString();
+        KVMStoragePool srcPool = template.getPool();
+        KVMPhysicalDisk disk = null;
+
+        /*
+            With RBD you can't run qemu-img convert with an existing RBD image as destination
+            qemu-img will exit with the error that the destination already exists.
+            So for RBD we don't create the image, but let qemu-img do that for us.
+
+            We then create a KVMPhysicalDisk object that we can return
+        */
 
         if (format == PhysicalDiskFormat.QCOW2) {
+            disk = destPool.createPhysicalDisk(newUuid, format, template.getVirtualSize());
+
             Script.runSimpleBashScript("qemu-img create -f "
                     + template.getFormat() + " -b  " + template.getPath() + " "
                     + disk.getPath());
         } else if (format == PhysicalDiskFormat.RAW) {
-            Script.runSimpleBashScript("qemu-img convert -f "
-                    + template.getFormat() + " -O raw " + template.getPath()
-                    + " " + disk.getPath());
+            disk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + newUuid, newUuid, destPool);
+            disk.setFormat(format);
+            disk.setSize(template.getVirtualSize());
+            disk.setVirtualSize(disk.getSize());
+
+            if (srcPool.getType() != StoragePoolType.RBD) {
+                Script.runSimpleBashScript("qemu-img convert"
+                        + " -f " + template.getFormat()
+                        + " -O " + format
+                        + " " + template.getPath()
+                        + " " + KVMPhysicalDisk.RBDStringBuilder(destPool.getSourceHost(),
+                                                destPool.getSourcePort(),
+                                                destPool.getAuthUserName(),
+                                                destPool.getAuthSecret(),
+                                                disk.getPath()));
+            } else {
+                Script.runSimpleBashScript("qemu-img convert"
+                        + " -f " + template.getFormat()
+                        + " -O " + format
+                        + " " + KVMPhysicalDisk.RBDStringBuilder(srcPool.getSourceHost(),
+                                                srcPool.getSourcePort(),
+                                                srcPool.getAuthUserName(),
+                                                srcPool.getAuthSecret(),
+                                                template.getPath())
+                        + " " + KVMPhysicalDisk.RBDStringBuilder(destPool.getSourceHost(),
+                                                destPool.getSourcePort(),
+                                                destPool.getAuthUserName(),
+                                                destPool.getAuthSecret(),
+                                                disk.getPath()));
+            }
         }
         return disk;
     }
@@ -627,12 +779,42 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
             KVMStoragePool destPool) {
         KVMPhysicalDisk newDisk = destPool.createPhysicalDisk(name,
                 disk.getVirtualSize());
-        String sourcePath = disk.getPath();
+
+        KVMStoragePool srcPool = disk.getPool();
         String destPath = newDisk.getPath();
+        String sourcePath = disk.getPath();
+        PhysicalDiskFormat sourceFormat = disk.getFormat();
+        PhysicalDiskFormat destFormat = newDisk.getFormat();
+
+        if ((srcPool.getType() != StoragePoolType.RBD) && (destPool.getType() != StoragePoolType.RBD)) {
+            Script.runSimpleBashScript("qemu-img convert -f " + sourceFormat
+                + " -O " + destFormat
+                + " " + sourcePath
+                + " " + destPath);
+        } else if ((srcPool.getType() != StoragePoolType.RBD) && (destPool.getType() == StoragePoolType.RBD))  {
+            Script.runSimpleBashScript("qemu-img convert -f " + sourceFormat
+                    + " -O " + destFormat
+                    + " " + sourcePath
+                    + " " + KVMPhysicalDisk.RBDStringBuilder(srcPool.getSourceHost(),
+                                                srcPool.getSourcePort(),
+                                                srcPool.getAuthUserName(),
+                                                srcPool.getAuthSecret(),
+                                                destPath));
+        } else {
+            Script.runSimpleBashScript("qemu-img convert -f " + sourceFormat
+                    + " -O " + destFormat
+                    + " " + KVMPhysicalDisk.RBDStringBuilder(srcPool.getSourceHost(),
+                                                srcPool.getSourcePort(),
+                                                srcPool.getAuthUserName(),
+                                                srcPool.getAuthSecret(),
+                                                sourcePath)
+                    + " " + KVMPhysicalDisk.RBDStringBuilder(destPool.getSourceHost(),
+                                                destPool.getSourcePort(),
+                                                destPool.getAuthUserName(),
+                                                destPool.getAuthSecret(),
+                                                destPath));
+        }
 
-        Script.runSimpleBashScript("qemu-img convert -f " + disk.getFormat()
-                + " -O " + newDisk.getFormat() + " " + sourcePath + " "
-                + destPath);
         return newDisk;
     }
 
@@ -658,7 +840,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
             protocal = StoragePoolType.NetworkFilesystem;
         }
 
-        return createStoragePool(uuid, sourceHost, sourcePath, protocal);
+            return createStoragePool(uuid, sourceHost, 0, sourcePath, "", protocal);
     }
 
     @Override
@@ -699,5 +881,4 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
 
         return true;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/storage/LibvirtStoragePool.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/storage/LibvirtStoragePool.java b/agent/src/com/cloud/agent/storage/LibvirtStoragePool.java
index d638bb9..943b8b2 100644
--- a/agent/src/com/cloud/agent/storage/LibvirtStoragePool.java
+++ b/agent/src/com/cloud/agent/storage/LibvirtStoragePool.java
@@ -34,6 +34,11 @@ public class LibvirtStoragePool implements KVMStoragePool {
     protected StoragePoolType type;
     protected StorageAdaptor _storageAdaptor;
     protected StoragePool _pool;
+    protected String authUsername;
+    protected String authSecret;
+    protected String sourceHost;
+    protected int sourcePort;
+    protected String sourceDir;
 
     public LibvirtStoragePool(String uuid, String name, StoragePoolType type,
             StorageAdaptor adaptor, StoragePool pool) {
@@ -138,6 +143,51 @@ public class LibvirtStoragePool implements KVMStoragePool {
     }
 
     @Override
+    public String getAuthUserName() {
+        return this.authUsername;
+    }
+
+    public void setAuthUsername(String authUsername) {
+        this.authUsername = authUsername;
+    }
+
+    @Override
+    public String getAuthSecret() {
+        return this.authSecret;
+    }
+
+    public void setAuthSecret(String authSecret) {
+        this.authSecret = authSecret;
+    }
+
+    @Override
+    public String getSourceHost() {
+        return this.sourceHost;
+    }
+
+    public void setSourceHost(String host) {
+        this.sourceHost = host;
+    }
+
+    @Override
+    public int getSourcePort() {
+        return this.sourcePort;
+    }
+
+    public void setSourcePort(int port) {
+        this.sourcePort = port;
+    }
+
+    @Override
+    public String getSourceDir() {
+        return this.sourceDir;
+    }
+
+    public void setSourceDir(String dir) {
+        this.sourceDir = dir;
+    }
+
+    @Override
     public StoragePoolType getType() {
         return this.type;
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/agent/src/com/cloud/agent/storage/StorageAdaptor.java
----------------------------------------------------------------------
diff --git a/agent/src/com/cloud/agent/storage/StorageAdaptor.java b/agent/src/com/cloud/agent/storage/StorageAdaptor.java
index 9cc5d14..8238677 100644
--- a/agent/src/com/cloud/agent/storage/StorageAdaptor.java
+++ b/agent/src/com/cloud/agent/storage/StorageAdaptor.java
@@ -30,8 +30,8 @@ public interface StorageAdaptor {
     public KVMPhysicalDisk getPhysicalDisk(String volumeUuid,
             KVMStoragePool pool);
 
-    public KVMStoragePool createStoragePool(String name, String host,
-            String path, StoragePoolType type);
+    public KVMStoragePool createStoragePool(String name, String host, int port,
+            String path, String userInfo, StoragePoolType type);
 
     public boolean deleteStoragePool(String uuid);
 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/api/src/com/cloud/agent/api/to/StorageFilerTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/StorageFilerTO.java b/api/src/com/cloud/agent/api/to/StorageFilerTO.java
index c0be269..26344da 100644
--- a/api/src/com/cloud/agent/api/to/StorageFilerTO.java
+++ b/api/src/com/cloud/agent/api/to/StorageFilerTO.java
@@ -24,6 +24,7 @@ public class StorageFilerTO {
     String uuid;
     String host;
     String path;
+    String userInfo;
     int port;
     StoragePoolType type;
     
@@ -34,6 +35,7 @@ public class StorageFilerTO {
         this.path = pool.getPath();
         this.type = pool.getPoolType();
         this.uuid = pool.getUuid();
+        this.userInfo = pool.getUserInfo();
     }
 
     public long getId() {
@@ -52,6 +54,10 @@ public class StorageFilerTO {
         return path;
     }
 
+    public String getUserInfo() {
+        return userInfo;
+    }
+
     public int getPort() {
         return port;
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/api/src/com/cloud/storage/Storage.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java
index 856f79d..d6bd04e 100755
--- a/api/src/com/cloud/storage/Storage.java
+++ b/api/src/com/cloud/storage/Storage.java
@@ -96,6 +96,7 @@ public class Storage {
         Iscsi(true), // for e.g., ZFS Comstar
         ISO(false), // for iso image
         LVM(false), // XenServer local LVM SR
+        RBD(true),
         SharedMountPoint(true),
         VMFS(true), // VMware VMFS storage
         PreSetup(true), // for XenServer, Storage Pool is set up by customers.

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/api/src/com/cloud/storage/StoragePool.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/StoragePool.java b/api/src/com/cloud/storage/StoragePool.java
index 5828986..ff38c54 100644
--- a/api/src/com/cloud/storage/StoragePool.java
+++ b/api/src/com/cloud/storage/StoragePool.java
@@ -86,6 +86,11 @@ public interface StoragePool {
     String getPath();
 
     /**
+     * @return the user information / credentials for the storage host
+     */
+    String getUserInfo();
+
+    /**
      * @return the storage pool represents a shared storage resource
      */
     boolean isShared();

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/build/package.xml
----------------------------------------------------------------------
diff --git a/build/package.xml b/build/package.xml
index 2b5a74b..fdf3346 100755
--- a/build/package.xml
+++ b/build/package.xml
@@ -82,7 +82,7 @@
         <include name="cloud-commons-collections-3.2.1.jar" />
         <include name="cloud-commons-codec-1.4.jar" />
         <include name="cloud-commons-pool-1.4.jar" />
-        <include name="cloud-libvirt-0.4.5.jar" />
+        <include name="cloud-libvirt-0.4.7.jar" />
         <include name="cloud-jna.jar" />
         <include name="cloud-cglib.jar" />
         <include name="jetty-6.1.26.jar" />

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/core/src/com/cloud/storage/StoragePoolVO.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/storage/StoragePoolVO.java b/core/src/com/cloud/storage/StoragePoolVO.java
index 526fecf..9e41cca 100644
--- a/core/src/com/cloud/storage/StoragePoolVO.java
+++ b/core/src/com/cloud/storage/StoragePoolVO.java
@@ -153,6 +153,9 @@ public class StoragePoolVO implements StoragePool, Identity {
     @Column(name="port")
     private int port;
 
+    @Column(name="user_info")
+    private String userInfo;
+
     @Column(name="cluster_id")
     private Long clusterId;
     
@@ -175,6 +178,11 @@ public class StoragePoolVO implements StoragePool, Identity {
     public String getPath() {
         return path;
     }
+
+    @Override
+    public String getUserInfo() {
+        return userInfo;
+    }
     
     public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type,
             long dataCenterId, Long podId, long availableBytes, long capacityBytes, String hostAddress, int port, String hostPath) {
@@ -204,6 +212,16 @@ public class StoragePoolVO implements StoragePool, Identity {
         this.setStatus(StoragePoolStatus.Up);
         this.uuid = UUID.randomUUID().toString();
     }
+
+    public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path, String userInfo) {
+        this.poolType = type;
+        this.hostAddress = hostAddress;
+        this.port = port;
+        this.path = path;
+        this.userInfo = userInfo;
+        this.setStatus(StoragePoolStatus.Up);
+        this.uuid = UUID.randomUUID().toString();
+    }
     
     public void setStatus(StoragePoolStatus status)
     {
@@ -229,6 +247,10 @@ public class StoragePoolVO implements StoragePool, Identity {
     public void setPath(String path) {
     	this.path = path;
     }
+
+    public void setUserInfo(String userInfo) {
+        this.userInfo = userInfo;
+    }
     
     @Override
     public int getPort() {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/debian/cloud-agent-deps.install
----------------------------------------------------------------------
diff --git a/debian/cloud-agent-deps.install b/debian/cloud-agent-deps.install
index 57122ac..6eb979c 100644
--- a/debian/cloud-agent-deps.install
+++ b/debian/cloud-agent-deps.install
@@ -1,3 +1,3 @@
 /usr/share/java/cloud-google-gson-1.7.1.jar
-/usr/share/java/cloud-libvirt-0.4.5.jar
+/usr/share/java/cloud-libvirt-0.4.7.jar
 /usr/share/java/cloud-log4j-extras.jar

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/deps/.classpath
----------------------------------------------------------------------
diff --git a/deps/.classpath b/deps/.classpath
index b9eb504..264310e 100755
--- a/deps/.classpath
+++ b/deps/.classpath
@@ -15,7 +15,7 @@
 	<classpathentry exported="true" kind="lib" path="cloud-jasypt-1.8.jar"/>
 	<classpathentry exported="true" kind="lib" path="cloud-jsch-0.1.42.jar"/>
 	<classpathentry exported="true" kind="lib" path="cloud-jstl-1.2.jar"/>
-	<classpathentry exported="true" kind="lib" path="cloud-libvirt-0.4.5.jar"/>
+	<classpathentry exported="true" kind="lib" path="cloud-libvirt-0.4.7.jar"/>
 	<classpathentry exported="true" kind="lib" path="cloud-log4j.jar" sourcepath="/home/dev/thirdparty/apache-log4j-1.2.16/src/main/java"/>
 	<classpathentry exported="true" kind="lib" path="cloud-mysql-connector-java-5.1.7-bin.jar"/>
 	<classpathentry exported="true" kind="lib" path="cloud-servlet-api.jar"/>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/deps/cloud-libvirt-0.4.5.jar
----------------------------------------------------------------------
diff --git a/deps/cloud-libvirt-0.4.5.jar b/deps/cloud-libvirt-0.4.5.jar
deleted file mode 100644
index 9d0a1df..0000000
Binary files a/deps/cloud-libvirt-0.4.5.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/deps/cloud-libvirt-0.4.7.jar
----------------------------------------------------------------------
diff --git a/deps/cloud-libvirt-0.4.7.jar b/deps/cloud-libvirt-0.4.7.jar
new file mode 100644
index 0000000..302f7b3
Binary files /dev/null and b/deps/cloud-libvirt-0.4.7.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/server/src/com/cloud/storage/StorageManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java
index f8ad65c..b178c7c 100755
--- a/server/src/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/com/cloud/storage/StorageManagerImpl.java
@@ -1248,10 +1248,10 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
                 if (uriPath == null) {
                     throw new InvalidParameterValueException("host or path is null, should be sharedmountpoint://localhost/path");
                 }
-            } else if (uri.getScheme().equalsIgnoreCase("clvm")) {
+            }  else if (uri.getScheme().equalsIgnoreCase("rbd")) {
                 String uriPath = uri.getPath();
                 if (uriPath == null) {
-                    throw new InvalidParameterValueException("host or path is null, should be clvm://localhost/path");
+                    throw new InvalidParameterValueException("host or path is null, should be rbd://hostname/pool");
                 }
             }
         } catch (URISyntaxException e) {
@@ -1274,6 +1274,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
         String scheme = uri.getScheme();
         String storageHost = uri.getHost();
         String hostPath = uri.getPath();
+        String userInfo = uri.getUserInfo();
         int port = uri.getPort();
         StoragePoolVO pool = null;
         if (s_logger.isDebugEnabled()) {
@@ -1294,6 +1295,11 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
             pool = new StoragePoolVO(StoragePoolType.Filesystem, "localhost", 0, hostPath);
         } else if (scheme.equalsIgnoreCase("sharedMountPoint")) {
             pool = new StoragePoolVO(StoragePoolType.SharedMountPoint, storageHost, 0, hostPath);
+        } else if (scheme.equalsIgnoreCase("rbd")) {
+            if (port == -1) {
+                port = 6789;
+            }
+            pool = new StoragePoolVO(StoragePoolType.RBD, storageHost, port, hostPath.replaceFirst("/", ""), userInfo);
         } else if (scheme.equalsIgnoreCase("PreSetup")) {
             pool = new StoragePoolVO(StoragePoolType.PreSetup, storageHost, 0, hostPath);
         } else if (scheme.equalsIgnoreCase("iscsi")) {
@@ -1592,7 +1598,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
         s_logger.debug("creating pool " + pool.getName() + " on  host " + hostId);
         if (pool.getPoolType() != StoragePoolType.NetworkFilesystem && pool.getPoolType() != StoragePoolType.Filesystem && pool.getPoolType() != StoragePoolType.IscsiLUN
                 && pool.getPoolType() != StoragePoolType.Iscsi && pool.getPoolType() != StoragePoolType.VMFS && pool.getPoolType() != StoragePoolType.SharedMountPoint
-                && pool.getPoolType() != StoragePoolType.PreSetup && pool.getPoolType() != StoragePoolType.OCFS2) {
+                && pool.getPoolType() != StoragePoolType.PreSetup && pool.getPoolType() != StoragePoolType.OCFS2 && pool.getPoolType() != StoragePoolType.RBD) {
             s_logger.warn(" Doesn't support storage pool type " + pool.getPoolType());
             return false;
         }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java
index 02ab3c1..957d479 100644
--- a/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java
+++ b/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java
@@ -27,18 +27,25 @@ import org.apache.log4j.Logger;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.deploy.DeploymentPlanner.ExcludeList;
 import com.cloud.server.StatsCollector;
+import com.cloud.storage.DiskOfferingVO;
+import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.StoragePoolVO;
 import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.user.Account;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.utils.component.Inject;
 
 @Local(value=StoragePoolAllocator.class)
 public class FirstFitStoragePoolAllocator extends AbstractStoragePoolAllocator {
     private static final Logger s_logger = Logger.getLogger(FirstFitStoragePoolAllocator.class);
     protected String _allocationAlgorithm = "random";
+
+    @Inject
+    DiskOfferingDao _diskOfferingDao;
     
     @Override
     public boolean allocatorIsCorrectType(DiskProfile dskCh) {
@@ -93,10 +100,16 @@ public class FirstFitStoragePoolAllocator extends AbstractStoragePoolAllocator {
             s_logger.debug("FirstFitStoragePoolAllocator has " + pools.size() + " pools to check for allocation");
         }
     	
+        DiskOfferingVO diskOffering = _diskOfferingDao.findById(dskCh.getDiskOfferingId());
         for (StoragePoolVO pool: pools) {
         	if(suitablePools.size() == returnUpTo){
         		break;
         	}
+            if (diskOffering.getSystemUse() && pool.getPoolType() == StoragePoolType.RBD) {
+                s_logger.debug("Skipping RBD pool " + pool.getName() + " as a suitable pool. RBD is not supported for System VM's");
+                continue;
+            }
+
         	if (checkPool(avoid, pool, dskCh, template, null, sc, plan)) {
         		suitablePools.add(pool);
         	}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index b97a7d7..db88aa2 100755
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -74,6 +74,7 @@ import com.cloud.storage.SnapshotPolicyVO;
 import com.cloud.storage.SnapshotScheduleVO;
 import com.cloud.storage.SnapshotVO;
 import com.cloud.storage.Storage;
+import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.StoragePoolVO;
@@ -287,6 +288,13 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
             }
         }
         StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId());
+
+        // RBD volumes do not support snapshotting in the way CloudStack does it.
+        // For now we leave the snapshot feature disabled for RBD volumes
+        if (srcPool.getPoolType() == StoragePoolType.RBD) {
+            throw new CloudRuntimeException("RBD volumes do not support snapshotting");
+        }
+
         ManageSnapshotCommand cmd = new ManageSnapshotCommand(snapshotId, volume.getPath(), srcPool, preSnapshotPath, snapshot.getName(), vmName);
       
         ManageSnapshotAnswer answer = (ManageSnapshotAnswer) sendToPool(volume, cmd);

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/setup/db/create-schema.sql
----------------------------------------------------------------------
diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql
index afcee3f..6cb6bcf 100755
--- a/setup/db/create-schema.sql
+++ b/setup/db/create-schema.sql
@@ -1474,6 +1474,7 @@ CREATE TABLE  `cloud`.`storage_pool` (
   `available_bytes` bigint unsigned,
   `capacity_bytes` bigint unsigned,
   `host_address` varchar(255) NOT NULL COMMENT 'FQDN or IP of storage server',
+  `user_info` varchar(255) NULL COMMENT 'Authorization information for the storage pool. Used by network filesystems',
   `path` varchar(255) NOT NULL COMMENT 'Filesystem path that is shared',
   `created` datetime COMMENT 'date the pool created',
   `removed` datetime COMMENT 'date removed if not null',

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/ui/index.jsp
----------------------------------------------------------------------
diff --git a/ui/index.jsp b/ui/index.jsp
index fb3327f..69c2dad 100644
--- a/ui/index.jsp
+++ b/ui/index.jsp
@@ -2032,6 +2032,7 @@ dictionary = {
 'label.SR.name ': '<fmt:message key="label.SR.name " />',
 'label.SharedMountPoint': '<fmt:message key="label.SharedMountPoint" />',
 'label.clvm': '<fmt:message key="label.clvm" />',
+'label.rbd': '<fmt:message key="label.rbd" />',
 'label.volgroup': '<fmt:message key="label.volgroup" />',
 'label.VMFS.datastore': '<fmt:message key="label.VMFS.datastore" />',
 'label.network.device': '<fmt:message key="label.network.device" />',

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/ui/scripts/sharedFunctions.js
----------------------------------------------------------------------
diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js
index cf437af..37a40f8 100644
--- a/ui/scripts/sharedFunctions.js
+++ b/ui/scripts/sharedFunctions.js
@@ -475,6 +475,24 @@ function SharedMountPointURL(server, path) {
 	return url;
 }
 
+function rbdURL(monitor, pool, id, secret) {
+	var url;
+
+	if (id != null && secret != null) {
+		monitor = id + ":" + secret + "@" + monitor;
+	}
+
+	if(pool.substring(0,1) != "/")
+		pool = "/" + pool;
+
+	if(monitor.indexOf("://")==-1)
+		url = "rbd://" + monitor + pool;
+	else
+		url = monitor + pool;
+
+	return url;
+}
+
 function clvmURL(vgname) {
 	var url;
 	if(vgname.indexOf("://")==-1)

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/2108dc5d/ui/scripts/system.js
----------------------------------------------------------------------
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 6d3b765..94750da 100644
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -7494,6 +7494,7 @@
                         var items = [];
                         items.push({id: "nfs", description: "nfs"});
                         items.push({id: "SharedMountPoint", description: "SharedMountPoint"});
+                        items.push({id: "rbd", description: "RBD"});
                         args.response.success({data: items});
                       }
                       else if(selectedClusterObj.hypervisortype == "XenServer") {
@@ -7677,6 +7678,27 @@
                           $form.find('.form-item[rel=vCenterDataCenter]').hide();
                           $form.find('.form-item[rel=vCenterDataStore]').hide();
                         }
+                        else if(protocol == "rbd") {
+                          $form.find('.form-item[rel=rbdmonitor]').css('display', 'inline-block');
+                          $form.find('.form-item[rel=rbdmonitor]').find(".name").find("label").text("RADOS Monitor:");
+
+                          $form.find('.form-item[rel=rbdpool]').css('display', 'inline-block');
+                          $form.find('.form-item[rel=rbdpool]').find(".name").find("label").text("RADOS Pool:");
+
+                          $form.find('.form-item[rel=rbdid]').css('display', 'inline-block');
+                          $form.find('.form-item[rel=rbdid]').find(".name").find("label").text("RADOS User:");
+
+                          $form.find('.form-item[rel=rbdsecret]').css('display', 'inline-block');
+                          $form.find('.form-item[rel=rbdsecret]').find(".name").find("label").text("RADOS Secret:");
+
+                          $form.find('.form-item[rel=server]').hide();
+                          $form.find('.form-item[rel=iqn]').hide();
+                          $form.find('.form-item[rel=lun]').hide();
+                          $form.find('.form-item[rel=volumegroup]').hide();
+                          $form.find('.form-item[rel=path]').hide();
+                          $form.find('.form-item[rel=vCenterDataCenter]').hide();
+                          $form.find('.form-item[rel=vCenterDataStore]').hide();
+                        }
                         else {
                           //$dialogAddPool.find("#add_pool_server_container").show();
                           $form.find('.form-item[rel=server]').css('display', 'inline-block');
@@ -7744,6 +7766,28 @@
                     validation: { required: true },
                     isHidden: true
                   },
+ 
+                  // RBD
+                  rbdmonitor: {
+                    label: 'label.rbd.monitor',
+                    validation: { required: true },
+                    isHidden: true
+                  },
+                  rbdpool: {
+                    label: 'label.rbd.pool',
+                    validation: { required: true },
+                    isHidden: true
+                  },
+                   rbdid: {
+                    label: 'label.rbd.id',
+                    validation: { required: false },
+                    isHidden: true
+                  },
+                   rbdsecret: {
+                    label: 'label.rbd.secret',
+                    validation: { required: false },
+                    isHidden: true
+                  },
 
                   //always appear (begin)
                   storageTags: {
@@ -7803,6 +7847,14 @@
                     vg = "/" + vg;
 									url = clvmURL(vg);
 								}
+                else if (args.data.protocol == "rbd") {
+                  var rbdmonitor = args.data.rbdmonitor;
+                  var rbdpool = args.data.rbdpool;
+                  var rbdid = args.data.rbdid;
+                  var rbdsecret = args.data.rbdsecret;
+
+                  url = rbdURL(rbdmonitor, rbdpool, rbdid, rbdsecret);
+                }
                 else if (args.data.protocol == "vmfs") {
                   //var path = trim($thisDialog.find("#add_pool_vmfs_dc").val());
                   var path = args.data.vCenterDataCenter;


Mime
View raw message