org.dasein.cloud.azure.compute.image.AzureOSImage.java Source code

Java tutorial

Introduction

Here is the source code for org.dasein.cloud.azure.compute.image.AzureOSImage.java

Source

/**
 * Copyright (C) 2012 enStratus Networks Inc
 *
 * ====================================================================
 * 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.azure.compute.image;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.dasein.cloud.AsynchronousTask;
import org.dasein.cloud.CloudErrorType;
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.azure.Azure;
import org.dasein.cloud.azure.AzureConfigException;
import org.dasein.cloud.azure.AzureMethod;
import org.dasein.cloud.azure.AzureService;
import org.dasein.cloud.azure.compute.vm.AzureVM;
import org.dasein.cloud.compute.AbstractImageSupport;
import org.dasein.cloud.compute.Architecture;
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.compute.VmState;
import org.dasein.cloud.identity.ServiceAction;
import org.dasein.util.CalendarWrapper;
import org.dasein.util.Jiterator;
import org.dasein.util.JiteratorPopulator;
import org.dasein.util.PopulatorThread;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;

/**
 * Implements support for Azure OS images through the Dasein Cloud machine image API.
 * @author George Reese (george.reese@imaginary.com)
 * @since 2012.04.1
 * @version 2012.04.1
 */
public class AzureOSImage implements MachineImageSupport {
    static private final Logger logger = Azure.getLogger(AzureOSImage.class);

    static private final String IMAGES = "/services/images";
    static private final String MICROSOFT = "--microsoft--";

    private Azure provider;

    public AzureOSImage(Azure provider) {
        this.provider = provider;
    }

    @Override
    public void bundleVirtualMachineAsync(@Nonnull String virtualMachineId, @Nonnull MachineImageFormat format,
            @Nonnull String bucket, @Nonnull String name, @Nonnull AsynchronousTask<String> trackingTask)
            throws CloudException, InternalException {
        throw new OperationNotSupportedException("No ability to bundle vms");
    }

@Override
protected @Nonnull MachineImage capture(@Nonnull ImageCreateOptions options, @Nullable AsynchronousTask<MachineImage> task) throws CloudException, InternalException {
    logger.debug("Capture image of "+options.getVirtualMachineId()+" with new name "+options.getName());
    try {
        if( task != null ) {
            task.setStartTime(System.currentTimeMillis());
        }

        String vmid = options.getVirtualMachineId();
        String name = options.getName();
        String description = options.getDescription();

        VirtualMachine vm;

        vm = provider.getComputeServices().getVirtualMachineSupport().getVirtualMachine(options.getVirtualMachineId());
        if (vm == null) {
            throw new CloudException("Virtual machine not found: " + options.getVirtualMachineId());
        }
        if (!vm.getCurrentState().equals(VmState.STOPPED)) {
            logger.debug("Stopping server");
            provider.getComputeServices().getVirtualMachineSupport().stop(vmid, false);
            try {
                long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 10L);
                vm = null;
                while (timeout > System.currentTimeMillis()) {
                    vm =  provider.getComputeServices().getVirtualMachineSupport().getVirtualMachine(options.getVirtualMachineId());
                    if (vm.getCurrentState().equals(VmState.STOPPED)) {
                        logger.debug("Server stopped");
                        break;
                    }
                    try { Thread.sleep(15000L); }
                    catch( InterruptedException ignore ) { }
                }
            }
            catch (Throwable ignore) {
            }
        }
        try {
            ProviderContext ctx = provider.getContext();

            if( ctx == null ) {
                throw new AzureConfigException("No context was set for this request");
            }

            String vmId = vm.getProviderVirtualMachineId();
            String serviceName, deploymentName, roleName;

            serviceName = vm.getTag("serviceName").toString();
            deploymentName = vm.getTag("deploymentName").toString();
            roleName = vm.getTag("roleName").toString();

            String resourceDir = AzureVM.HOSTED_SERVICES + "/" + serviceName + "/deployments/" +  deploymentName + "/roleInstances/" + roleName + "/Operations";
            AzureMethod method = new AzureMethod(provider);
            StringBuilder xml = new StringBuilder();

            xml.append("<CaptureRoleOperation xmlns=\"http://schemas.microsoft.com/windowsazure\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">");
            xml.append("<OperationType>CaptureRoleOperation</OperationType>\n");
            xml.append("<PostCaptureAction>Delete</PostCaptureAction>\n");
            xml.append("<TargetImageLabel>").append(name).append("</TargetImageLabel>\n");
            xml.append("<TargetImageName>").append(name).append("</TargetImageName>\n");
            xml.append("</CaptureRoleOperation>\n");

            method.post(ctx.getAccountNumber(), resourceDir, xml.toString());

            MachineImage img = getMachineImage(name);

            if (img == null) {
                throw new CloudException("Drive cloning completed, but no ID was provided for clone");
            }if( task != null ) {
                task.completeWithResult(img);
            }
            return img;
        }
        finally {
            if( logger.isTraceEnabled() ) {
                logger.trace("EXIT: " + AzureOSImage.class.getName() + ".launch()");
            }
        }
    };

    t.setName("Image " + options.getVirtualMachineId());
    t.setDaemon(true);
    t.start();
}

