org.cloudifysource.utilitydomain.context.blockstorage.VolumeUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudifysource.utilitydomain.context.blockstorage.VolumeUtils.java

Source

/*******************************************************************************
 * Copyright (c) 2012 GigaSpaces Technologies Ltd. All rights reserved
 *
 * Licensed 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 org.cloudifysource.utilitydomain.context.blockstorage;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.LogOutputStream;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.cloudifysource.domain.context.blockstorage.LocalStorageOperationException;
import org.cloudifysource.domain.context.blockstorage.StorageFacade;
import org.hyperic.sigar.FileSystem;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;

import com.gigaspaces.internal.sigar.SigarHolder;

/**
 * 
 * @author elip
 *
 */
public final class VolumeUtils {

    // prevent instantiation.
    private VolumeUtils() {

    }

    private static final Logger logger = Logger.getLogger(VolumeUtils.class.getName());

    private static final String USER_NAME = System.getProperty("user.name");

    private static final long MOUNT_TIMEOUT = 30 * 1000;
    private static final long FORMAT_TIMEOUT = 5 * 60 * 1000;
    private static final long PARTITION_TIMEOUT = 30 * 1000;
    private static final long UNMOUNT_TIMEOUT = 15 * 1000;

    private static final long TEN_SECONDS = 10 * 1000;

    /**
     * @see {@link StorageFacade#unmount(String, long)}.
     * @param device .
     * @param timeoutInMillis .
     * @throws LocalStorageOperationException .
     * @throws TimeoutException .
     */
    public static void unmount(final String device, final long timeoutInMillis)
            throws LocalStorageOperationException, TimeoutException {
        executeCommandLine("sudo umount -d -v -l -f " + device, timeoutInMillis);
    }

    /**
     * @see {@link StorageFacade#unmount(String)}
     * @param device . 
     * @throws LocalStorageOperationException .
     * @throws TimeoutException .
     */
    public static void unmount(final String device) throws LocalStorageOperationException, TimeoutException {
        unmount(device, UNMOUNT_TIMEOUT);
    }

    /**
     * @see {@link StorageFacade#mount(String, String, long)}
     * @param device .
     * @param path .
     * @param timeoutInMillis .
     * @throws LocalStorageOperationException .
     * @throws TimeoutException .
     */
    public static void mount(final String device, final String path, final long timeoutInMillis)
            throws LocalStorageOperationException, TimeoutException {
        File devicePath = new File(path);
        executeCommandLine("sudo mkdir " + path, TEN_SECONDS);
        executeCommandLine("sudo mount " + device + " " + path, timeoutInMillis);
        executeCommandLine("sudo chown " + USER_NAME + " " + devicePath.getAbsolutePath(), TEN_SECONDS);
    }

    /**
     * @see {@link StorageFacade#mount(String, String)}
     * @param device .
     * @param path .
     * @throws LocalStorageOperationException .
     * @throws TimeoutException .
     */
    public static void mount(final String device, final String path)
            throws LocalStorageOperationException, TimeoutException {
        mount(device, path, MOUNT_TIMEOUT);
    }

    /**
     * @see {@link StorageFacade#format(String, String, long)}
     * @param device . 
     * @param fileSystem .
     * @param timeoutInMillis .
     * @throws LocalStorageOperationException .
     * @throws TimeoutException .
     */
    public static void format(final String device, final String fileSystem, final long timeoutInMillis)
            throws LocalStorageOperationException, TimeoutException {
        checkFileSystemSupported(fileSystem);
        executeCommandLine("sudo mkfs -t " + fileSystem + " " + device, timeoutInMillis);

    }

    /**
     * @see {@link StorageFacade#format(String, String)}.
     * @param device .
     * @param fileSystem .
     * @throws LocalStorageOperationException .
     * @throws TimeoutException .
     */
    public static void format(final String device, final String fileSystem)
            throws LocalStorageOperationException, TimeoutException {
        format(device, fileSystem, FORMAT_TIMEOUT);
    }

    /**
     * @see {@link StorageFacade#partition(String, long)}
     * @param device .
     * @param timeoutInMillis .
     * @throws LocalStorageOperationException .
     * @throws TimeoutException .
     */
    public static void partition(final String device, final long timeoutInMillis)
            throws LocalStorageOperationException, TimeoutException {
        try {
            File tempParitioningScript = File.createTempFile("partitionvolume", ".sh");
            FileUtils.writeStringToFile(tempParitioningScript,
                    "(echo o; echo n; echo p; echo 1; echo; echo; echo w) | sudo fdisk " + device);
            tempParitioningScript.setExecutable(true);
            tempParitioningScript.deleteOnExit();
            executeCommandLine(tempParitioningScript.getAbsolutePath(), timeoutInMillis);
        } catch (IOException ioe) {
            // fdisk returns exit code 1 even when successful so we have to verify
            logger.info("inspecting fdisk command exception: " + ioe.getMessage());
            if (!verifyDevicePartitioning(device, timeoutInMillis)) {
                throw new LocalStorageOperationException(
                        "Failed to partition device " + device + ", reported error: " + ioe.getMessage(), ioe);
            }
        }

    }

