org.dasein.cloud.google.compute.server.SnapshotSupport.java Source code

Java tutorial

Introduction

Here is the source code for org.dasein.cloud.google.compute.server.SnapshotSupport.java

Source

/**
 * Copyright (C) 2012-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.google.compute.server;

import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.services.compute.Compute;
import com.google.api.services.compute.model.*;
import org.apache.log4j.Logger;
import org.dasein.cloud.*;
import org.dasein.cloud.compute.*;
import org.dasein.cloud.compute.Snapshot;
import org.dasein.cloud.google.GoogleException;
import org.dasein.cloud.google.GoogleMethod;
import org.dasein.cloud.google.GoogleOperationType;
import org.dasein.cloud.google.capabilities.GCESnapshotCapabilities;
import org.dasein.cloud.google.Google;
import org.dasein.cloud.util.APITrace;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

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

import java.io.IOException;
import java.util.*;

/**
 * Implements the snapshot services supported in the Google API.
 * @author Drew Lyall
 * @version 2014.03 initial version
 * @since 2014.03
 */

public class SnapshotSupport extends AbstractSnapshotSupport {
    static private final Logger logger = Google.getLogger(SnapshotSupport.class);
    private Google provider;

    public SnapshotSupport(Google provider) {
        super(provider);
        this.provider = provider;
    }

    @Override
    public void addSnapshotShare(@Nonnull String providerSnapshotId, @Nonnull String accountNumber)
            throws CloudException, InternalException {
        throw new OperationNotSupportedException("Google does not support sharing a snapshot across accounts.");

    }

    @Override
    public void addPublicShare(@Nonnull String providerSnapshotId) throws CloudException, InternalException {
        throw new OperationNotSupportedException("Google does not support sharing a snapshot across accounts.");
    }

    @Override
    public String createSnapshot(@Nonnull SnapshotCreateOptions options) throws CloudException, InternalException {
        APITrace.begin(provider, "Snapshot.createSnapshot");
        try {
            Compute gce = provider.getGoogleCompute();
            try {
                Volume volume = provider.getComputeServices().getVolumeSupport().getVolume(options.getVolumeId());

                com.google.api.services.compute.model.Snapshot snapshot = new com.google.api.services.compute.model.Snapshot();
                snapshot.setName(getCapabilities().getSnapshotNamingConstraints()
                        .convertToValidName(options.getName(), Locale.US));
                snapshot.setDescription(options.getDescription());
                snapshot.setSourceDiskId(options.getVolumeId());

                Operation job = gce.disks().createSnapshot(provider.getContext().getAccountNumber(),
                        volume.getProviderDataCenterId(), options.getVolumeId(), snapshot).execute();
                GoogleMethod method = new GoogleMethod(provider);
                if (method.getOperationComplete(provider.getContext(), job, GoogleOperationType.ZONE_OPERATION, "",
                        volume.getProviderDataCenterId())) {
                    SnapshotList snapshots = gce.snapshots().list(provider.getContext().getAccountNumber())
                            .setFilter("name eq " + options.getName()).execute();
                    for (com.google.api.services.compute.model.Snapshot s : snapshots.getItems()) {
                        if (s.getName().equals(options.getName()))
                            return s.getName();
                    }
                }
                throw new CloudException("An error occurred creating the snapshot: Operation Timedout");
            } catch (IOException ex) {
                logger.error(ex.getMessage());
                if (ex.getClass() == GoogleJsonResponseException.class) {
                    GoogleJsonResponseException gjre = (GoogleJsonResponseException) ex;
                    throw new GoogleException(CloudErrorType.GENERAL, gjre.getStatusCode(), gjre.getContent(),
                            gjre.getDetails().getMessage());
                } else
                    throw new CloudException("An error occurred creating the snapshot: " + ex.getMessage());
            } catch (Exception ex) {
                throw new OperationNotSupportedException("Copying snapshots is not supported in GCE");
            }
        } finally {
            APITrace.end();
        }
    }

    private transient volatile GCESnapshotCapabilities capabilities;

    @Override
    public @Nonnull GCESnapshotCapabilities getCapabilities() {
        if (capabilities == null) {
            capabilities = new GCESnapshotCapabilities(provider);
        }
        return capabilities;
    }

    @Override
    public @Nonnull String getProviderTermForSnapshot(@Nonnull Locale locale) {
        return "snapshot";
    }

    @Override
    public Snapshot getSnapshot(@Nonnull String snapshotId) throws InternalException, CloudException {
        APITrace.begin(provider, "Snapshot.getSnapshot");
        try {
            Compute gce = provider.getGoogleCompute();
            try {
                com.google.api.services.compute.model.Snapshot snapshot = gce.snapshots()
                        .get(provider.getContext().getAccountNumber(), snapshotId).execute();
                return toSnapshot(snapshot);
            } catch (IOException ex) {
                if ((ex.getMessage() != null) && (ex.getMessage().contains("404 Not Found"))) // not found.
                    return null;
                logger.error(ex.getMessage());
                if (ex.getClass() == GoogleJsonResponseException.class) {
                    GoogleJsonResponseException gjre = (GoogleJsonResponseException) ex;
                    throw new GoogleException(CloudErrorType.GENERAL, gjre.getStatusCode(), gjre.getContent(),
                            gjre.getDetails().getMessage());
                } else
                    throw new CloudException("An error occurred getting the snapshot: " + ex.getMessage());
            }
        } finally {
            APITrace.end();
        }
    }

    @Override
    public boolean isPublic(@Nonnull String snapshotId) throws InternalException, CloudException {
        return false;
    }

    @Override
    public boolean isSubscribed() throws InternalException, CloudException {
        return true;
    }

    @Override
    public @Nonnull Iterable<String> listShares(@Nonnull String snapshotId)
            throws InternalException, CloudException {
        return Collections.emptyList();
    }