    @Override
    public MachineImage getImage(@Nonnull String machineImageId) throws CloudException, InternalException {
        final ProviderContext ctx = provider.getContext();

        if (ctx == null) {
            throw new AzureConfigException("No context was specified for this request");
        }

        PopulatorThread<MachineImage> populator;

        provider.hold();
        populator = new PopulatorThread<MachineImage>(new JiteratorPopulator<MachineImage>() {
            public void populate(@Nonnull Jiterator<MachineImage> iterator)
                    throws CloudException, InternalException {
                try {

                    populateImages(ctx, iterator, MICROSOFT, ctx.getAccountNumber(), "--public--", "--Canonical--",
                            "--RightScaleLinux--", "--RightScaleWindows--", "--OpenLogic--", "--SUSE--");
                } finally {
                    provider.release();
                }
            }
        });
        populator.populate();
        for (MachineImage img : populator.getResult()) {
            if (machineImageId.equals(img.getProviderMachineImageId())) {
                logger.debug("Found image i'm looking for " + machineImageId);
                img.setImageClass(ImageClass.MACHINE);
                return (AzureMachineImage) img;
            }
        }
        return null;
    }

    @Override
    public @Nonnull String getProviderTermForImage(@Nonnull Locale locale) {
        return "OS image";
    }

    @Nonnull
    @Override
    public String getProviderTermForImage(@Nonnull Locale locale, @Nonnull ImageClass cls) {
        return "OS image";
    }

    @Nonnull
    @Override
    public String getProviderTermForCustomImage(@Nonnull Locale locale, @Nonnull ImageClass cls) {
        return "OS image";
    }

    @Override
    public boolean hasPublicLibrary() {
        return true;
    }

    @Nonnull
    @Override
    public Requirement identifyLocalBundlingRequirement() throws CloudException, InternalException {
        return Requirement.NONE;
    }

    @Override
    public boolean isImageSharedWithPublic(@Nonnull String machineImageId)
            throws CloudException, InternalException {
        MachineImage img = getMachineImage(machineImageId);

        return (img != null && (MICROSOFT.equals(img.getProviderOwnerId())
                || "--public--".equals(img.getProviderOwnerId()) || "--Canonical--".equals(img.getProviderOwnerId())
                || "--RightScaleLinux--".equals(img.getProviderOwnerId())
                || "--RightScaleWindows--".equals(img.getProviderOwnerId())
                || "--OpenLogic--".equals(img.getProviderOwnerId())
                || "--SUSE--".equals(img.getProviderOwnerId())));
    }

