mirror of https://github.com/apache/cloudstack.git
new managed nfs storage adapter
Signed-off-by: Mike Tutkowski <mike.tutkowski@solidfire.com>
This commit is contained in:
parent
7716989344
commit
09a62b8389
|
|
@ -35,6 +35,7 @@ public class DiskTO {
|
|||
public static final String MOUNT_POINT = "mountpoint";
|
||||
public static final String PROTOCOL_TYPE = "protocoltype";
|
||||
public static final String PATH = "path";
|
||||
public static final String UUID = "uuid";
|
||||
|
||||
private DataTO data;
|
||||
private Long diskSeq;
|
||||
|
|
|
|||
|
|
@ -131,7 +131,8 @@ public class Storage {
|
|||
EXT(false), // XenServer local EXT SR
|
||||
OCFS2(true),
|
||||
SMB(true),
|
||||
Gluster(true);
|
||||
Gluster(true),
|
||||
ManagedNFS(true);
|
||||
|
||||
boolean shared;
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ public class KVMStoragePoolManager {
|
|||
// add other storage adaptors here
|
||||
// this._storageMapper.put("newadaptor", new NewStorageAdaptor(storagelayer));
|
||||
this._storageMapper.put(StoragePoolType.Iscsi.toString(), new IscsiAdmStorageAdaptor());
|
||||
this._storageMapper.put(StoragePoolType.ManagedNFS.toString(), new ManagedNfsStorageAdaptor(storagelayer));
|
||||
}
|
||||
|
||||
public boolean connectPhysicalDisk(StoragePoolType type, String poolUuid, String volPath, Map<String, String> details) {
|
||||
|
|
|
|||
|
|
@ -256,6 +256,11 @@ public class LibvirtStoragePool implements KVMStoragePool {
|
|||
return this._pool;
|
||||
}
|
||||
|
||||
public void setPool(StoragePool pool) {
|
||||
this._pool = pool;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,330 @@
|
|||
// 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.kvm.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.libvirt.Connect;
|
||||
import org.libvirt.LibvirtException;
|
||||
import org.libvirt.StoragePool;
|
||||
import org.libvirt.StoragePoolInfo;
|
||||
import org.libvirt.StorageVol;
|
||||
|
||||
import com.cloud.agent.api.to.DiskTO;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef.poolType;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtStorageVolumeDef;
|
||||
import com.cloud.hypervisor.kvm.resource.LibvirtStorageVolumeXMLParser;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.StorageLayer;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.script.Script;
|
||||
|
||||
public class ManagedNfsStorageAdaptor implements StorageAdaptor {
|
||||
private static final Logger s_logger = Logger.getLogger(ManagedNfsStorageAdaptor.class);
|
||||
private String _mountPoint = "/mnt";
|
||||
private StorageLayer _storageLayer;
|
||||
|
||||
private static final Map<String, KVMStoragePool> MapStorageUuidToStoragePool = new HashMap<String, KVMStoragePool>();
|
||||
|
||||
public ManagedNfsStorageAdaptor(StorageLayer storagelayer) {
|
||||
_storageLayer = storagelayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType) {
|
||||
|
||||
LibvirtStoragePool storagePool = new LibvirtStoragePool(uuid, path, StoragePoolType.ManagedNFS, this, null);
|
||||
storagePool.setSourceHost(host);
|
||||
storagePool.setSourcePort(port);
|
||||
MapStorageUuidToStoragePool.put(uuid, storagePool);
|
||||
|
||||
return storagePool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMStoragePool getStoragePool(String uuid) {
|
||||
return getStoragePool(uuid, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMStoragePool getStoragePool(String uuid, boolean refreshInfo) {
|
||||
return MapStorageUuidToStoragePool.get(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteStoragePool(String uuid) {
|
||||
return MapStorageUuidToStoragePool.remove(uuid) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteStoragePool(KVMStoragePool pool) {
|
||||
return deleteStoragePool(pool.getUuid());
|
||||
}
|
||||
|
||||
public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, KVMStoragePool pool, PhysicalDiskFormat format, long size) {
|
||||
throw new UnsupportedOperationException("Creating a physical disk is not supported.");
|
||||
}
|
||||
|
||||
/*
|
||||
* creates a nfs storage pool using libvirt
|
||||
*/
|
||||
@Override
|
||||
public boolean connectPhysicalDisk(String volumeUuid, KVMStoragePool pool, Map<String, String> details) {
|
||||
|
||||
StoragePool sp = null;
|
||||
Connect conn = null;
|
||||
String targetPath = null;
|
||||
LibvirtStoragePoolDef spd = null;
|
||||
try {
|
||||
conn = LibvirtConnection.getConnection();
|
||||
|
||||
targetPath = "/mnt" + volumeUuid;
|
||||
spd = new LibvirtStoragePoolDef(poolType.NETFS, volumeUuid, details.get(DiskTO.UUID), pool.getSourceHost(), details.get(DiskTO.MOUNT_POINT), targetPath);
|
||||
_storageLayer.mkdir(targetPath);
|
||||
|
||||
s_logger.debug(spd.toString());
|
||||
sp = conn.storagePoolCreateXML(spd.toString(), 0);
|
||||
|
||||
if (sp == null) {
|
||||
throw new CloudRuntimeException("Failed to create storage pool:" + volumeUuid);
|
||||
}
|
||||
|
||||
try {
|
||||
if (sp.isActive() == 0) {
|
||||
// s_logger.debug("attempting to activate pool " + name);
|
||||
sp.create(0);
|
||||
}
|
||||
// now add the storage pool
|
||||
LibvirtStoragePool storagePool = (LibvirtStoragePool) getStoragePool(pool.getUuid());
|
||||
storagePool.setPool(sp);
|
||||
|
||||
return true;
|
||||
} catch (LibvirtException e) {
|
||||
String error = e.toString();
|
||||
if (error.contains("Storage source conflict")) {
|
||||
throw new CloudRuntimeException("A pool matching this location already exists in libvirt, " + " but has a different UUID/Name. Cannot create new pool without first "
|
||||
+ " removing it. Check for inactive pools via 'virsh pool-list --all'. " + error);
|
||||
} else {
|
||||
throw new CloudRuntimeException(error);
|
||||
}
|
||||
}
|
||||
} catch (LibvirtException e) {
|
||||
s_logger.error(e.toString());
|
||||
// if error is that pool is mounted, try to handle it
|
||||
if (e.toString().contains("already mounted")) {
|
||||
s_logger.error("Attempting to unmount old mount libvirt is unaware of at " + targetPath);
|
||||
String result = Script.runSimpleBashScript("umount -l " + targetPath);
|
||||
if (result == null) {
|
||||
s_logger.error("Succeeded in unmounting " + targetPath);
|
||||
try {
|
||||
sp = conn.storagePoolCreateXML(spd.toString(), 0);
|
||||
s_logger.error("Succeeded in redefining storage");
|
||||
return true;
|
||||
} catch (LibvirtException l) {
|
||||
s_logger.error("Target was already mounted, unmounted it but failed to redefine storage:" + l);
|
||||
}
|
||||
} else {
|
||||
s_logger.error("Failed in unmounting and redefining storage");
|
||||
}
|
||||
} else {
|
||||
s_logger.error("Internal error occurred when attempting to mount:" + e.getMessage());
|
||||
// stacktrace for agent.log
|
||||
e.printStackTrace();
|
||||
throw new CloudRuntimeException(e.toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* creates a disk based on the created nfs storage pool using libvirt
|
||||
*/
|
||||
@Override
|
||||
public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
|
||||
// now create the volume upon the given storage pool in kvm
|
||||
Connect conn;
|
||||
StoragePool virtPool = null;
|
||||
try {
|
||||
conn = LibvirtConnection.getConnection();
|
||||
virtPool = conn.storagePoolLookupByName("/" + volumeUuid);
|
||||
} catch (LibvirtException e1) {
|
||||
throw new CloudRuntimeException(e1.toString());
|
||||
}
|
||||
|
||||
LibvirtStorageVolumeDef.volFormat libvirtformat = null;
|
||||
String volPath = null;
|
||||
String volName = null;
|
||||
long volAllocation = 0;
|
||||
long volCapacity = 0;
|
||||
// check whether the volume is present on the given pool
|
||||
StorageVol vol = getVolume(virtPool, volumeUuid);
|
||||
try {
|
||||
if (vol == null) {
|
||||
|
||||
libvirtformat = LibvirtStorageVolumeDef.volFormat.QCOW2;
|
||||
|
||||
StoragePoolInfo poolinfo = virtPool.getInfo();
|
||||
volCapacity = poolinfo.available;
|
||||
|
||||
LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(volumeUuid, volCapacity, libvirtformat, null, null);
|
||||
s_logger.debug(volDef.toString());
|
||||
|
||||
vol = virtPool.storageVolCreateXML(volDef.toString(), 0);
|
||||
volPath = vol.getPath();
|
||||
volName = vol.getName();
|
||||
volAllocation = vol.getInfo().allocation;
|
||||
volCapacity = vol.getInfo().capacity;
|
||||
|
||||
}
|
||||
|
||||
KVMPhysicalDisk disk = new KVMPhysicalDisk(vol.getPath(), volumeUuid, pool);
|
||||
disk.setFormat(PhysicalDiskFormat.QCOW2);
|
||||
disk.setSize(vol.getInfo().allocation);
|
||||
disk.setVirtualSize(vol.getInfo().capacity);
|
||||
return disk;
|
||||
|
||||
} catch (LibvirtException e) {
|
||||
throw new CloudRuntimeException(e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public LibvirtStorageVolumeDef getStorageVolumeDef(Connect conn, StorageVol vol) throws LibvirtException {
|
||||
String volDefXML = vol.getXMLDesc(0);
|
||||
LibvirtStorageVolumeXMLParser parser = new LibvirtStorageVolumeXMLParser();
|
||||
return parser.parseStorageVolumeXML(volDefXML);
|
||||
}
|
||||
|
||||
public StorageVol getVolume(StoragePool pool, String volName) {
|
||||
StorageVol vol = null;
|
||||
|
||||
try {
|
||||
vol = pool.storageVolLookupByName(volName);
|
||||
} catch (LibvirtException e) {
|
||||
s_logger.debug("Can't find volume: " + e.toString());
|
||||
}
|
||||
if (vol == null) {
|
||||
try {
|
||||
refreshPool(pool);
|
||||
} catch (LibvirtException e) {
|
||||
s_logger.debug("failed to refresh pool: " + e.toString());
|
||||
}
|
||||
s_logger.debug("no volume is present on the pool, creating a new one");
|
||||
}
|
||||
return vol;
|
||||
}
|
||||
|
||||
private void refreshPool(StoragePool pool) throws LibvirtException {
|
||||
pool.refresh(0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* disconnect the disk by destroying the sp pointer
|
||||
*/
|
||||
public boolean disconnectPhysicalDisk(KVMStoragePool pool, String mountpoint) throws LibvirtException {
|
||||
|
||||
LibvirtStoragePool libvirtPool = (LibvirtStoragePool) pool;
|
||||
StoragePool sp = libvirtPool.getPool();
|
||||
// destroy the pool
|
||||
sp.destroy();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean disconnectPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
|
||||
try {
|
||||
return disconnectPhysicalDisk(pool, volumeUuid);
|
||||
} catch (LibvirtException e) {
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean disconnectPhysicalDiskByPath(String localPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean deletePhysicalDisk(String volumeUuid, KVMStoragePool pool) {
|
||||
throw new UnsupportedOperationException("Deleting a physical disk is not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KVMPhysicalDisk> listPhysicalDisks(String storagePoolUuid, KVMStoragePool pool) {
|
||||
throw new UnsupportedOperationException("Listing disks is not supported for this configuration.");
|
||||
}
|
||||
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool, int timeout) {
|
||||
throw new UnsupportedOperationException("Creating a disk from a template is not yet supported for this configuration.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk createTemplateFromDisk(KVMPhysicalDisk disk, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool) {
|
||||
throw new UnsupportedOperationException("Creating a template from a disk is not yet supported for this configuration.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMStoragePool destPool, int timeout) {
|
||||
throw new UnsupportedOperationException("Copying a disk is not supported in this configuration.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk createDiskFromSnapshot(KVMPhysicalDisk snapshot, String snapshotName, String name, KVMStoragePool destPool) {
|
||||
throw new UnsupportedOperationException("Creating a disk from a snapshot is not supported in this configuration.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean refresh(KVMStoragePool pool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createFolder(String uuid, String path) {
|
||||
String mountPoint = _mountPoint + File.separator + uuid;
|
||||
File f = new File(mountPoint + File.separator + path);
|
||||
if (!f.exists()) {
|
||||
f.mkdirs();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, PhysicalDiskFormat format, ProvisioningType provisioningType, long size) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool, ImageFormat format) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, PhysicalDiskFormat format, ProvisioningType provisioningType, long size, KVMStoragePool destPool, int timeout) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue