org.dasein.cloud.qingcloud.compute.QingCloudImage.java Source code

Java tutorial

Introduction

Here is the source code for org.dasein.cloud.qingcloud.compute.QingCloudImage.java

Source

/*
 *  *
 *  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.qingcloud.compute;

import org.apache.http.client.methods.HttpUriRequest;
import org.dasein.cloud.AsynchronousTask;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.Tag;
import org.dasein.cloud.VisibleScope;
import org.dasein.cloud.compute.AbstractImageSupport;
import org.dasein.cloud.compute.Architecture;
import org.dasein.cloud.compute.ImageCapabilities;
import org.dasein.cloud.compute.ImageClass;
import org.dasein.cloud.compute.ImageCreateOptions;
import org.dasein.cloud.compute.ImageFilterOptions;
import org.dasein.cloud.compute.MachineImage;
import org.dasein.cloud.compute.MachineImageFormat;
import org.dasein.cloud.compute.MachineImageState;
import org.dasein.cloud.compute.MachineImageSupport;
import org.dasein.cloud.compute.MachineImageType;
import org.dasein.cloud.compute.Platform;
import org.dasein.cloud.compute.VirtualMachine;
import org.dasein.cloud.qingcloud.QingCloud;
import org.dasein.cloud.qingcloud.compute.model.CaptureInstanceResponseModel;
import org.dasein.cloud.qingcloud.compute.model.DescribeImageUsersResponseModel;
import org.dasein.cloud.qingcloud.compute.model.DescribeImagesResponseModel;
import org.dasein.cloud.qingcloud.model.ResponseModel;
import org.dasein.cloud.qingcloud.model.SimpleJobResponseModel;
import org.dasein.cloud.qingcloud.util.requester.QingCloudDriverToCoreMapper;
import org.dasein.cloud.qingcloud.util.requester.QingCloudRequestBuilder;
import org.dasein.cloud.qingcloud.util.requester.QingCloudRequester;
import org.dasein.cloud.util.APITrace;
import org.dasein.cloud.util.requester.fluent.Requester;
import org.dasein.util.CalendarWrapper;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by Jeffrey Yan on 12/9/2015.
 *
 * @author Jeffrey Yan
 * @since 2016.02.1
 */
public class QingCloudImage extends AbstractImageSupport<QingCloud> implements MachineImageSupport {

    protected QingCloudImage(QingCloud provider) {
        super(provider);
    }

    @Override
    public ImageCapabilities getCapabilities() throws CloudException, InternalException {
        return new QingCloudImageCapabilities(getProvider());
    }

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