    @Override
    public boolean isSubscribed() throws CloudException, InternalException {
        return provider.getDataCenterServices().isSubscribed(AzureService.COMPUTE);
    }

    @Nonnull
    @Override
    public Iterable<ResourceStatus> listImageStatus(@Nonnull ImageClass cls)
            throws CloudException, InternalException {
        if (!cls.equals(ImageClass.MACHINE)) {
            return Collections.emptyList();
        }

        final ProviderContext ctx = provider.getContext();

        if (ctx == null) {
            throw new AzureConfigException("No context was specified for this request");
        }

        ArrayList<ResourceStatus> list = new ArrayList<ResourceStatus>();

        final String owner = ctx.getAccountNumber();

        AzureMethod method = new AzureMethod(provider);

        Document doc = method.getAsXML(ctx.getAccountNumber(), IMAGES);

        if (doc == null) {
            throw new CloudException(CloudErrorType.AUTHENTICATION, HttpServletResponse.SC_FORBIDDEN,
                    "Illegal Access", "Illegal access to requested resource");
        }
        NodeList entries = doc.getElementsByTagName("OSImage");

        for (int i = 0; i < entries.getLength(); i++) {
            Node entry = entries.item(i);
            ResourceStatus status = toStatus(ctx, entry);

            if (status != null) {
                list.add(status);
            }
        }
        return list;
    }

    public ResourceStatus toStatus(@Nonnull ProviderContext ctx, @Nullable Node entry)
            throws CloudException, InternalException {
        String regionId = ctx.getRegionId();
        String id = "";

        NodeList attributes = entry.getChildNodes();
        for (int j = 0; j < attributes.getLength(); j++) {
            Node attribute = attributes.item(j);
            if (attribute.getNodeType() == Node.TEXT_NODE)
                continue;
            String nodeName = attribute.getNodeName();

            if (nodeName.equalsIgnoreCase("name") && attribute.hasChildNodes()) {
                id = (attribute.getFirstChild().getNodeValue().trim());
            } else if (nodeName.equalsIgnoreCase("category") && attribute.hasChildNodes()) {
                if (!"user".equalsIgnoreCase(attribute.getFirstChild().getNodeValue().trim())) {
                    return null;
                }
            } else if (nodeName.equalsIgnoreCase("location") && attribute.hasChildNodes()) {
                if (!regionId.equalsIgnoreCase(attribute.getFirstChild().getNodeValue().trim())) {
                    return null;
                }
            }
        }
        return new ResourceStatus(id, MachineImageState.ACTIVE);
    }

    @Nonnull
    @Override
    public Iterable<MachineImage> listImages(@Nullable ImageFilterOptions imageFilterOptions)
            throws CloudException, InternalException {
        if (!imageFilterOptions.getImageClass().equals(ImageClass.MACHINE)) {
            return Collections.emptyList();
        }

        final ProviderContext ctx = provider.getContext();

        if (ctx == null) {
            throw new AzureConfigException("No context was specified for this request");
        }

        ArrayList<MachineImage> images = new ArrayList<MachineImage>();
        AzureMethod method = new AzureMethod(provider);

        Document doc = method.getAsXML(ctx.getAccountNumber(), IMAGES);

        if (doc == null) {
            throw new CloudException(CloudErrorType.AUTHENTICATION, HttpServletResponse.SC_FORBIDDEN,
                    "Illegal Access", "Illegal access to requested resource");
        }
        NodeList entries = doc.getElementsByTagName("OSImage");

        for (int i = 0; i < entries.getLength(); i++) {
            Node entry = entries.item(i);
            AzureMachineImage image = toImage(ctx, entry);
            image.setImageClass(ImageClass.MACHINE);

            if (image != null) {

                if (imageFilterOptions.matches(image)) {
                    if (imageFilterOptions.getAccountNumber() == null) {
                        if (ctx.getAccountNumber().equals(image.getProviderOwnerId())) {
                            images.add(image);
                        }
                    } else if (image.getProviderOwnerId().equalsIgnoreCase(imageFilterOptions.getAccountNumber())) {
                        images.add(image);
                    }
                }
            }
        }
        return images;
    }

