Java tutorial
/******************************************************************************* *Copyright (c) 2009-2014 Eucalyptus Systems, Inc. * * This program 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, only version 3 of the License. * * * This file 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/>. * * Please contact Eucalyptus Systems, Inc., 130 Castilian * Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/> * if you need additional information or have any questions. * * This file may incorporate work covered under the following copyright and * permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF * THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE * LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS * SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA * BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN * THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT * OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR * WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH * ANY SUCH LICENSES OR RIGHTS. *******************************************************************************/ /* * * Author: Neil Soman neil@eucalyptus.com */ package com.eucalyptus.blockstorage; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; import java.security.PublicKey; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.crypto.Cipher; import javax.persistence.EntityNotFoundException; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.bouncycastle.util.encoders.Base64; import com.eucalyptus.auth.util.Hashes; import com.eucalyptus.blockstorage.StorageManagers.StorageManagerProperty; import com.eucalyptus.blockstorage.entities.DASInfo; import com.eucalyptus.blockstorage.entities.DirectStorageInfo; import com.eucalyptus.blockstorage.entities.ISCSIVolumeInfo; import com.eucalyptus.blockstorage.entities.LVMVolumeInfo; import com.eucalyptus.blockstorage.entities.StorageInfo; import com.eucalyptus.blockstorage.util.StorageProperties; import com.eucalyptus.component.Partitions; import com.eucalyptus.component.ServiceConfiguration; import com.eucalyptus.component.ServiceConfigurations; import com.eucalyptus.component.id.ClusterController; import com.eucalyptus.configurable.ConfigurableClass; import com.eucalyptus.configurable.ConfigurableProperty; import com.eucalyptus.configurable.ConfigurablePropertyException; import com.eucalyptus.configurable.PropertyDirectory; import com.eucalyptus.crypto.Ciphers; import com.eucalyptus.entities.Entities; import com.eucalyptus.entities.EntityWrapper; import com.eucalyptus.objectstorage.util.ObjectStorageProperties; import com.eucalyptus.storage.common.CheckerTask; import com.eucalyptus.system.BaseDirectory; import com.eucalyptus.util.EucalyptusCloudException; import com.google.common.base.Function; import edu.ucsb.eucalyptus.msgs.ComponentProperty; import edu.ucsb.eucalyptus.util.SystemUtil; import edu.ucsb.eucalyptus.util.SystemUtil.CommandOutput; @StorageManagerProperty("das") public class DASManager implements LogicalStorageManager { private static Logger LOG = Logger.getLogger(DASManager.class); public static final String lvmRootDirectory = "/dev"; protected static final long LVM_HEADER_LENGTH = 4 * StorageProperties.MB; public static final String PATH_SEPARATOR = "/"; public static boolean initialized = false; public static final int MAX_LOOP_DEVICES = 256; public static final String EUCA_ROOT_WRAPPER = BaseDirectory.LIBEXEC.toString() + "/euca_rootwrap"; public static final String EUCA_VAR_RUN_PATH = System.getProperty("euca.run.dir"); public static final StorageExportManager exportManager = new ISCSIManager(); private static String volumeGroup; protected ConcurrentHashMap<String, VolumeOpMonitor> volumeOps; public void checkPreconditions() throws EucalyptusCloudException { //check if binaries exist, commands can be executed, etc. if (!new File(EUCA_ROOT_WRAPPER).exists()) { throw new EucalyptusCloudException( "root wrapper (euca_rootwrap) does not exist in " + EUCA_ROOT_WRAPPER); } File varDir = new File(EUCA_VAR_RUN_PATH); if (!varDir.exists()) { varDir.mkdirs(); } try { String returnValue = LVMWrapper.getLvmVersion(); if (returnValue.length() == 0) { throw new EucalyptusCloudException("Is lvm installed?"); } else { LOG.info(returnValue); } //exportManager = new ISCSIManager(); if (exportManager != null) { exportManager.checkPreconditions(); } } catch (EucalyptusCloudException ex) { String error = "Unable to run command: " + ex.getMessage(); LOG.error(error); throw new EucalyptusCloudException(error); } } private void updateVolumeGroup() throws EucalyptusCloudException { if (volumeGroup == null) { String dasDevice = DASInfo.getStorageInfo().getDASDevice(); if (dasDevice != null) { try { boolean volumeGroupFound = false; String returnValue = null; try { returnValue = LVMWrapper.getVolumeGroup(dasDevice); if (returnValue.length() > 0) { volumeGroupFound = true; } } catch (EucalyptusCloudException e) { LOG.warn(e); } if (volumeGroupFound) { Pattern volumeGroupPattern = Pattern.compile("(?s:.*VG Name)(.*)\n.*"); Matcher m = volumeGroupPattern.matcher(returnValue); if (m.find()) volumeGroup = m.group(1).trim(); else throw new EucalyptusCloudException("Not a volume group: " + dasDevice); } else { boolean physicalVolumeGroupFound = false; try { returnValue = LVMWrapper.getPhysicalVolume(dasDevice); if (returnValue.matches("(?s:.*)PV Name.*" + dasDevice + "(?s:.*)")) { physicalVolumeGroupFound = true; } } catch (EucalyptusCloudException e) { LOG.warn(e); } if (!physicalVolumeGroupFound) { returnValue = LVMWrapper.createPhysicalVolume(dasDevice); if (returnValue.length() == 0) { throw new EucalyptusCloudException( "Unable to create physical volume on device: " + dasDevice); } } //PV should be initialized at this point. returnValue = LVMWrapper.getPhysicalVolumeVerbose(dasDevice); if (returnValue.matches("(?s:.*)PV Name.*" + dasDevice + "(?s:.*)")) { Pattern volumeGroupPattern = Pattern.compile("(?s:.*VG Name)(.*)\n.*"); Matcher m = volumeGroupPattern.matcher(returnValue); if (m.find()) { volumeGroup = m.group(1).trim(); } if ((volumeGroup == null) || (volumeGroup.length() == 0)) { volumeGroup = generateVGName(Hashes.getRandom(10)); returnValue = LVMWrapper.createVolumeGroup(dasDevice, volumeGroup); if (returnValue.length() == 0) { throw new EucalyptusCloudException("Unable to create volume group: " + volumeGroup + " physical volume: " + dasDevice); } } } else { Pattern volumeGroupPattern = Pattern.compile("(?s:.*VG Name)(.*)\n.*"); Matcher m = volumeGroupPattern.matcher(returnValue); if (m.find()) volumeGroup = m.group(1).trim(); else throw new EucalyptusCloudException( "Unable to get volume group for physical volume: " + dasDevice); } } } catch (EucalyptusCloudException e) { LOG.error(e); throw new EucalyptusCloudException(e); } } else { throw new EucalyptusCloudException("DAS partition not yet configured. Please specify partition."); } } } protected String duplicateLogicalVolume(String oldLvName, String newLvName) throws EucalyptusCloudException { return SystemUtil.run(new String[] { EUCA_ROOT_WRAPPER, "dd", "if=" + oldLvName, "of=" + newLvName, "bs=" + StorageProperties.blockSize }); } protected String createFile(String fileName, long size) throws EucalyptusCloudException { if (!DirectStorageInfo.getStorageInfo().getZeroFillVolumes()) return SystemUtil.run(new String[] { EUCA_ROOT_WRAPPER, "dd", "if=/dev/zero", "of=" + fileName, "count=1", "bs=" + StorageProperties.blockSize, "seek=" + (size - 1) }); else return SystemUtil.run(new String[] { EUCA_ROOT_WRAPPER, "dd", "if=/dev/zero", "of=" + fileName, "count=" + size, "bs=" + StorageProperties.blockSize }); } protected String createEmptyFile(String fileName, int size) throws EucalyptusCloudException { long fileSize = size * 1024; return createFile(fileName, fileSize); } public String createAbsoluteEmptyFile(String fileName, long size) throws EucalyptusCloudException { size = size / ObjectStorageProperties.M; return createFile(fileName, size); } public void initialize() throws EucalyptusCloudException { if (!initialized) { //DO NOT WANT! //System.loadLibrary("dascontrol"); //registerSignals(); initialized = true; } } public void configure() throws EucalyptusCloudException { exportManager.configure(); //dummy init //this is retarded. wtf? LOG.info(StorageInfo.getStorageInfo().getName()); LOG.info(DirectStorageInfo.getStorageInfo().getName()); LOG.info(DASInfo.getStorageInfo().getName()); } public void startupChecks() { reload(); } public void cleanVolume(String volumeId) { try { updateVolumeGroup(); VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo lvmVolInfo = volumeManager.getVolumeInfo(volumeId); if (lvmVolInfo != null) { volumeManager.unexportVolume(lvmVolInfo); String lvName = lvmVolInfo.getLvName(); String absoluteLVName = lvmRootDirectory + PATH_SEPARATOR + volumeGroup + PATH_SEPARATOR + lvName; try { String returnValue = LVMWrapper.removeLogicalVolume(absoluteLVName); } catch (EucalyptusCloudException ex) { volumeManager.abort(); String error = "Unable to run command: " + ex.getMessage(); LOG.error(error); } volumeManager.remove(lvmVolInfo); volumeManager.finish(); } } catch (EucalyptusCloudException e) { LOG.debug("Failed to clean volume: " + volumeId, e); return; } } public void cleanSnapshot(String snapshotId) { try { updateVolumeGroup(); VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo lvmVolInfo = volumeManager.getVolumeInfo(snapshotId); if (lvmVolInfo != null) { volumeManager.remove(lvmVolInfo); } volumeManager.finish(); } catch (EucalyptusCloudException e) { LOG.debug("Failed to clean snapshotId: " + snapshotId, e); return; } } public native void registerSignals(); public void dupFile(String oldFileName, String newFileName) { FileOutputStream fileOutputStream = null; FileChannel out = null; FileInputStream fileInputStream = null; FileChannel in = null; try { fileOutputStream = new FileOutputStream(new File(newFileName)); out = fileOutputStream.getChannel(); fileInputStream = new FileInputStream(new File(oldFileName)); in = fileInputStream.getChannel(); in.transferTo(0, in.size(), out); } catch (Exception ex) { ex.printStackTrace(); } finally { if (fileOutputStream != null) { try { out.close(); fileOutputStream.close(); } catch (IOException e) { LOG.error(e); } } if (fileInputStream != null) { try { in.close(); fileInputStream.close(); } catch (IOException e) { LOG.error(e); } } } } //creates a logical volume (and a new physical volume and volume group) public void createLogicalVolume(String volumeId, String lvName, long size) throws EucalyptusCloudException { if (volumeGroup != null) { String returnValue = LVMWrapper.createLogicalVolume(volumeId, volumeGroup, lvName, size); if (returnValue.length() == 0) { throw new EucalyptusCloudException( "Unable to create logical volume " + lvName + " in volume group " + volumeGroup); } } else { throw new EucalyptusCloudException("Volume group is null! This should never happen"); } } public void createVolume(String volumeId, int size) throws EucalyptusCloudException { updateVolumeGroup(); File volumeDir = new File(DirectStorageInfo.getStorageInfo().getVolumesDir()); volumeDir.mkdirs(); VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); String lvName = generateLVName(volumeId);//"lv-" + Hashes.getRandom(4); LVMVolumeInfo lvmVolumeInfo = null; lvmVolumeInfo = new ISCSIVolumeInfo(); volumeManager.finish(); //create file and attach to loopback device try { //create logical volume createLogicalVolume(volumeId, lvName, (size * StorageProperties.KB)); lvmVolumeInfo.setVolumeId(volumeId); lvmVolumeInfo.setVgName(volumeGroup); lvmVolumeInfo.setLvName(lvName); lvmVolumeInfo.setStatus(StorageProperties.Status.available.toString()); lvmVolumeInfo.setSize(size); volumeManager = new VolumeEntityWrapperManager(); volumeManager.add(lvmVolumeInfo); volumeManager.finish(); } catch (EucalyptusCloudException ex) { String error = "Unable to run command: " + ex.getMessage(); volumeManager.abort(); LOG.error(error); throw new EucalyptusCloudException(error); } } public int createVolume(String volumeId, String snapshotId, int size) throws EucalyptusCloudException { updateVolumeGroup(); VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo foundSnapshotInfo = volumeManager.getVolumeInfo(snapshotId); if (foundSnapshotInfo != null) { String status = foundSnapshotInfo.getStatus(); if (status.equals(StorageProperties.Status.available.toString())) { String lvName = generateLVName(volumeId); //"lv-" + Hashes.getRandom(4); LVMVolumeInfo lvmVolumeInfo = volumeManager.getVolumeInfo(); String snapId = foundSnapshotInfo.getVolumeId(); String loFileName = foundSnapshotInfo.getLoFileName(); volumeManager.finish(); try { File snapshotFile = new File( DirectStorageInfo.getStorageInfo().getVolumesDir() + PATH_SEPARATOR + snapId); assert (snapshotFile.exists()); long absoluteSize; if (size <= 0 || size == foundSnapshotInfo.getSize()) { // size = (int)(snapshotFile.length() / StorageProperties.GB); absoluteSize = snapshotFile.length() / StorageProperties.MB; size = (int) (absoluteSize / StorageProperties.KB); } else { absoluteSize = size * StorageProperties.KB; } //create physical volume, volume group and logical volume createLogicalVolume(volumeId, lvName, absoluteSize); //duplicate snapshot volume String absoluteLVName = lvmRootDirectory + PATH_SEPARATOR + volumeGroup + PATH_SEPARATOR + lvName; duplicateLogicalVolume(loFileName, absoluteLVName); lvmVolumeInfo.setVolumeId(volumeId); lvmVolumeInfo.setVgName(volumeGroup); lvmVolumeInfo.setLvName(lvName); lvmVolumeInfo.setStatus(StorageProperties.Status.available.toString()); lvmVolumeInfo.setSize(size); volumeManager = new VolumeEntityWrapperManager(); volumeManager.add(lvmVolumeInfo); volumeManager.finish(); } catch (EucalyptusCloudException ex) { volumeManager.abort(); String error = "Unable to run command: " + ex.getMessage(); LOG.error(error); throw new EucalyptusCloudException(error); } } } else { volumeManager.abort(); throw new EucalyptusCloudException("Unable to find snapshot: " + snapshotId); } return size; } public void cloneVolume(String volumeId, String parentVolumeId) throws EucalyptusCloudException { updateVolumeGroup(); VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo foundVolumeInfo = volumeManager.getVolumeInfo(parentVolumeId); if (foundVolumeInfo != null) { String status = foundVolumeInfo.getStatus(); String lvName = generateLVName(volumeId); //"lv-" + Hashes.getRandom(4); LVMVolumeInfo lvmVolumeInfo = volumeManager.getVolumeInfo(); String parentLvName = foundVolumeInfo.getLvName(); int size = foundVolumeInfo.getSize(); volumeManager.finish(); try { File parentVolumeFile = new File( DirectStorageInfo.getStorageInfo().getVolumesDir() + PATH_SEPARATOR + parentVolumeId); assert (parentVolumeFile.exists()); long absouluteSize = (parentVolumeFile.length() / StorageProperties.MB); //create physical volume, volume group and logical volume createLogicalVolume(volumeId, lvName, absouluteSize); //duplicate snapshot volume String absoluteLVName = lvmRootDirectory + PATH_SEPARATOR + volumeGroup + PATH_SEPARATOR + lvName; String absoluteParentLVName = lvmRootDirectory + PATH_SEPARATOR + volumeGroup + PATH_SEPARATOR + parentLvName; duplicateLogicalVolume(absoluteParentLVName, absoluteLVName); //export logical volume try { volumeManager.exportVolume(lvmVolumeInfo, volumeGroup, lvName); } catch (EucalyptusCloudException ex) { String returnValue = LVMWrapper.removeLogicalVolume(absoluteLVName); throw ex; } lvmVolumeInfo.setVolumeId(volumeId); lvmVolumeInfo.setVgName(volumeGroup); lvmVolumeInfo.setLvName(lvName); lvmVolumeInfo.setStatus(StorageProperties.Status.available.toString()); lvmVolumeInfo.setSize(size); volumeManager = new VolumeEntityWrapperManager(); volumeManager.add(lvmVolumeInfo); volumeManager.finish(); } catch (EucalyptusCloudException ex) { volumeManager.abort(); String error = "Unable to run command: " + ex.getMessage(); LOG.error(error); throw new EucalyptusCloudException(error); } } else { volumeManager.abort(); throw new EucalyptusCloudException("Unable to find volume: " + parentVolumeId); } } public void addSnapshot(String snapshotId) throws EucalyptusCloudException { String snapshotRawFileName = DirectStorageInfo.getStorageInfo().getVolumesDir() + "/" + snapshotId; File snapshotFile = new File(snapshotRawFileName); if (snapshotFile.exists()) { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo lvmVolumeInfo = volumeManager.getVolumeInfo(); lvmVolumeInfo.setVolumeId(snapshotId); lvmVolumeInfo.setLoFileName(snapshotRawFileName); lvmVolumeInfo.setStatus(StorageProperties.Status.available.toString()); lvmVolumeInfo.setSize((int) (snapshotFile.length() / StorageProperties.GB)); volumeManager.add(lvmVolumeInfo); volumeManager.finish(); } else { throw new EucalyptusCloudException("Snapshot backing file does not exist for: " + snapshotId); } } public void deleteVolume(String volumeId) throws EucalyptusCloudException { updateVolumeGroup(); LVMVolumeInfo foundLVMVolumeInfo = null; { final VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); try { foundLVMVolumeInfo = volumeManager.getVolumeInfo(volumeId); } finally { volumeManager.finish(); } } if (foundLVMVolumeInfo != null) { boolean isReadyForDelete = false; int retryCount = 0; // Obtain a lock on the volume VolumeOpMonitor monitor = getMonitor(foundLVMVolumeInfo.getVolumeId()); VolumeEntityWrapperManager outerVolumeManager = null; do { LOG.debug("Trying to lock volume for export detection" + volumeId); synchronized (monitor) { final VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); try { foundLVMVolumeInfo = volumeManager.getVolumeInfo(volumeId); if (exportManager.isExported(foundLVMVolumeInfo)) { LOG.error("Cannot delete volume " + volumeId + " because it is currently exported"); volumeManager.finish(); } else { LOG.debug("Volume " + volumeId + " is prepped for deletion"); isReadyForDelete = true; break; } } catch (Exception e) { LOG.error("Error trying to check volume status", e); } finally { if (isReadyForDelete) { outerVolumeManager = volumeManager; // hand off without closing } else { volumeManager.abort(); //no-op if finish() called } } LOG.debug("Lap: " + retryCount++); } //Release the lock for retry. if (!isReadyForDelete) { try { Thread.sleep(10000); //sleep before the retry } catch (InterruptedException e) { throw new EucalyptusCloudException( "Thread interrupted. Failing volume delete for volume " + volumeId); } } } while (!isReadyForDelete && retryCount < 20); LOG.debug("Trying to lock volume for volume deletion" + volumeId); synchronized (monitor) { // delete the volume if (isReadyForDelete) { try { LOG.info("Deleting volume " + volumeId); String lvName = foundLVMVolumeInfo.getLvName(); String absoluteLVName = lvmRootDirectory + PATH_SEPARATOR + volumeGroup + PATH_SEPARATOR + lvName; String returnValue = ""; for (int i = 0; i < 5; ++i) { returnValue = LVMWrapper.removeLogicalVolume(absoluteLVName); if (returnValue.length() != 0) { if (returnValue.contains("successfully removed")) { break; } } //retry lv deletion (can take a while). try { Thread.sleep(500); } catch (InterruptedException e) { LOG.error(e); break; } } if (returnValue.length() == 0) { throw new EucalyptusCloudException("Unable to remove logical volume " + absoluteLVName); } outerVolumeManager.remove(foundLVMVolumeInfo); try { outerVolumeManager.finish(); } catch (Exception e) { LOG.error("Error deleting volume " + volumeId + ", failed to commit DB transaction", e); } } finally { outerVolumeManager.abort(); //no-op if finish() called } } else { LOG.error("All attempts to cleanup volume " + volumeId + " failed"); throw new EucalyptusCloudException( "Unable to delete volume: " + volumeId + ". All attempts to cleanup the volume failed"); } } // Remove the monitor removeMonitor(volumeId); } else { throw new EucalyptusCloudException("Unable to find volume: " + volumeId); } } protected static String generateLVName(String baseName) { return "euca-" + baseName; } protected static String generateVGName(String baseName) { return "euca-ebs-storage-vg-" + baseName; } public List<String> createSnapshot(String volumeId, String snapshotId, String snapshotPointId, Boolean shouldTransferSnapshot) throws EucalyptusCloudException { if (snapshotPointId != null) { throw new EucalyptusCloudException("Synchronous snapshot points not supported in DAS storage manager"); } updateVolumeGroup(); VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo foundLVMVolumeInfo = volumeManager.getVolumeInfo(volumeId); ArrayList<String> returnValues = new ArrayList<String>(); if (foundLVMVolumeInfo != null) { LVMVolumeInfo snapshotInfo = volumeManager.getVolumeInfo(); snapshotInfo.setVolumeId(snapshotId); File snapshotDir = new File(DirectStorageInfo.getStorageInfo().getVolumesDir()); snapshotDir.mkdirs(); String lvName = generateLVName(snapshotId);//"lv-snap-" + Hashes.getRandom(4); String absoluteLVName = lvmRootDirectory + PATH_SEPARATOR + volumeGroup + PATH_SEPARATOR + foundLVMVolumeInfo.getLvName(); int size = foundLVMVolumeInfo.getSize(); volumeManager.finish(); volumeManager = null; try { long absoluteSize; CommandOutput result = SystemUtil.runWithRawOutput( new String[] { EUCA_ROOT_WRAPPER, "blockdev", "--getsize64", absoluteLVName }); if (null != result && result.returnValue == 0 && StringUtils.isNotBlank(StringUtils.trim(result.output))) { try { absoluteSize = (Long.parseLong(StringUtils.trim(result.output)) / StorageProperties.MB); } catch (NumberFormatException e) { LOG.debug("Failed to parse size of volume " + volumeId, e); absoluteSize = size * StorageProperties.KB; } } else { absoluteSize = size * StorageProperties.KB; } //create physical volume, volume group and logical volume // String returnValue = createSnapshotLogicalVolume(absoluteLVName, lvName, size); String returnValue = LVMWrapper.createSnapshotLogicalVolume(absoluteLVName, lvName, absoluteSize); if (returnValue.length() == 0) { throw new EucalyptusCloudException( "Unable to create snapshot logical volume " + lvName + " for volume " + lvName); } String snapRawFileName = DirectStorageInfo.getStorageInfo().getVolumesDir() + "/" + snapshotId; String absoluteSnapLVName = lvmRootDirectory + PATH_SEPARATOR + volumeGroup + PATH_SEPARATOR + lvName; duplicateLogicalVolume(absoluteSnapLVName, snapRawFileName); returnValue = LVMWrapper.removeLogicalVolume(absoluteSnapLVName); if (returnValue.length() == 0) { throw new EucalyptusCloudException("Unable to remove logical volume " + absoluteSnapLVName); } snapshotInfo.setLoFileName(snapRawFileName); // snapshotInfo.setStatus(StorageProperties.Status.available.toString()); snapshotInfo.setSize(size); volumeManager = new VolumeEntityWrapperManager(); volumeManager.add(snapshotInfo); returnValues.add(snapRawFileName); returnValues.add(String.valueOf(size * ObjectStorageProperties.G)); // } catch(EucalyptusCloudException ex) { } catch (Exception ex) { if (volumeManager != null) volumeManager.abort(); String error = "Unable to run command: " + ex.getMessage(); LOG.error(error); throw new EucalyptusCloudException(error); } } volumeManager.finish(); return returnValues; } public List<String> prepareForTransfer(String snapshotId) throws EucalyptusCloudException { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo foundLVMVolumeInfo = volumeManager.getVolumeInfo(snapshotId); ArrayList<String> returnValues = new ArrayList<String>(); if (foundLVMVolumeInfo != null) { returnValues.add(DirectStorageInfo.getStorageInfo().getVolumesDir() + PATH_SEPARATOR + foundLVMVolumeInfo.getVolumeId()); volumeManager.finish(); } else { volumeManager.abort(); throw new EucalyptusCloudException("Unable to find snapshot: " + snapshotId); } return returnValues; } public void deleteSnapshot(String snapshotId) throws EucalyptusCloudException { updateVolumeGroup(); VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo foundLVMVolumeInfo = volumeManager.getVolumeInfo(snapshotId); if (foundLVMVolumeInfo != null) { volumeManager.remove(foundLVMVolumeInfo); File snapFile = new File(DirectStorageInfo.getStorageInfo().getVolumesDir() + File.separator + foundLVMVolumeInfo.getVolumeId()); volumeManager.finish(); if (snapFile.exists()) { if (!snapFile.delete()) { throw new EucalyptusCloudException("Unable to delete: " + snapFile.getAbsolutePath()); } } } else { volumeManager.abort(); throw new EucalyptusCloudException("Unable to find snapshot: " + snapshotId); } } public String getVolumeConnectionString(String volumeId) throws EucalyptusCloudException { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); String returnValue = volumeManager.getConnectionString(volumeId); volumeManager.finish(); return returnValue; } public void reload() { LOG.info("Reload: starting reload process to re-export volumes if necessary"); VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); List<LVMVolumeInfo> volumeInfos = volumeManager.getAllVolumeInfos(); //now enable them for (LVMVolumeInfo foundVolumeInfo : volumeInfos) { try { LOG.info("Reload: Checking volume " + foundVolumeInfo.getVolumeId() + " for export"); if (foundVolumeInfo.getVgName() != null && volumeManager.shouldExportOnReload(foundVolumeInfo)) { LOG.info("Reload: Volume " + foundVolumeInfo.getVolumeId() + " was exported at shutdown. Not found to be already exported. Re-exporting volume."); volumeManager.exportVolume(foundVolumeInfo); } else { LOG.info("Reload: volume " + foundVolumeInfo.getVolumeId() + " not previously exported or already exported, no action required. Skipping"); } } catch (EucalyptusCloudException ex) { LOG.error("Unable to reload volume: " + foundVolumeInfo.getVolumeId() + " due to: " + ex); } } volumeManager.finish(); } public int getSnapshotSize(String snapshotId) throws EucalyptusCloudException { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo lvmVolumeInfo = volumeManager.getVolumeInfo(snapshotId); if (lvmVolumeInfo != null) { int snapSize = lvmVolumeInfo.getSize(); volumeManager.finish(); return snapSize; } else { volumeManager.abort(); return 0; } } protected class VolumeEntityWrapperManager { private EntityWrapper entityWrapper; protected VolumeEntityWrapperManager() { entityWrapper = StorageProperties.getEntityWrapper(); } /** * Returns if the volume should be re-exported on reload based on DB state. Masks the implementation * details from DASManager so it can be changed based on DB or iscsi implementation * @param lvmVolumeInfo * @return */ public boolean shouldExportOnReload(LVMVolumeInfo lvmVolumeInfo) { if (lvmVolumeInfo instanceof ISCSIVolumeInfo) { ISCSIVolumeInfo iscsiVolumeInfo = (ISCSIVolumeInfo) lvmVolumeInfo; try { return iscsiVolumeInfo.getTid() >= 0 && !exportManager.isExported(lvmVolumeInfo); } catch (EucalyptusCloudException e) { LOG.error("Failed to determine if volume " + lvmVolumeInfo.getVolumeId() + " is already exported. Returning false", e); } } return false; } public List<String> getSnapshotValues(String snapshotId) { ArrayList<String> returnValues = new ArrayList<String>(); LVMVolumeInfo lvmVolumeInfo = getVolumeInfo(snapshotId); return returnValues; } public void exportVolume(LVMVolumeInfo lvmVolumeInfo) throws EucalyptusCloudException { if (lvmVolumeInfo instanceof ISCSIVolumeInfo) { ISCSIVolumeInfo iscsiVolumeInfo = (ISCSIVolumeInfo) lvmVolumeInfo; String absoluteLVName = lvmRootDirectory + PATH_SEPARATOR + iscsiVolumeInfo.getVgName() + PATH_SEPARATOR + iscsiVolumeInfo.getLvName(); if (!LVMWrapper.logicalVolumeExists(absoluteLVName)) { LOG.error("Backing volume not found: " + absoluteLVName); throw new EucalyptusCloudException("Logical volume not found: " + absoluteLVName); } try { LVMWrapper.enableLogicalVolume(absoluteLVName); } catch (EucalyptusCloudException ex) { String error = "Unable to run command: " + ex.getMessage(); LOG.error(error); throw new EucalyptusCloudException(ex); } ((ISCSIManager) exportManager).exportTarget(iscsiVolumeInfo.getVolumeId(), iscsiVolumeInfo.getTid(), iscsiVolumeInfo.getStoreName(), iscsiVolumeInfo.getLun(), absoluteLVName, iscsiVolumeInfo.getStoreUser()); } } public String getConnectionString(String volumeId) { LVMVolumeInfo lvmVolumeInfo = getVolumeInfo(volumeId); if (lvmVolumeInfo != null) { ISCSIVolumeInfo iscsiVolumeInfo = (ISCSIVolumeInfo) lvmVolumeInfo; String storeName = iscsiVolumeInfo.getStoreName(); String encryptedPassword; try { encryptedPassword = ((ISCSIManager) exportManager).getEncryptedPassword(); } catch (EucalyptusCloudException e) { LOG.error(e); return null; } return ",,," + encryptedPassword + ",," + StorageProperties.STORAGE_HOST + "," + storeName; } return null; } public void unexportVolume(LVMVolumeInfo volumeInfo) { StorageExportManager manager = exportManager; if (!(exportManager instanceof ISCSIManager)) { manager = new ISCSIManager(); } ISCSIVolumeInfo iscsiVolumeInfo = (ISCSIVolumeInfo) volumeInfo; //Use the absolute name to verify that the target is correct before unexport String absoluteLVName = lvmRootDirectory + PATH_SEPARATOR + iscsiVolumeInfo.getVgName() + PATH_SEPARATOR + iscsiVolumeInfo.getLvName(); if (LVMWrapper.logicalVolumeExists(absoluteLVName)) { try { ((ISCSIManager) manager).unexportTarget(volumeInfo.getVolumeId(), iscsiVolumeInfo.getTid(), iscsiVolumeInfo.getLun(), absoluteLVName); } catch (EucalyptusCloudException e) { LOG.error("Error unexporting target for volume " + volumeInfo.getVolumeId(), e); return; } } iscsiVolumeInfo.setTid(-1); } protected void finish() { try { entityWrapper.commit(); } catch (Exception ex) { LOG.error(ex, ex); entityWrapper.rollback(); } } protected void abort() { entityWrapper.rollback(); } protected LVMVolumeInfo getVolumeInfo(String volumeId) { ISCSIVolumeInfo ISCSIVolumeInfo = new ISCSIVolumeInfo(volumeId); List<ISCSIVolumeInfo> ISCSIVolumeInfos = entityWrapper.query(ISCSIVolumeInfo); if (ISCSIVolumeInfos.size() > 0) { return ISCSIVolumeInfos.get(0); } return null; } protected boolean areSnapshotsPending(String volumeId) { ISCSIVolumeInfo ISCSIVolumeInfo = new ISCSIVolumeInfo(); ISCSIVolumeInfo.setSnapshotOf(volumeId); ISCSIVolumeInfo.setStatus(StorageProperties.Status.pending.toString()); List<ISCSIVolumeInfo> ISCSIVolumeInfos = entityWrapper.query(ISCSIVolumeInfo); if (ISCSIVolumeInfos.size() > 0) { return true; } return false; } protected LVMVolumeInfo getVolumeInfo() { return new ISCSIVolumeInfo(); } protected List<LVMVolumeInfo> getAllVolumeInfos() { List<LVMVolumeInfo> volumeInfos = new ArrayList<LVMVolumeInfo>(); volumeInfos.addAll(entityWrapper.query(new ISCSIVolumeInfo())); return volumeInfos; } protected void add(LVMVolumeInfo volumeInfo) { entityWrapper.add(volumeInfo); } protected void remove(LVMVolumeInfo volumeInfo) { entityWrapper.delete(volumeInfo); } protected String encryptTargetPassword(String password) throws EucalyptusCloudException { try { List<ServiceConfiguration> partitionConfigs = ServiceConfigurations .listPartition(ClusterController.class, StorageProperties.NAME); ServiceConfiguration clusterConfig = partitionConfigs.get(0); PublicKey ncPublicKey = Partitions.lookup(clusterConfig).getNodeCertificate().getPublicKey(); Cipher cipher = Ciphers.RSA_PKCS1.get(); cipher.init(Cipher.ENCRYPT_MODE, ncPublicKey); return new String(Base64.encode(cipher.doFinal(password.getBytes()))); } catch (Exception e) { LOG.error("Unable to encrypt storage target password"); throw new EucalyptusCloudException(e.getMessage(), e); } } protected void exportVolume(LVMVolumeInfo lvmVolumeInfo, String vgName, String lvName) throws EucalyptusCloudException { ISCSIVolumeInfo iscsiVolumeInfo = (ISCSIVolumeInfo) lvmVolumeInfo; String absoluteLVName = lvmRootDirectory + PATH_SEPARATOR + vgName + PATH_SEPARATOR + lvName; int max_tries = 10; int i = 0; EucalyptusCloudException ex = null; do { exportManager.allocateTarget(iscsiVolumeInfo); try { ((ISCSIManager) exportManager).exportTarget(iscsiVolumeInfo.getVolumeId(), iscsiVolumeInfo.getTid(), iscsiVolumeInfo.getStoreName(), iscsiVolumeInfo.getLun(), absoluteLVName, iscsiVolumeInfo.getStoreUser()); ex = null; //it worked. break out. may be break is a better way of breaking out? //i = max_tries; break; } catch (EucalyptusCloudException e) { ex = e; LOG.error(e); } } while (i++ < max_tries); // EUCA-3597 After all retries, check if the process actually completed if (null != ex) { throw ex; } } } @Override public void loadSnapshots(List<String> snapshotSet, List<String> snapshotFileNames) throws EucalyptusCloudException { // TODO Auto-generated method stub } @Override public String prepareSnapshot(String snapshotId, int sizeExpected, long actualSizeInMB) throws EucalyptusCloudException { String deviceName = null; VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo foundSnapshotInfo = volumeManager.getVolumeInfo(snapshotId); if (null == foundSnapshotInfo) { LVMVolumeInfo snapshotInfo = volumeManager.getVolumeInfo(); snapshotInfo.setVolumeId(snapshotId); snapshotInfo.setSize(sizeExpected); snapshotInfo.setLoFileName( DirectStorageInfo.getStorageInfo().getVolumesDir() + File.separator + snapshotId); deviceName = snapshotInfo.getLoFileName(); volumeManager.add(snapshotInfo); } volumeManager.finish(); return deviceName; // return DirectStorageInfo.getStorageInfo().getVolumesDir() + File.separator + snapshotId; } @Override public ArrayList<ComponentProperty> getStorageProps() { ArrayList<ComponentProperty> componentProperties = null; ConfigurableClass configurableClass = StorageInfo.class.getAnnotation(ConfigurableClass.class); if (configurableClass != null) { String root = configurableClass.root(); String alias = configurableClass.alias(); componentProperties = (ArrayList<ComponentProperty>) PropertyDirectory .getComponentPropertySet(StorageProperties.NAME + "." + root, alias); } configurableClass = DirectStorageInfo.class.getAnnotation(ConfigurableClass.class); if (configurableClass != null) { String root = configurableClass.root(); String alias = configurableClass.alias(); if (componentProperties == null) componentProperties = (ArrayList<ComponentProperty>) PropertyDirectory .getComponentPropertySet(StorageProperties.NAME + "." + root, alias); else componentProperties.addAll( PropertyDirectory.getComponentPropertySet(StorageProperties.NAME + "." + root, alias)); } configurableClass = DASInfo.class.getAnnotation(ConfigurableClass.class); if (configurableClass != null) { String root = configurableClass.root(); String alias = configurableClass.alias(); if (componentProperties == null) componentProperties = (ArrayList<ComponentProperty>) PropertyDirectory .getComponentPropertySet(StorageProperties.NAME + "." + root, alias); else componentProperties.addAll( PropertyDirectory.getComponentPropertySet(StorageProperties.NAME + "." + root, alias)); } return componentProperties; } @Override public void setStorageProps(ArrayList<ComponentProperty> storageProps) { for (ComponentProperty prop : storageProps) { try { ConfigurableProperty entry = PropertyDirectory.getPropertyEntry(prop.getQualifiedName()); //type parser will correctly covert the value entry.setValue(prop.getValue()); } catch (IllegalAccessException | ConfigurablePropertyException e) { LOG.error(e, e); } } } @Override public String getStorageRootDirectory() { return DirectStorageInfo.getStorageInfo().getVolumesDir(); } @Override public void finishVolume(String snapshotId) throws EucalyptusCloudException { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo foundSnapshotInfo = volumeManager.getVolumeInfo(snapshotId); if (null != foundSnapshotInfo) { foundSnapshotInfo.setStatus(StorageProperties.Status.available.toString()); } volumeManager.finish(); } @Override public String getSnapshotPath(String snapshotId) throws EucalyptusCloudException { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo volInfo = volumeManager.getVolumeInfo(snapshotId); if (volInfo != null) { String snapPath = volInfo.getLoFileName(); volumeManager.finish(); return snapPath; } else { volumeManager.abort(); throw new EntityNotFoundException("Unable to find snapshot with id: " + snapshotId); } } @Override public String getVolumePath(String volumeId) throws EucalyptusCloudException { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo volInfo = volumeManager.getVolumeInfo(volumeId); if (volInfo != null) { String volumePath = lvmRootDirectory + File.separator + volInfo.getVgName() + File.separator + volInfo.getLvName(); volumeManager.finish(); return volumePath; } else { volumeManager.abort(); throw new EntityNotFoundException("Unable to find volume with id: " + volumeId); } } @Override public void importSnapshot(String snapshotId, String snapPath, String volumeId, int size) throws EucalyptusCloudException { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo snapInfo = volumeManager.getVolumeInfo(snapshotId); if (snapInfo != null) { volumeManager.finish(); throw new EucalyptusCloudException("Snapshot " + snapshotId + " already exists. Import failed."); } volumeManager.finish(); String snapFileName = getStorageRootDirectory() + File.separator + snapshotId; SystemUtil.run(new String[] { StorageProperties.EUCA_ROOT_WRAPPER, "dd", "if=" + snapPath, "of=" + snapFileName, "bs=" + StorageProperties.blockSize }); volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo snapshotInfo = volumeManager.getVolumeInfo(); snapshotInfo.setVolumeId(snapshotId); snapshotInfo.setLoFileName(snapFileName); snapshotInfo.setSize(size); snapshotInfo.setSnapshotOf(volumeId); volumeManager.add(snapshotInfo); volumeManager.finish(); } @Override public void importVolume(String volumeId, String volumePath, int size) throws EucalyptusCloudException { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo volInfo = volumeManager.getVolumeInfo(volumeId); if (volInfo != null) { volumeManager.finish(); throw new EucalyptusCloudException("Volume " + volumeId + " already exists. Import failed."); } volumeManager.finish(); createVolume(volumeId, size); volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo volumeInfo = volumeManager.getVolumeInfo(volumeId); if (volumeInfo != null) { SystemUtil.run(new String[] { StorageProperties.EUCA_ROOT_WRAPPER, "dd", "if=" + volumePath, "of=" + lvmRootDirectory + File.separator + volumeInfo.getVgName() + File.separator + volumeInfo.getLvName(), "bs=" + StorageProperties.blockSize }); } else { volumeManager.abort(); throw new EucalyptusCloudException("Unable to find volume with id: " + volumeId); } } /** * NOTE: once exported to one host, it is exported to all in this implementation */ @Override public String exportVolume(String volumeId, String nodeIqn) throws EucalyptusCloudException { try { updateVolumeGroup(); } catch (EucalyptusCloudException e) { LOG.error(e); throw e; } LVMVolumeInfo lvmVolumeInfo = null; { final VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); try { lvmVolumeInfo = volumeManager.getVolumeInfo(volumeId); } finally { volumeManager.finish(); } } if (lvmVolumeInfo != null) { VolumeOpMonitor monitor = getMonitor(volumeId); synchronized (monitor) { final VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); try { lvmVolumeInfo = volumeManager.getVolumeInfo(volumeId); String lvName = lvmVolumeInfo.getLvName(); if (lvmVolumeInfo.getVgName() == null) { lvmVolumeInfo.setVgName(volumeGroup); } try { // export logical volume volumeManager.exportVolume(lvmVolumeInfo, volumeGroup, lvName); } catch (EucalyptusCloudException ex) { LOG.error("Unable to export volume " + volumeId, ex); throw ex; } } catch (Exception ex) { LOG.error("Failed to attach volume " + volumeId, ex); throw new EucalyptusCloudException("Failed to attach volume " + volumeId, ex); } finally { try { volumeManager.finish(); } catch (Exception e) { LOG.error("Unable to commit the database transaction after an attempt to attach volume " + volumeId, e); } } } // synchronized } //Return the connection string. return getVolumeConnectionString(volumeId); } /** * This implementation does not do export/unexport from single hosts, only all or none. * Caller should be keeping track of exports and call @unexportVolumeFromAll when appropriate */ @Override public void unexportVolume(String volumeId, String nodeIqn) throws EucalyptusCloudException, UnsupportedOperationException { throw new UnsupportedOperationException("DASManager does not support node-specific export/unexport"); /*VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); LVMVolumeInfo foundLVMVolumeInfo = volumeManager.getVolumeInfo(volumeId); if(foundLVMVolumeInfo != null) { LOG.info("Marking volume: " + volumeId + " for cleanup"); foundLVMVolumeInfo.setCleanup(true); volumeManager.finish(); } else { volumeManager.abort(); throw new EucalyptusCloudException("Unable to find volume: " + volumeId); }*/ } @Override public void unexportVolumeFromAll(String volumeId) throws EucalyptusCloudException { VolumeEntityWrapperManager volumeManager = new VolumeEntityWrapperManager(); try { LVMVolumeInfo foundLVMVolumeInfo = volumeManager.getVolumeInfo(volumeId); if (foundLVMVolumeInfo != null) { //LOG.info("Marking volume: " + volumeId + " for cleanup"); //foundLVMVolumeInfo.setCleanup(true); LOG.info("Unexporting volume " + volumeId + " from all clients"); VolumeOpMonitor monitor = getMonitor(volumeId); synchronized (monitor) { try { LOG.info("Unexporting volume " + foundLVMVolumeInfo.getVolumeId()); try { String path = lvmRootDirectory + PATH_SEPARATOR + volumeGroup + PATH_SEPARATOR + foundLVMVolumeInfo.getLvName(); if (LVMWrapper.logicalVolumeExists(path)) { //guard this. tgt is not happy when you ask it to //get rid of a non existent tid exportManager.cleanup(foundLVMVolumeInfo); } foundLVMVolumeInfo.setStatus("available"); LOG.info("Done cleaning up: " + foundLVMVolumeInfo.getVolumeId()); } catch (EucalyptusCloudException ee) { LOG.error(ee, ee); throw ee; } } finally { monitor.notifyAll(); } } // synchronized } else { volumeManager.abort(); throw new EucalyptusCloudException("Unable to find volume: " + volumeId); } } catch (Exception e) { LOG.error("Failed to unexport volume " + volumeId); throw new EucalyptusCloudException("Failed to unexport volume " + volumeId); } finally { volumeManager.finish(); } } @Override public void checkReady() throws EucalyptusCloudException { //check if binaries exist, commands can be executed, etc. if (!new File(StorageProperties.EUCA_ROOT_WRAPPER).exists()) { throw new EucalyptusCloudException( "root wrapper (euca_rootwrap) does not exist in " + StorageProperties.EUCA_ROOT_WRAPPER); } File varDir = new File(EUCA_VAR_RUN_PATH); if (!varDir.exists()) { varDir.mkdirs(); } exportManager.check(); } @Override public void stop() throws EucalyptusCloudException { exportManager.stop(); } @Override public void disable() throws EucalyptusCloudException { volumeOps.clear(); volumeOps = null; } @Override public void enable() throws EucalyptusCloudException { volumeOps = new ConcurrentHashMap<String, VolumeOpMonitor>(); } @Override public boolean getFromBackend(String snapshotId, int size) throws EucalyptusCloudException { return false; } @Override public void checkVolume(String volumeId) throws EucalyptusCloudException { } @Override public List<CheckerTask> getCheckers() { List<CheckerTask> checkers = new ArrayList<CheckerTask>(); //Volume cleanup is now synchronous, no need for background tasks return checkers; } @Override public String createSnapshotPoint(String volumeId, String snapshotId) throws EucalyptusCloudException { return null; } @Override public void deleteSnapshotPoint(String volumeId, String snapshotId, String snapshotPointId) throws EucalyptusCloudException { throw new EucalyptusCloudException("Synchronous snapshot points not supported in DAS storage manager"); } protected class VolumeOpMonitor { public VolumeOpMonitor() { }; } protected VolumeOpMonitor getMonitor(String key) { VolumeOpMonitor monitor = volumeOps.putIfAbsent(key, new VolumeOpMonitor()); if (monitor == null) { monitor = volumeOps.get(key); } return monitor; } public void removeMonitor(String key) { volumeOps.remove(key); } }