All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dasein.cloud.aws.compute.EBSVolume Maven / Gradle / Ivy

There is a newer version: 2015.10.9
Show newest version
/**
 * Copyright (C) 2009-2015 Dell, Inc.
 * See annotations for authorship information
 *
 * ====================================================================
 * 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.dasein.cloud.aws.compute;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import org.apache.log4j.Logger;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.OperationNotSupportedException;
import org.dasein.cloud.ProviderContext;
import org.dasein.cloud.Requirement;
import org.dasein.cloud.ResourceStatus;
import org.dasein.cloud.Tag;
import org.dasein.cloud.aws.AWSCloud;
import org.dasein.cloud.aws.model.*;
import org.dasein.cloud.compute.*;
import org.dasein.cloud.compute.VolumeProduct;
import org.dasein.cloud.dc.DataCenter;
import org.dasein.cloud.identity.ServiceAction;
import org.dasein.cloud.util.APITrace;
import org.dasein.cloud.util.Cache;
import org.dasein.cloud.util.CacheLevel;
import org.dasein.util.uom.storage.Gigabyte;
import org.dasein.util.uom.storage.Storage;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public class EBSVolume extends AbstractVolumeSupport {
	static private final Logger logger = Logger.getLogger(EBSVolume.class);

    static private final String VOLUME_PRODUCT_IOPS = "io1";

    private EBSVolumeCapabilities capabilities;

    EBSVolume(AWSCloud provider) {
        super(provider);
	}

	@Override
	public void attach(@Nonnull String volumeId, @Nonnull String toServer, @Nullable String device) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "Volume.attach");
        try {
            Map parameters = getProvider().getStandardParameters(getProvider().getContext(), EC2Method.ATTACH_VOLUME);
            EC2Method method;

            parameters.put("VolumeId", volumeId);
            parameters.put("InstanceId", toServer);
            parameters.put("Device", device);
            method = new EC2Method(getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                logger.error(e.getSummary());
                throw new CloudException(e);
            }
        }
        finally {
            APITrace.end();
        }
	}

    @Override
    public @Nonnull String createVolume(@Nonnull VolumeCreateOptions options) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "Volume.createVolume");
        try {
            if( !options.getFormat().equals(VolumeFormat.BLOCK)) {
                throw new OperationNotSupportedException("NFS volumes are not currently supported");
            }
            ProviderContext ctx = getProvider().getContext();

            if( ctx == null ) {
                throw new InternalException("No context was specified for this request");
            }
            Map parameters = getProvider().getStandardParameters(ctx, EC2Method.CREATE_VOLUME);
            EC2Method method;
            NodeList blocks;
            Document doc;

            if( options.getSnapshotId() != null ) {
                parameters.put("SnapshotId", options.getSnapshotId());
            }
            parameters.put("Size", String.valueOf(options.getVolumeSize().getQuantity().intValue()));

            String az = options.getDataCenterId();

            if( az == null ) {
                for( DataCenter dc : getProvider().getDataCenterServices().listDataCenters(ctx.getRegionId()) ) {
                    az = dc.getProviderDataCenterId();
                }
                if( az == null ) {
                    throw new CloudException("Unable to identify a launch data center");
                }
            }
            parameters.put("AvailabilityZone", az);
            if( getProvider().getEC2Provider().isAWS() || getProvider().getEC2Provider().isEnStratus() ) {
                if( options.getVolumeProductId() != null ) {
                    VolumeProduct prd = getVolumeProduct( options.getVolumeProductId() );
                    if( prd != null ) {
                        parameters.put("VolumeType", prd.getProviderProductId());
                        if ( VOLUME_PRODUCT_IOPS.equals( prd.getProviderProductId() ) ) {
                            if ( prd.getMaxIops() > 0 && options.getIops() > 0 ) {
                                parameters.put( "Iops", String.valueOf( options.getIops() ) );
                            }
                            else if ( prd.getMinIops() > 0 ) {
                                parameters.put( "Iops", String.valueOf( prd.getMinIops() ) );
                            }
                        }
                    }
                }
            }
            method = new EC2Method(getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                logger.error(e.getSummary());
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("volumeId");
            if( blocks.getLength() > 0 ) {
                String id = blocks.item(0).getFirstChild().getNodeValue().trim();
                Map meta = options.getMetaData();

                meta.put("Name", options.getName());
                meta.put("Description", options.getDescription());
                ArrayList tags = new ArrayList();

                for( Map.Entry entry : meta.entrySet() ) {
                    Object value = entry.getValue();

                    if( value != null ) {
                        tags.add(new Tag(entry.getKey(), value.toString()));
                    }
                }
                if( !tags.isEmpty() ) {
                    getProvider().createTags(EC2Method.SERVICE_ID, id, tags.toArray(new Tag[tags.size()]));
                }
                return id;
            }
            throw new CloudException("Successful POST, but no volume information was provided");
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public void detach(@Nonnull String volumeId, boolean force) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "Volume.detach");
        try {
            Map parameters = getProvider().getStandardParameters(getProvider().getContext(), EC2Method.DETACH_VOLUME);
            EC2Method method;
            NodeList blocks;
            Document doc;

            parameters.put("VolumeId", volumeId);
            if( force ) {
                parameters.put("Force", "true");
            }
            method = new EC2Method(getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                logger.error(e.getSummary());
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("return");
            if( blocks.getLength() > 0 ) {
                if( !blocks.item(0).getFirstChild().getNodeValue().equalsIgnoreCase("true") ) {
                    throw new CloudException("Detach of volume denied.");
                }
            }
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public VolumeCapabilities getCapabilities() {
        if( capabilities == null ) {
            capabilities = new EBSVolumeCapabilities(getProvider());
        }
        return capabilities;
    }

    @Override
    public int getMaximumVolumeCount() throws InternalException, CloudException {
        return getCapabilities().getMaximumVolumeCount();
    }

    @Override
    public @Nullable Storage getMaximumVolumeSize() throws InternalException, CloudException {
        return getCapabilities().getMaximumVolumeSize();
    }

    @Override
    public @Nonnull Storage getMinimumVolumeSize() throws InternalException, CloudException {
        return getCapabilities().getMinimumVolumeSize();
    }

    @Override
	public @Nonnull String getProviderTermForVolume(@Nonnull Locale locale) {
		return getCapabilities().getProviderTermForVolume(locale);
	}

    @Override
    public boolean isSubscribed() throws CloudException, InternalException {
        return true;
    }
    
    @Override
    public @Nonnull Iterable listPossibleDeviceIds(@Nonnull Platform platform) throws InternalException, CloudException {
        return getCapabilities().listPossibleDeviceIds(platform);
    }

    @Override
    public @Nonnull Iterable listSupportedFormats() throws InternalException, CloudException {
        return getCapabilities().listSupportedFormats();
    }

    @Override
    public @Nonnull Iterable listVolumeProducts() throws InternalException, CloudException {
        VolumeProvider volumeProvider = VolumeProvider.fromFile("/org/dasein/cloud/aws/volproducts.json", "AWS");
        String regionId = getContext().getRegionId();
        List products = volumeProvider.getProducts();
        List volumeProducts = new ArrayList();
        for ( org.dasein.cloud.aws.model.VolumeProduct product : products ) {
            VolumePrice price = volumeProvider.findProductPrice(regionId, product.getId());
            if( price == null ) {
                continue;
            }
            VolumeProduct volumeProduct = VolumeProduct.getInstance(product.getId(), product.getName(), product.getDescription(), VolumeType.valueOf(product.getType().toUpperCase()), product.getMinIops(), product.getMaxIops(), price.getMonthly(), price.getIops() );
            volumeProduct.withMaxIopsRatio(product.getIopsToGb());
            volumeProduct.withMaxVolumeSize(new Storage(product.getMaxSize(), Storage.GIGABYTE));
            volumeProduct.withMinVolumeSize(new Storage(product.getMinSize(), Storage.GIGABYTE));
            volumeProducts.add(volumeProduct);
        }
        return volumeProducts;
    }

    @Override
	public @Nullable Volume getVolume(@Nonnull String volumeId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "Volume.getVolume");
        try {
            ProviderContext ctx = getProvider().getContext();

            if( ctx == null ) {
                throw new CloudException("No context exists for this request.");
            }
            Map parameters = getProvider().getStandardParameters(getProvider().getContext(), EC2Method.DESCRIBE_VOLUMES);
            EC2Method method;
            NodeList blocks;
            Document doc;

            parameters.put("VolumeId.1", volumeId);
            method = new EC2Method(getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                String code = e.getCode();

                if( code != null && (code.startsWith("InvalidVolume.NotFound") || code.equals("InvalidParameterValue")) ) {
                    return null;
                }
                logger.error(e.getSummary());
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("volumeSet");
            for( int i=0; i listVolumeStatus() throws InternalException, CloudException {
        APITrace.begin(getProvider(), "Volume.listVolumeStatus");
        try {
            ProviderContext ctx = getProvider().getContext();

            if( ctx == null ) {
                throw new CloudException("No context exists for this request.");
            }
            Map parameters = getProvider().getStandardParameters(getProvider().getContext(), EC2Method.DESCRIBE_VOLUMES);
            ArrayList list = new ArrayList();
            EC2Method method;
            NodeList blocks;
            Document doc;

            method = new EC2Method(getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                logger.error(e.getSummary());
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("volumeSet");
            for( int i=0; i listVolumes() throws InternalException, CloudException {
        return listVolumes( null );
    }

    @Override
    public @Nonnull Iterable listVolumes(@Nullable VolumeFilterOptions options) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "Volume.listVolumes");
        try {
            ProviderContext ctx = getProvider().getContext();

            if( ctx == null ) {
                throw new CloudException("No context exists for this request.");
            }
            Map parameters = getProvider().getStandardParameters(getProvider().getContext(), EC2Method.DESCRIBE_VOLUMES);
            ArrayList list = new ArrayList();
            EC2Method method;
            NodeList blocks;
            Document doc;

            if ( options != null ) {
                AWSCloud.addExtraParameters( parameters, getProvider().getTagFilterParams( options.getTags() ) );
            }

            method = new EC2Method( getProvider(), parameters );
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                logger.error(e.getSummary());
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("volumeSet");
            for( int i=0; i parameters = getProvider().getStandardParameters(getProvider().getContext(), EC2Method.DELETE_VOLUME);
            EC2Method method;
            NodeList blocks;
            Document doc;

            parameters.put("VolumeId", volumeId);
            method = new EC2Method(getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                logger.error(e.getSummary());
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("return");
            if( blocks.getLength() > 0 ) {
                if( !blocks.item(0).getFirstChild().getNodeValue().equalsIgnoreCase("true") ) {
                    throw new CloudException("Deletion of volume denied.");
                }
            }
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public void updateTags(@Nonnull String volumeId, @Nonnull Tag ... tags) throws CloudException, InternalException {
        updateTags(new String[] { volumeId }, tags);
    }

    @Override
    public void updateTags(@Nonnull String[] volumeIds, @Nonnull Tag... tags) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Volume.updateTags");
        try {
            getProvider().createTags(EC2Method.SERVICE_ID, volumeIds, tags);
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public void removeTags(@Nonnull String volumeId, @Nonnull Tag ... tags) throws CloudException, InternalException {
        removeTags(new String[]{volumeId}, tags);
    }

    @Override
    public void removeTags(@Nonnull String[] volumeIds, @Nonnull Tag... tags) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Volume.removeTags");
        try {
            getProvider().removeTags(EC2Method.SERVICE_ID, volumeIds, tags);
        }
        finally {
            APITrace.end();
        }
    }

    public VolumeProduct getVolumeProduct(String volumeProductId) throws InternalException, CloudException{
      VolumeProduct prd = null;

      for ( VolumeProduct p : listVolumeProducts() ) {
        if ( p.getProviderProductId().equals( volumeProductId ) ) {
          prd = p;
          break;
        }
      }

      return prd;
    }

    private @Nullable ResourceStatus toStatus(@Nullable Node node) throws CloudException {
        if( node == null ) {
            return null;
        }
        NodeList attrs = node.getChildNodes();
        VolumeState state = VolumeState.PENDING;
        String volumeId = null;

        for( int i=0; i(size, Storage.GIGABYTE));
            }
            else if( name.equals("snapshotId") ) {
                NodeList values = attr.getChildNodes();

                if( values != null && values.getLength() > 0 ) {
                    volume.setProviderSnapshotId(values.item(0).getNodeValue().trim());
                }
            }
            else if( name.equals("availabilityZone") ) {
                String zoneId = attr.getFirstChild().getNodeValue().trim();

                volume.setProviderDataCenterId(zoneId);
            }
            else if( name.equalsIgnoreCase("volumeType") && attr.hasChildNodes() ) {
                volume.setProviderProductId(attr.getFirstChild().getNodeValue().trim());
            }
            else if( name.equalsIgnoreCase("iops") && attr.hasChildNodes() ) {
                volume.setIops(Integer.parseInt(attr.getFirstChild().getNodeValue().trim()));
            }
			else if( name.equals("createTime") ) {
				SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
				String value = attr.getFirstChild().getNodeValue().trim();

				try {
					volume.setCreationTimestamp(fmt.parse(value).getTime());
				} 
				catch( ParseException e ) {
					logger.error(e);
					e.printStackTrace();
					throw new CloudException(e);
				}				
			}
			else if( name.equals("status") ) {
        volume.setCurrentState( toVolumeState( attr ) );
      }
            else if( name.equals("tagSet") ) {
                getProvider().setTags(attr, volume);

                String s = volume.getTag("Name");

                if( s != null && volume.getName() == null ) {
                    volume.setName(s);
                }
                s = volume.getTag("Description");

                if( s != null && volume.getDescription() == null ) {
                    volume.setDescription(s);
                }
            }
			else if( name.equals("attachmentSet") ) {
				NodeList attachments = attr.getChildNodes();
				
				for( int j=0; j




© 2015 - 2024 Weber Informatics LLC | Privacy Policy