    @Nonnull
    @Override
    public Iterable<MachineImage> listImages(@Nonnull ImageClass cls) throws CloudException, InternalException {
        if (!cls.equals(ImageClass.MACHINE)) {
            return Collections.emptyList();
        }

        ProviderContext ctx = provider.getContext();

        String me = ctx.getAccountNumber();
        ArrayList<MachineImage> allImages = listMachineImages();

        ArrayList<MachineImage> list = new ArrayList<MachineImage>();

        for (MachineImage img : allImages) {
            if (img.getProviderOwnerId().equalsIgnoreCase(me)) {
                img.setImageClass(ImageClass.MACHINE);
                list.add(img);
            }
        }
        return list;
    }

    @Nonnull
    @Override
    public Iterable<MachineImage> listImages(@Nonnull ImageClass cls, @Nonnull String ownedBy)
            throws CloudException, InternalException {
        if (!cls.equals(ImageClass.MACHINE)) {
            return Collections.emptyList();
        }

        ProviderContext ctx = provider.getContext();

        String me = ctx.getAccountNumber();
        ArrayList<MachineImage> allImages = listMachineImages();

        ArrayList<MachineImage> list = new ArrayList<MachineImage>();

        for (MachineImage img : allImages) {
            if (img.getProviderOwnerId().equalsIgnoreCase(ownedBy)) {
                img.setImageClass(ImageClass.MACHINE);
                list.add(img);
            }
        }
        return list;
    }

    @Override
    public @Nonnull ArrayList<MachineImage> listMachineImages() throws CloudException, InternalException {
        final ProviderContext ctx = provider.getContext();

        if (ctx == null) {
            throw new AzureConfigException("No context was specified for this request");
        }

        ArrayList<MachineImage> list = new ArrayList<MachineImage>();
        AzureMethod method = new AzureMethod(provider);

        Document doc = method.getAsXML(ctx.getAccountNumber(), IMAGES);

        if (doc == null) {
            throw new CloudException(CloudErrorType.AUTHENTICATION, HttpServletResponse.SC_FORBIDDEN,
                    "Illegal Access", "Illegal access to requested resource");
        }
        NodeList entries = doc.getElementsByTagName("OSImage");

        for (int i = 0; i < entries.getLength(); i++) {
            Node entry = entries.item(i);
            AzureMachineImage image = toImage(ctx, entry);

            if (image != null) {
                if (ctx.getAccountNumber().equalsIgnoreCase(image.getProviderOwnerId())) {
                    list.add(image);
                }
            }
        }
        return list;
    }

    @Override
    public @Nonnull Iterable<MachineImage> listMachineImagesOwnedBy(String accountId)
            throws CloudException, InternalException {
        final ProviderContext ctx = provider.getContext();

        if (ctx == null) {
            throw new AzureConfigException("No context was specified for this request");
        }

        final String[] accounts = (accountId == null ? new String[] { ctx.getAccountNumber() }
                : new String[] { accountId });

        PopulatorThread<MachineImage> populator;

        provider.hold();
        populator = new PopulatorThread<MachineImage>(new JiteratorPopulator<MachineImage>() {
            public void populate(@Nonnull Jiterator<MachineImage> iterator)
                    throws CloudException, InternalException {
                try {
                    populateImages(ctx, iterator, accounts);
                } finally {
                    provider.release();
                }
            }
        });
        populator.populate();
        return populator.getResult();
    }

    @Override
    public @Nonnull Iterable<MachineImageFormat> listSupportedFormats() throws CloudException, InternalException {
        //dmayne 20130417: seems to be the right type
        return Collections.singletonList(MachineImageFormat.VHD);
        // return Collections.singletonList(MachineImageFormat.AWS); // nonsense, I know
    }

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

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