    @Override
    protected MachineImage capture(@Nonnull ImageCreateOptions options,
            @Nullable AsynchronousTask<MachineImage> task) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Image.capture");
        try {
            VirtualMachine vm = getProvider().getComputeServices().getVirtualMachineSupport()
                    .getVirtualMachine(options.getVirtualMachineId());
            if (vm == null) {
                throw new CloudException("Virtual machine not found: " + options.getVirtualMachineId());
            }

            if (!getCapabilities().canImage(vm.getCurrentState())) {
                throw new CloudException(
                        "Server must be stopped before making an image - current state: " + vm.getCurrentState());
            }

            if (task != null) {
                task.setStartTime(System.currentTimeMillis());
            }

            //Note, Qing Cloud does support capture image from a snapshot, but Dasein Cloud doesn't support it
            HttpUriRequest request = QingCloudRequestBuilder.post(getProvider()).action("CaptureInstance")
                    .parameter("instance", options.getVirtualMachineId()).parameter("image_name", options.getName())
                    .parameter("zone", getProvider().getZoneId()).build();

            Requester<CaptureInstanceResponseModel> requester = new QingCloudRequester<CaptureInstanceResponseModel, CaptureInstanceResponseModel>(
                    getProvider(), request, CaptureInstanceResponseModel.class);

            CaptureInstanceResponseModel responseModel = requester.execute();

            MachineImage image = getImage(responseModel.getImageId());

            //TODO, handle options.getReboot(), and tags
            if (task != null) {
                task.completeWithResult(image);
            }
            return image;
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void remove(@Nonnull String providerImageId, boolean checkState)
            throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Image.remove");
        try {
            if (checkState) {
                long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 30L);

                while (timeout > System.currentTimeMillis()) {
                    try {
                        MachineImage img = getMachineImage(providerImageId);

                        if (img == null || MachineImageState.DELETED.equals(img.getCurrentState())) {
                            return;
                        }
                        if (MachineImageState.ACTIVE.equals(img.getCurrentState())) {
                            break;
                        }
                    } catch (Throwable ignore) {
                        // ignore
                    }
                    try {
                        Thread.sleep(15000L);
                    } catch (InterruptedException ignore) {
                    }
                }
            }

            HttpUriRequest request = QingCloudRequestBuilder.post(getProvider()).action("DeleteImages")
                    .parameter("images.1", providerImageId).parameter("zone", getProvider().getZoneId()).build();

            Requester<SimpleJobResponseModel> requester = new QingCloudRequester<SimpleJobResponseModel, SimpleJobResponseModel>(
                    getProvider(), request, SimpleJobResponseModel.class);

            requester.execute();
        } finally {
            APITrace.end();
        }
    }

    @Nullable
    @Override
    public MachineImage getImage(@Nonnull String providerImageId) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Image.getImage");
        try {
            HttpUriRequest request = QingCloudRequestBuilder.get(getProvider()).action("DescribeImages")
                    .parameter("images.1", providerImageId).parameter("zone", getProvider().getZoneId()).build();

            Requester<List<MachineImage>> requester = new QingCloudRequester<DescribeImagesResponseModel, List<MachineImage>>(
                    getProvider(), request, new ImagesMapper(), DescribeImagesResponseModel.class);

            List<MachineImage> result = requester.execute();
            if (result.size() > 0) {
                return result.get(0);
            } else {
                return null;
            }
        } finally {
            APITrace.end();
        }
    }

    @Nonnull
    @Override
    public Iterable<MachineImage> listImages(@Nullable ImageFilterOptions options)
            throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Image.listImages");
        try {
            HttpUriRequest request = QingCloudRequestBuilder.get(getProvider()).action("DescribeImages")
                    .parameter("visibility", "private").parameter("limit", "999")
                    .parameter("zone", getProvider().getZoneId()).build();

            Requester<List<MachineImage>> requester = new QingCloudRequester<DescribeImagesResponseModel, List<MachineImage>>(
                    getProvider(), request, new ImagesMapper(), DescribeImagesResponseModel.class);

            List<MachineImage> result = new ArrayList<MachineImage>();

            for (MachineImage machineImage : requester.execute()) {
                if (options.matches(machineImage)) {
                    result.add(machineImage);
                }
            }

            return result;
        } finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull Iterable<MachineImage> searchPublicImages(@Nonnull ImageFilterOptions options)
            throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Image.searchPublicImages");
        try {
            HttpUriRequest request = QingCloudRequestBuilder.get(getProvider()).action("DescribeImages")
                    .parameter("visibility", "public").parameter("limit", "999")
                    .parameter("zone", getProvider().getZoneId()).build();

            Requester<List<MachineImage>> requester = new QingCloudRequester<DescribeImagesResponseModel, List<MachineImage>>(
                    getProvider(), request, new ImagesMapper(), DescribeImagesResponseModel.class);

            List<MachineImage> result = new ArrayList<MachineImage>();

            for (MachineImage machineImage : requester.execute()) {
                if (options.matches(machineImage)) {
                    result.add(machineImage);
                }
            }

            return result;
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void addImageShare(@Nonnull String providerImageId, @Nonnull String accountNumber)
            throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Image.addImageShare");
        try {
            HttpUriRequest request = QingCloudRequestBuilder.post(getProvider()).action("GrantImageToUsers")
                    .parameter("image", providerImageId).parameter("users.1", accountNumber)
                    .parameter("zone", getProvider().getZoneId()).build();

            Requester<ResponseModel> requester = new QingCloudRequester<ResponseModel, ResponseModel>(getProvider(),
                    request, ResponseModel.class);

            requester.execute();
        } finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull Iterable<String> listShares(@Nonnull String providerImageId)
            throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Image.listShares");
        try {
            HttpUriRequest request = QingCloudRequestBuilder.get(getProvider()).action("DescribeImageUsers")
                    .parameter("image_id", providerImageId).parameter("offset", "0").parameter("limit", "999")
                    .parameter("zone", getProvider().getZoneId()).build();

            Requester<List<String>> requester = new QingCloudRequester<DescribeImageUsersResponseModel, List<String>>(
                    getProvider(), request,
                    new QingCloudDriverToCoreMapper<DescribeImageUsersResponseModel, List<String>>() {
                        @Override
                        protected List<String> doMapFrom(DescribeImageUsersResponseModel responseModel) {
                            List<String> result = new ArrayList<String>();
                            for (DescribeImageUsersResponseModel.ImageUser imageUser : responseModel
                                    .getImageUsers()) {
                                result.add(imageUser.getUser().getUserId());
                            }
                            return result;
                        }
                    }, DescribeImageUsersResponseModel.class);

            return requester.execute();
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void removeAllImageShares(@Nonnull String providerImageId) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Image.removeAllImageShares");
        try {
            Iterable<String> shares = listShares(providerImageId);

            QingCloudRequestBuilder requestBuilder = QingCloudRequestBuilder.post(getProvider())
                    .action("RevokeImageFromUsers").parameter("image", providerImageId)
                    .parameter("zone", getProvider().getZoneId());

            Iterator<String> sharesIterator = shares.iterator();
            int index = 1;
            while (sharesIterator.hasNext()) {
                requestBuilder.parameter("users." + (index++), sharesIterator.next());
            }

            Requester<ResponseModel> requester = new QingCloudRequester<ResponseModel, ResponseModel>(getProvider(),
                    requestBuilder.build(), ResponseModel.class);

            requester.execute();
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void removeImageShare(@Nonnull String providerImageId, @Nonnull String accountNumber)
            throws CloudException, InternalException {
        APITrace.begin(getProvider(), "Image.removeImageShare");
        try {
            HttpUriRequest request = QingCloudRequestBuilder.post(getProvider()).action("RevokeImageFromUsers")
                    .parameter("image", providerImageId).parameter("users.1", accountNumber)
                    .parameter("zone", getProvider().getZoneId()).build();

            Requester<ResponseModel> requester = new QingCloudRequester<ResponseModel, ResponseModel>(getProvider(),
                    request, ResponseModel.class);

            requester.execute();
        } finally {
            APITrace.end();
        }
    }

    @Override
    public void updateTags(@Nonnull String imageId, @Nonnull Tag... tags) throws CloudException, InternalException {
        //TODO
    }

    @Override
    public void removeTags(@Nonnull String imageId, @Nonnull Tag... tags) throws CloudException, InternalException {
        //TODO
    }

    private class ImagesMapper
            extends QingCloudDriverToCoreMapper<DescribeImagesResponseModel, List<MachineImage>> {

        @Override
        protected List<MachineImage> doMapFrom(DescribeImagesResponseModel responseModel) {
            try {
                List<MachineImage> images = new ArrayList<MachineImage>();

                for (DescribeImagesResponseModel.Image imageModel : responseModel.getImages()) {
                    String ownerId = mapOwner(imageModel.getProvider(), imageModel.getOwner());
                    String regionId = getContext().getRegionId();
                    MachineImageState imageState = mapImageState(imageModel.getStatus(),
                            imageModel.getTransitionStatus());
                    Architecture architecture = mapArchitecture(imageModel.getProcessorType());
                    Platform platform = Platform.guess(imageModel.getOsFamily());

                    MachineImage machineImage = MachineImage.getInstance(ownerId, regionId, imageModel.getImageId(),
                            ImageClass.MACHINE, imageState, imageModel.getImageName(), imageModel.getDescription(),
                            architecture, platform);
                    machineImage.constrainedTo(getProvider().getZoneId());
                    machineImage.createdAt(getProvider().parseIso8601Date(imageModel.getCreateTime()).getTime());
                    machineImage.setMinimumDiskSizeGb(imageModel.getSize());

                    machineImage.withStorageFormat(MachineImageFormat.VHD);
                    machineImage.withType(MachineImageType.VOLUME);
                    machineImage.withVisibleScope(VisibleScope.ACCOUNT_DATACENTER);
                    //TODO, set tags

                    images.add(machineImage);
                }

                return images;
            } catch (Exception exception) {
                throw new RuntimeException(exception);
            }
        }

        private Architecture mapArchitecture(String architecture) {
            if ("64bit".equals(architecture)) {
                return Architecture.I64;
            } else {
                return Architecture.I32;
            }
        }

        private String mapOwner(String provider, String owner) {
            if ("system".equals(provider)) {
                return provider;
            } else { //self or may be other
                return owner;
            }
        }

        private MachineImageState mapImageState(String state, String transitionState) {
            if (transitionState != null && !transitionState.equals("")) {
                return MachineImageState.PENDING;
            }

            if ("pending".equals(state)) {
                return MachineImageState.PENDING;
            } else if ("available".equals(state)) {
                return MachineImageState.ACTIVE;
            } else if ("deprecated".equals(state) || "suspended".equals(state)) {
                return MachineImageState.ERROR;
            } else if ("deleted".equals(state) || "ceased".equals(state)) {
                return MachineImageState.DELETED;
            } else {
                return null;
            }
        }
    }
}