/*******************************************************************************
* 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.util.concurrent.TimeoutException;
import org.cloudifysource.domain.cloud.storage.StorageTemplate;
import org.cloudifysource.domain.context.ServiceContext;
import org.cloudifysource.domain.context.blockstorage.LocalStorageOperationException;
import org.cloudifysource.domain.context.blockstorage.RemoteStorageOperationException;
import org.cloudifysource.domain.context.blockstorage.StorageFacade;
import org.cloudifysource.dsl.internal.context.RemoteStorageProvisioningDriver;
import org.cloudifysource.utilitydomain.context.kvstore.AttributesFacadeImpl;
import org.openspaces.core.GigaSpace;
import com.gigaspaces.client.ChangeSet;
/**
*
* @author elip
*
*/
public class StorageFacadeImpl implements StorageFacade {
private static final long AFTER_ATTACH_TIMEOUT = 10 * 1000;
private final ServiceContext serviceContext;
private final RemoteStorageProvisioningDriver remoteStorageProvisioningDriver;
private final GigaSpace managementSpace;
private static final java.util.logging.Logger logger = java.util.logging.Logger
.getLogger(StorageFacade.class.getName());
public StorageFacadeImpl(final ServiceContext serviceContext,
final RemoteStorageProvisioningDriver storageApi) {
this.serviceContext = serviceContext;
this.remoteStorageProvisioningDriver = storageApi;
this.managementSpace = ((AttributesFacadeImpl) serviceContext.getAttributes()).getManagementSpace();
logger.fine("Storage Facade initiated successfully");
}
@Override
public void attachVolume(final String volumeId, final String device)
throws RemoteStorageOperationException, LocalStorageOperationException {
validateNotWindows();
logger.info("Attaching volume with id " + volumeId + " to device " + device);
safeGetRemoteStorageProvisioningDriver().attachVolume(volumeId, device, serviceContext.getBindAddress());
changeStateOfVolumeWithId(volumeId, VolumeState.ATTACHED);
setDeviceForVolumeWithId(volumeId, device);
try {
// ugly as hell. can't really figure out how to wait here properly for the volume to actually be attached.
// see CLOUDIFY-1551
Thread.sleep(AFTER_ATTACH_TIMEOUT);
} catch (InterruptedException e) {
throw new LocalStorageOperationException(e);
}
}
@Override
public String createVolume(final String templateName) throws RemoteStorageOperationException, TimeoutException {
logger.info("Creating volume for service " + serviceContext.getServiceName() + ". Using template : "
+ templateName);
String volumeId =
safeGetRemoteStorageProvisioningDriver().createVolume(templateName, serviceContext.getLocationId());
writeNewVolume(volumeId);
return volumeId;
}
@Override
public String createVolume(final String templateName, final long timeoutInMillis)
throws RemoteStorageOperationException, TimeoutException {
logger.info("Creating volume for service " + serviceContext.getServiceName() + ". Using template : "
+ templateName);
String volumeId = safeGetRemoteStorageProvisioningDriver().
createVolume(templateName, serviceContext.getLocationId(), timeoutInMillis);
writeNewVolume(volumeId);
return volumeId;
}
@Override
public void detachVolume(final String volumeId)
throws RemoteStorageOperationException, LocalStorageOperationException {
validateNotWindows();
logger.info("Detaching volume with id " + volumeId);
safeGetRemoteStorageProvisioningDriver().detachVolume(volumeId, serviceContext.getBindAddress());
}
@Override
public void deleteVolume(final String volumeId) throws RemoteStorageOperationException {
validateNotWindows();
logger.info("Deleting volume with id " + volumeId);
safeGetRemoteStorageProvisioningDriver().deleteVolume(serviceContext.getLocationId(), volumeId);
deleteVolumeWithId(volumeId);
}
@Override
public void mount(final String volumeId, final String device, final String path, final long timeoutInMillis)
throws LocalStorageOperationException, TimeoutException {
validateNotWindows();
if (!serviceContext.isPrivileged()) {
throw new IllegalStateException("Cannot mount when not running in privileged mode");
}
logger.info("Mounting device " + device + " to mount point " + path);
VolumeUtils.mount(device, path, timeoutInMillis);
if (volumeId != null) {
changeStateOfVolumeWithId(volumeId, VolumeState.MOUNTED);
} else {
changeStateOfVolumeWithDevice(device, VolumeState.MOUNTED);
}
}
@Override
public void mount(final String volumeId, final String device, final String path)
throws LocalStorageOperationException, TimeoutException {
validateNotWindows();
if (!serviceContext.isPrivileged()) {
throw new IllegalStateException("Cannot mount when not running in privileged mode");
}
logger.info("Mounting device " + device + " to mount point " + path);
VolumeUtils.mount(device, path);
if (volumeId != null) {
changeStateOfVolumeWithId(volumeId, VolumeState.MOUNTED);
} else {
changeStateOfVolumeWithDevice(device, VolumeState.MOUNTED);
}
}
@Override
public void mount(final String device, final String path, final long timeoutInMillis)
throws LocalStorageOperationException, TimeoutException {
mount(null, device, path, timeoutInMillis);
}
@Override
public void mount(final String device, final String path)
throws LocalStorageOperationException, TimeoutException {
mount(null, device, path);
}
@Override
public void unmount(final String device, final long timeoutInMillis)
throws LocalStorageOperationException, TimeoutException {
validateNotWindows();
if (!serviceContext.isPrivileged()) {
throw new IllegalStateException("Cannot unmount when not running in privileged mode");
}
logger.info("Unmounting device " + device);
VolumeUtils.unmount(device, timeoutInMillis);
}
@Override
public void unmount(final String device)
throws LocalStorageOperationException, TimeoutException {
validateNotWindows();
if (!serviceContext.isPrivileged()) {
throw new IllegalStateException("Cannot unmount when not running in privileged mode");
}
logger.info("Unmounting device " + device);
VolumeUtils.unmount(device);
}
@Override
public StorageTemplate getTemplate(final String templateName) {
return safeGetRemoteStorageProvisioningDriver().getTemplate(templateName);
}
@Override
public void partition(final String volumeId, final String device, final long timeoutInMillis)
throws LocalStorageOperationException, TimeoutException {
validateNotWindows();
if (!serviceContext.isPrivileged()) {
throw new IllegalStateException("Cannot partition when not running in privileged mode");
}
logger.info("Partitioning device " + device);
VolumeUtils.partition(device, timeoutInMillis);
if (volumeId != null) {
changeStateOfVolumeWithId(volumeId, VolumeState.PARTITIONED);
} else {
changeStateOfVolumeWithDevice(device, VolumeState.PARTITIONED);
}
}
@Override
public void partition(final String device, final long timeoutInMillis)
throws LocalStorageOperationException, TimeoutException {
partition(null, device, timeoutInMillis);
}
@Override
public void partition(final String device) throws LocalStorageOperationException,
TimeoutException {
partition(null, device);
}
private void changeStateOfVolumeWithDevice(final String device,
final VolumeState newState) {
ServiceVolume serviceVolume = new ServiceVolume();
serviceVolume.setDevice(device);
serviceVolume.setApplicationName(serviceContext.getApplicationName());
serviceVolume.setServiceName(serviceContext.getServiceName());
serviceVolume.setIp(serviceContext.getBindAddress());
logger.fine("Changing state of volume with device " + device + " to " + newState);
managementSpace.change(serviceVolume, new ChangeSet().set("state", newState));
}
@Override
public void partition(final String volumeId, final String device)
throws LocalStorageOperationException, TimeoutException {
validateNotWindows();
if (!serviceContext.isPrivileged()) {
throw new IllegalStateException("Cannot partition when not running in privileged mode");
}
logger.info("Partitioning device " + device);
VolumeUtils.partition(device);
if (volumeId != null) {
changeStateOfVolumeWithId(volumeId, VolumeState.PARTITIONED);
} else {
changeStateOfVolumeWithDevice(device, VolumeState.PARTITIONED);
}
}
@Override
public void format(final String volumeId, final String device, final String fileSystem, final long timeoutInMillis)
throws LocalStorageOperationException, TimeoutException {
validateNotWindows();
if (!serviceContext.isPrivileged()) {
throw new IllegalStateException("Cannot format when not running in privileged mode");
}
logger.info("Formatting device " + device + " to File System " + fileSystem);
VolumeUtils.format(device, fileSystem, timeoutInMillis);
if (volumeId != null) {
changeStateOfVolumeWithId(volumeId, VolumeState.FORMATTED);
} else {
changeStateOfVolumeWithDevice(device, VolumeState.FORMATTED);
}
}
@Override
public void format(final String volumeId, final String device, final String fileSystem)
throws LocalStorageOperationException, TimeoutException {
validateNotWindows();
if (!serviceContext.isPrivileged()) {
throw new IllegalStateException("Cannot format when not running in privileged mode");
}
logger.info("Formatting device " + device + " to File System " + fileSystem);
VolumeUtils.format(device, fileSystem);
if (volumeId != null) {
changeStateOfVolumeWithId(volumeId, VolumeState.FORMATTED);
} else {
changeStateOfVolumeWithDevice(device, VolumeState.FORMATTED);
}
}
@Override
public void format(final String device, final String fileSystem, long timeoutInMillis)
throws LocalStorageOperationException, TimeoutException {
format(null, device, fileSystem, timeoutInMillis);
}
@Override
public void format(final String device, final String fileSystem)
throws LocalStorageOperationException, TimeoutException {
format(null, device, fileSystem);
}
private void validateNotWindows() {
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
throw new UnsupportedOperationException("Windows OS is not supported for Storage API");
}
}
private void deleteVolumeWithId(final String volumeId) {
managementSpace.takeById(ServiceVolume.class, volumeId);
}
private void writeNewVolume(final String volumeId) {
ServiceVolume serviceVolume = new ServiceVolume();
serviceVolume.setApplicationName(serviceContext.getApplicationName());
serviceVolume.setServiceName(serviceContext.getServiceName());
serviceVolume.setIp(serviceContext.getBindAddress());
serviceVolume.setId(volumeId);
serviceVolume.setState(VolumeState.CREATED);
logger.fine("Writing new service volume : " + serviceVolume + " to management space");
managementSpace.write(serviceVolume);
}
private void changeStateOfVolumeWithId(final String volumeId, final VolumeState newState) {
ServiceVolume serviceVolume = new ServiceVolume();
serviceVolume.setId(volumeId);
logger.fine("Changing state of volume with id " + volumeId + " to " + newState);
managementSpace.change(serviceVolume, new ChangeSet().set("state", newState));
}
private void setDeviceForVolumeWithId(final String volumeId, final String device) {
ServiceVolume serviceVolume = new ServiceVolume();
serviceVolume.setId(volumeId);
logger.fine("Changing device of volume with id " + volumeId + " to " + device);
managementSpace.change(serviceVolume, new ChangeSet().set("device", device));
}
private RemoteStorageProvisioningDriver safeGetRemoteStorageProvisioningDriver() {
if (remoteStorageProvisioningDriver == null) {
throw new IllegalStateException(
"No storage provisioning driver configured, remote provisioning calls are not possible");
}
return remoteStorageProvisioningDriver;
}
}