    private static boolean verifyDevicePartitioning(final String device, final long timeoutInMillis)
            throws LocalStorageOperationException, TimeoutException {

        boolean deviceFormatted = false;

        try {
            File tempDeviceListScript = File.createTempFile("getPartitionStatus", ".sh");
            FileUtils.writeStringToFile(tempDeviceListScript, "sudo fdisk -l | grep " + device);
            tempDeviceListScript.setExecutable(true);
            tempDeviceListScript.deleteOnExit();
            String fdiskOutput = executeSilentCommandLineReturnOutput(tempDeviceListScript.getAbsolutePath(),
                    timeoutInMillis);
            if (fdiskOutput.contains(device + ":")
                    && !fdiskOutput.contains(device + " doesn't contain a valid partition table")) {
                deviceFormatted = true;
            }
        } catch (Exception e) {
            throw new LocalStorageOperationException("Failed verifying paritioning of device: " + device, e);
        }

        return deviceFormatted;

    }

    /**
     * @see {@link StorageFacade#partition(String)}.
     * @param device .
     * @throws LocalStorageOperationException .
     * @throws TimeoutException .
     */
    public static void partition(final String device) throws LocalStorageOperationException, TimeoutException {
        partition(device, PARTITION_TIMEOUT);
    }

    private static void checkFileSystemSupported(final String fileSystem) throws LocalStorageOperationException {

        FileSystem[] fileSystemList;
        try {
            Sigar sigar = SigarHolder.getSigar();
            fileSystemList = sigar.getFileSystemList();
        } catch (final SigarException e) {
            throw new LocalStorageOperationException(e);
        }

        List<String> supportedFileSystems = new ArrayList<String>();
        for (FileSystem fs : fileSystemList) {
            if (fileSystem.equalsIgnoreCase(fs.getSysTypeName())) {
                return;
            } else {
                supportedFileSystems.add(fs.getSysTypeName());
            }
        }
        throw new LocalStorageOperationException("File system type " + fileSystem
                + " is not supported for the current operating system. Supported File Systems are : "
                + StringUtils.join(supportedFileSystems, ","));
    }

    private static void executeCommandLine(final String commandLine, final long timeout)
            throws LocalStorageOperationException, TimeoutException {

        Executor executor = new DefaultExecutor();
        executor.setExitValue(0);
        ExecuteWatchdog watchdog = new ExecuteWatchdog(timeout);
        executor.setWatchdog(watchdog);
        ProcessOutputStream outAndErr = new ProcessOutputStream();
        try {
            PumpStreamHandler streamHandler = new PumpStreamHandler(outAndErr);
            executor.setStreamHandler(streamHandler);
            logger.info("Executing commandLine : '" + commandLine + "'");
            executor.execute(CommandLine.parse(commandLine));
            logger.info("Execution completed successfully. Process output was : " + outAndErr.getOutput());
        } catch (final Exception e) {
            if (watchdog.killedProcess()) {
                throw new TimeoutException("Timed out while executing commandLine : '" + commandLine + "'");
            }

            throw new LocalStorageOperationException("Failed executing commandLine : '" + commandLine
                    + ". Process output was : " + outAndErr.getOutput(), e);
        }
    }

    private static String executeSilentCommandLineReturnOutput(final String commandLine, final long timeout)
            throws LocalStorageOperationException, TimeoutException {

        Executor executor = new DefaultExecutor();
        executor.setExitValue(0);
        ExecuteWatchdog watchdog = new ExecuteWatchdog(timeout);
        executor.setWatchdog(watchdog);
        ProcessOutputStream outAndErr = new ProcessOutputStream();
        try {
            PumpStreamHandler streamHandler = new PumpStreamHandler(outAndErr);
            executor.setStreamHandler(streamHandler);
            executor.execute(CommandLine.parse(commandLine));
        } catch (final Exception e) {
            if (watchdog.killedProcess()) {
                throw new TimeoutException("Timed out while executing commandLine : '" + commandLine + "'");
            }

            throw new LocalStorageOperationException("Failed executing commandLine : '" + commandLine
                    + ". Process output was : " + outAndErr.getOutput(), e);
        }

        return outAndErr.getOutput();
    }

    /**
     * Logs process output to the logger.
     * @author elip
     *
     */
    private static class ProcessOutputStream extends LogOutputStream {

        private List<String> output = new java.util.LinkedList<String>();

        private String getOutput() {
            return StringUtils.join(output, "\n");
        }

        @Override
        protected void processLine(final String line, final int level) {
            output.add(line);
            logger.info(line);
        }
    }
}