    @Nonnull
    @Override
    public Iterable<ImageClass> listSupportedImageClasses() throws CloudException, InternalException {
        return Collections.singletonList(ImageClass.MACHINE);
    }

    @Nonnull
    @Override
    public Iterable<MachineImageType> listSupportedImageTypes() throws CloudException, InternalException {
        return Collections.singletonList(MachineImageType.VOLUME);
    }

    @Nonnull
    @Override
    public MachineImage registerImageBundle(@Nonnull ImageCreateOptions options)
            throws CloudException, InternalException {
        throw new OperationNotSupportedException("No image registering is currently supported");
    }

    private void populateImages(@Nonnull ProviderContext ctx, @Nonnull Jiterator<MachineImage> iterator,
            @Nullable String... accounts) throws CloudException, InternalException {
        AzureMethod method = new AzureMethod(provider);

        Document doc = method.getAsXML(ctx.getAccountNumber(), IMAGES);

        if (doc == null) {
            throw new CloudException(CloudErrorType.AUTHENTICATION, HttpServletResponse.SC_FORBIDDEN,
                    "Illegal Access", "Illegal access to requested resource");
        }
        NodeList entries = doc.getElementsByTagName("OSImage");

        for (int i = 0; i < entries.getLength(); i++) {
            Node entry = entries.item(i);
            AzureMachineImage image = toImage(ctx, entry);

            if (image != null) {
                if (accounts != null) {
                    for (String accountNumber : accounts) {
                        if (accountNumber.equalsIgnoreCase(image.getProviderOwnerId())) {
                            iterator.push(image);
                            break;
                        }
                    }
                } else if (image.getProviderOwnerId() == null || MICROSOFT.equals(image.getProviderOwnerId())
                        || "--public--".equals(image.getProviderOwnerId())) {
                    iterator.push(image);
                }
            }
        }
    }

    @Override
    public void remove(@Nonnull String machineImageId) throws CloudException, InternalException {
        if (logger.isTraceEnabled()) {
            logger.trace("ENTER: " + AzureOSImage.class.getName() + ".remove(" + machineImageId + ")");
        }
        try {
            ProviderContext ctx = provider.getContext();

            if (ctx == null) {
                throw new AzureConfigException("No context was specified for this request");
            }

            MachineImage image = getMachineImage(machineImageId);

            if (image == null) {
                throw new CloudException("No such machine image: " + machineImageId);
            }

            AzureMethod method = new AzureMethod(provider);

            //dmayne 20130425: delete image blob too
            method.invoke("DELETE", ctx.getAccountNumber(), IMAGES + "/" + machineImageId + "?comp=media", null);
        } finally {
            if (logger.isTraceEnabled()) {
                logger.trace("EXIT: " + AzureOSImage.class.getName() + ".launch()");
            }
        }
    }