    @Override
    public @Nonnull Iterable<ResourceStatus> listSnapshotStatus() throws InternalException, CloudException {
        APITrace.begin(provider, "Snapshot.listSnapshotStatus");
        try {
            ArrayList<ResourceStatus> statuses = new ArrayList<ResourceStatus>();
            Compute gce = provider.getGoogleCompute();
            try {
                SnapshotList list = gce.snapshots().list(provider.getContext().getAccountNumber()).execute();
                if (list != null && list.size() > 0) {
                    for (com.google.api.services.compute.model.Snapshot googleSnapshot : list.getItems()) {
                        ResourceStatus status = toStatus(googleSnapshot);
                        if (status != null)
                            statuses.add(status);
                    }
                }
                return statuses;
            } catch (IOException ex) {
                logger.error(ex.getMessage());
                if (ex.getClass() == GoogleJsonResponseException.class) {
                    GoogleJsonResponseException gjre = (GoogleJsonResponseException) ex;
                    throw new GoogleException(CloudErrorType.GENERAL, gjre.getStatusCode(), gjre.getContent(),
                            gjre.getDetails().getMessage());
                } else
                    throw new CloudException("An error occurred retrieving snapshot status");
            }
        } finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull Iterable<Snapshot> listSnapshots() throws InternalException, CloudException {
        APITrace.begin(provider, "Snapshot.listSnapshots");
        try {
            ArrayList<Snapshot> snapshots = new ArrayList<Snapshot>();
            Compute gce = provider.getGoogleCompute();
            try {
                SnapshotList list = gce.snapshots().list(provider.getContext().getAccountNumber()).execute();
                if (list != null && list.getItems() != null && list.getItems().size() > 0) {
                    for (com.google.api.services.compute.model.Snapshot googleSnapshot : list.getItems()) {
                        Snapshot snapshot = toSnapshot(googleSnapshot);
                        if (snapshot != null)
                            snapshots.add(snapshot);
                    }
                }
                return snapshots;
            } catch (IOException ex) {
                logger.error(ex.getMessage());
                if (ex.getClass() == GoogleJsonResponseException.class) {
                    GoogleJsonResponseException gjre = (GoogleJsonResponseException) ex;
                    throw new GoogleException(CloudErrorType.GENERAL, gjre.getStatusCode(), gjre.getContent(),
                            gjre.getDetails().getMessage());
                } else
                    throw new CloudException("An error occurred while listing snapshots: " + ex.getMessage());
            }
        } finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull Iterable<Snapshot> listSnapshots(SnapshotFilterOptions options)
            throws InternalException, CloudException {
        return searchSnapshots(options);
    }

    @Override
    public void remove(@Nonnull String snapshotId) throws InternalException, CloudException {
        APITrace.begin(provider, "Snapshot.remove");
        try {
            Compute gce = provider.getGoogleCompute();
            try {
                Operation job = gce.snapshots().delete(provider.getContext().getAccountNumber(), snapshotId)
                        .execute();

                GoogleMethod method = new GoogleMethod(provider);
                if (!method.getOperationComplete(provider.getContext(), job, GoogleOperationType.GLOBAL_OPERATION,
                        "", "")) {
                    throw new CloudException("An error occurred deleting the snapshot: Operation timed out");
                }
            } catch (IOException ex) {
                if (ex.getClass() == GoogleJsonResponseException.class) {
                    logger.error(ex.getMessage());
                    GoogleJsonResponseException gjre = (GoogleJsonResponseException) ex;
                    throw new GoogleException(CloudErrorType.GENERAL, gjre.getStatusCode(), gjre.getContent(),
                            gjre.getDetails().getMessage());
                } else
                    throw new CloudException("An error occurred deleting the snapshot: " + ex.getMessage());
            }
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void removeAllSnapshotShares(@Nonnull String providerSnapshotId)
            throws CloudException, InternalException {
        // NOP in clouds without sharing
    }

    @Override
    public void removeSnapshotShare(@Nonnull String providerSnapshotId, @Nonnull String accountNumber)
            throws CloudException, InternalException {
        throw new OperationNotSupportedException(
                "Google does not support sharing/unsharing a snapshot across accounts.");

    }

    @Override
    public void removePublicShare(@Nonnull String providerSnapshotId) throws CloudException, InternalException {
        throw new OperationNotSupportedException(
                "Google does not support sharing/unsharing a snapshot across accounts.");

    }

    @Override
    public void removeTags(@Nonnull String snapshotId, @Nonnull Tag... tags)
            throws CloudException, InternalException {
        throw new OperationNotSupportedException("Google snapshot does not contain meta data");

    }

    @Override
    public void removeTags(@Nonnull String[] snapshotIds, @Nonnull Tag... tags)
            throws CloudException, InternalException {
        throw new OperationNotSupportedException("Google snapshot does not contain meta data");
    }

    @Override
    public @Nonnull Iterable<Snapshot> searchSnapshots(@Nonnull SnapshotFilterOptions options)
            throws InternalException, CloudException {
        APITrace.begin(provider, "Snapshot.searchSnapshots");
        try {
            ArrayList<Snapshot> snapshots = new ArrayList<Snapshot>();
            for (Snapshot snapshot : listSnapshots()) {
                if (options == null || options.matches(snapshot, null)) {
                    snapshots.add(snapshot);
                }
            }
            return snapshots;
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void updateTags(@Nonnull String snapshotId, @Nonnull Tag... tags)
            throws CloudException, InternalException {
        throw new OperationNotSupportedException("Google snapshot does not contain meta data");
    }

    @Override
    public void updateTags(@Nonnull String[] snapshotIds, @Nonnull Tag... tags)
            throws CloudException, InternalException {
        throw new OperationNotSupportedException("Google snapshot does not contain meta data");
    }

    private @Nullable Snapshot toSnapshot(com.google.api.services.compute.model.Snapshot googleSnapshot) {
        Snapshot snapshot = new Snapshot();
        snapshot.setProviderSnapshotId(googleSnapshot.getName());
        snapshot.setName(googleSnapshot.getName());
        snapshot.setDescription(googleSnapshot.getDescription());
        snapshot.setOwner(provider.getContext().getAccountNumber());
        SnapshotState state = SnapshotState.PENDING;
        if (googleSnapshot.getStatus().equals("READY"))
            state = SnapshotState.AVAILABLE;
        else if (googleSnapshot.getStatus().equals("DELETING"))
            state = SnapshotState.DELETED;
        snapshot.setCurrentState(state);
        //TODO: Set visible scope for snapshots
        snapshot.setSizeInGb(googleSnapshot.getDiskSizeGb().intValue());

        DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
        DateTime dt = DateTime.parse(googleSnapshot.getCreationTimestamp(), fmt);
        snapshot.setSnapshotTimestamp(dt.toDate().getTime());

        String sourceDisk = googleSnapshot.getSourceDisk();
        if (sourceDisk != null) {
            snapshot.setVolumeId(sourceDisk.substring(sourceDisk.lastIndexOf("/") + 1));
        }

        return snapshot;
    }

    private @Nullable ResourceStatus toStatus(@Nullable com.google.api.services.compute.model.Snapshot snapshot)
            throws CloudException {
        SnapshotState state;
        if (snapshot.getStatus().equals("READY")) {
            state = SnapshotState.AVAILABLE;
        } else if (snapshot.getStatus().equals("DELETING")) {
            state = SnapshotState.DELETED;
        } else
            state = SnapshotState.PENDING;

        return new ResourceStatus(snapshot.getName(), state);
    }
}