    @Override
    public void remove(@Nonnull String providerImageId, boolean checkState)
            throws CloudException, InternalException {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void removeAllImageShares(@Nonnull String providerImageId) throws CloudException, InternalException {
        //No-OP
    }

    @Override
    public void removeImageShare(@Nonnull String providerImageId, @Nonnull String accountNumber)
            throws CloudException, InternalException {
        throw new OperationNotSupportedException("No ability to share images");
    }

    @Override
    public void removePublicShare(@Nonnull String providerImageId) throws CloudException, InternalException {
        throw new OperationNotSupportedException("No ability to share images");
    }

    @Override
    public @Nonnull Iterable<MachineImage> searchMachineImages(@Nullable String keyword,
            @Nullable Platform platform, @Nullable Architecture architecture)
            throws CloudException, InternalException {
        ArrayList<MachineImage> images = new ArrayList<MachineImage>();

        final ProviderContext ctx = provider.getContext();

        if (ctx == null) {
            throw new AzureConfigException("No context was specified for this request");
        }

        PopulatorThread<MachineImage> populator;

        provider.hold();
        populator = new PopulatorThread<MachineImage>(new JiteratorPopulator<MachineImage>() {
            public void populate(@Nonnull Jiterator<MachineImage> iterator)
                    throws CloudException, InternalException {
                try {
                    populateImages(ctx, iterator, MICROSOFT, "--public--", ctx.getAccountNumber(), "--Canonical--",
                            "--RightScaleLinux--", "--RightScaleWindows--", "--OpenLogic--", "--SUSE--");
                } finally {
                    provider.release();
                }
            }
        });
        populator.populate();
        for (MachineImage img : populator.getResult()) {
            if (architecture != null) {
                if (!architecture.equals(img.getArchitecture())) {
                    continue;
                }
            }
            if (platform != null && !platform.equals(Platform.UNKNOWN)) {
                Platform p = img.getPlatform();

                if (p.equals(Platform.UNKNOWN)) {
                    continue;
                } else if (platform.isWindows()) {
                    if (!p.isWindows()) {
                        continue;
                    }
                } else if (platform.equals(Platform.UNIX)) {
                    if (!p.isUnix()) {
                        continue;
                    }
                } else if (!platform.equals(p)) {
                    continue;
                }
            }
            if (keyword != null) {
                if (!img.getName().contains(keyword)) {
                    if (!img.getDescription().contains(keyword)) {
                        if (!img.getProviderMachineImageId().contains(keyword)) {
                            continue;
                        }
                    }
                }
            }
            images.add(img);
        }
        return images;
    }

    @Nonnull
    @Override
    public Iterable<MachineImage> searchImages(@Nullable String accountNumber, @Nullable String keyword,
            @Nullable Platform platform, @Nullable Architecture architecture, @Nullable ImageClass... imageClasses)
            throws CloudException, InternalException {
        return null; //To change body of implemented methods use File | Settings | File Templates.
    }

    @Nonnull
    @Override
    public Iterable<MachineImage> searchPublicImages(@Nullable String keyword, @Nullable Platform platform,
            @Nullable Architecture architecture, @Nullable ImageClass... imageClasses)
            throws CloudException, InternalException {
        ArrayList<MachineImage> list = new ArrayList<MachineImage>();
        for (ImageClass a : imageClasses) {
            Iterable<MachineImage> images = searchMachineImages(keyword, platform, architecture);
            for (MachineImage img : images) {
                if (isImageSharedWithPublic(img.getProviderMachineImageId())) {
                    list.add(img);
                }
            }
        }
        return list;
    }

    @Override
    public boolean supportsCustomImages() {
        return true;
    }

    @Override
    public boolean supportsDirectImageUpload() throws CloudException, InternalException {
        return false; //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public boolean supportsImageCapture(@Nonnull MachineImageType type) throws CloudException, InternalException {
        if (type.equals(MachineImageType.VOLUME)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean supportsImageSharing() {
        return false;
    }

    @Override
    public boolean supportsImageSharingWithPublic() {
        return false;
    }

    @Override
    public boolean supportsPublicLibrary(@Nonnull ImageClass cls) throws CloudException, InternalException {
        return true; //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void updateTags(@Nonnull String imageId, @Nonnull Tag... tags) throws CloudException, InternalException {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void updateTags(@Nonnull String[] strings, @Nonnull Tag... tags)
            throws CloudException, InternalException {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void removeTags(@Nonnull String s, @Nonnull Tag... tags) throws CloudException, InternalException {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void removeTags(@Nonnull String[] strings, @Nonnull Tag... tags)
            throws CloudException, InternalException {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public @Nonnull String[] mapServiceAction(@Nonnull ServiceAction action) {
        return new String[0];
    }

    private @Nullable AzureMachineImage toImage(@Nonnull ProviderContext ctx, @Nullable Node entry)
            throws CloudException, InternalException {
        if (entry == null) {
            return null;
        }

        String regionID = ctx.getRegionId();
        AzureMachineImage image = new AzureMachineImage();

        HashMap<String, String> tags = new HashMap<String, String>();
        image.setCurrentState(MachineImageState.ACTIVE);
        image.setProviderRegionId(ctx.getRegionId());
        image.setArchitecture(Architecture.I64);

        NodeList attributes = entry.getChildNodes();

        for (int i = 0; i < attributes.getLength(); i++) {
            Node attribute = attributes.item(i);
            if (attribute.getNodeType() == Node.TEXT_NODE)
                continue;
            String nodeName = attribute.getNodeName();

            if (nodeName.equalsIgnoreCase("name") && attribute.hasChildNodes()) {
                image.setProviderMachineImageId(attribute.getFirstChild().getNodeValue().trim());
            }
            if (nodeName.equalsIgnoreCase("category") && attribute.hasChildNodes()) {
                String c = attribute.getFirstChild().getNodeValue().trim();
                if ("user".equalsIgnoreCase(c)) {
                    image.setProviderOwnerId(ctx.getAccountNumber());
                } else if (c.toLowerCase().contains("microsoft")) {
                    image.setProviderOwnerId(MICROSOFT);
                } else if (c.toLowerCase().contains("partner")) {
                    image.setProviderOwnerId("--public--");
                } else if (c.toLowerCase().contains("canonical")) {
                    image.setProviderOwnerId("--Canonical--");
                } else if (c.toLowerCase().contains("rightscale with linux")) {
                    image.setProviderOwnerId("--RightScaleLinux--");
                } else if (c.toLowerCase().contains("rightscale with windows")) {
                    image.setProviderOwnerId("--RightScaleWindows--");
                } else if (c.toLowerCase().contains("openlogic")) {
                    image.setProviderOwnerId("--OpenLogic--");
                } else if (c.toLowerCase().contains("suse")) {
                    image.setProviderOwnerId("--SUSE--");
                }
            } else if (nodeName.equalsIgnoreCase("label") && attribute.hasChildNodes()) {
                image.setName(attribute.getFirstChild().getNodeValue().trim());

            } else if (nodeName.equalsIgnoreCase("description") && attribute.hasChildNodes()) {
                image.setDescription(attribute.getFirstChild().getNodeValue().trim());
            } else if (nodeName.equalsIgnoreCase("location") && attribute.hasChildNodes()) {
                String location = attribute.getFirstChild().getNodeValue().trim();
                String[] locations = location.split(";");
                boolean found = false;
                for (String loc : locations) {
                    if (regionID.equalsIgnoreCase(loc)) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    return null;
                }
            } else if (nodeName.equalsIgnoreCase("medialink") && attribute.hasChildNodes()) {
                image.setMediaLink(attribute.getFirstChild().getNodeValue().trim());
            } else if (nodeName.equalsIgnoreCase("os") && attribute.hasChildNodes()) {
                String os = attribute.getFirstChild().getNodeValue().trim();

                if (os.equalsIgnoreCase("windows")) {
                    image.setPlatform(Platform.WINDOWS);
                } else if (os.equalsIgnoreCase("linux")) {
                    image.setPlatform(Platform.UNIX);
                }
            }
        }
        if (image.getProviderMachineImageId() == null) {
            return null;
        }
        if (image.getName() == null) {
            image.setName(image.getProviderMachineImageId());
        }
        if (image.getDescription() == null) {
            image.setDescription(image.getName());
        }
        String descriptor = image.getProviderMachineImageId() + " " + image.getName() + " "
                + image.getDescription();

        if (image.getPlatform() == null || image.getPlatform().equals(Platform.UNIX)) {
            Platform p = Platform.guess(descriptor);

            if (image.getPlatform() == null || !Platform.UNKNOWN.equals(p)) {
                image.setPlatform(p);
            }
        }
        image.setSoftware(descriptor.contains("SQL Server") ? "SQL Server" : "");
        image.setTags(tags);
        image.setType(MachineImageType.VOLUME);

        return image;
    }
}