org.jclouds.virtualbox.compute.extensions.VirtualBoxImageExtension.java Source code

Java tutorial

Introduction

Here is the source code for org.jclouds.virtualbox.compute.extensions.VirtualBoxImageExtension.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.jclouds.virtualbox.compute.extensions;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;

import java.util.List;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.CloneImageTemplate;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate;
import org.jclouds.compute.domain.ImageTemplateBuilder;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.extensions.ImageExtension;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.functions.IMachineToVmSpec;
import org.jclouds.virtualbox.functions.TakeSnapshotIfNotAlreadyAttached;
import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndDeleteItsMedia;
import org.jclouds.virtualbox.util.MachineUtils;
import org.virtualbox_4_2.CloneMode;
import org.virtualbox_4_2.CloneOptions;
import org.virtualbox_4_2.IMachine;
import org.virtualbox_4_2.IProgress;
import org.virtualbox_4_2.ISnapshot;
import org.virtualbox_4_2.VirtualBoxManager;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

/**
 * Virtualbox implementation of {@link ImageExtension}
 * 
 * @author David Alves
 * 
 */
@Singleton
public class VirtualBoxImageExtension implements ImageExtension {

    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
    private Logger logger = Logger.NULL;
    private ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter;
    private Function<IMachine, NodeMetadata> machineToNode;
    private Supplier<VirtualBoxManager> manager;
    private String workingDir;
    private boolean isLinkedClone = true;
    private Function<IMachine, Image> imachineToImage;
    private MachineUtils machineUtils;

    @Inject
    public VirtualBoxImageExtension(ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter,
            Function<IMachine, NodeMetadata> machineToNode, Supplier<VirtualBoxManager> manager,
            @Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function<IMachine, Image> imachineToImage,
            MachineUtils machineUtils) {
        this.vboxAdapter = vboxAdapter;
        this.machineToNode = machineToNode;
        this.manager = manager;
        this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir;
        this.imachineToImage = imachineToImage;
        this.machineUtils = machineUtils;
    }

    @Override
    public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
        Optional<NodeMetadata> sourceNode = getNodeById(id);
        checkState(sourceNode.isPresent(), " there is no node with id " + id);
        String vmName = VIRTUALBOX_IMAGE_PREFIX + name;

        IMachine vm = null;
        try {
            vm = manager.get().getVBox().findMachine(vmName);
        } catch (Exception e) {
        }
        checkState(vm == null, " a machine exists with name: " + vmName);
        return new ImageTemplateBuilder.CloneImageTemplateBuilder().name(vmName).nodeId(id).build();
    }

    @Override
    public ListenableFuture<Image> createImage(ImageTemplate template) {
        checkState(template instanceof CloneImageTemplate,
                " vbox image extension only supports cloning for the moment.");
        CloneImageTemplate cloneTemplate = CloneImageTemplate.class.cast(template);

        IMachine source = manager.get().getVBox().findMachine(cloneTemplate.getSourceNodeId());

        String flags = "";
        List<String> groups = ImmutableList.of();
        String group = "";
        String settingsFile = manager.get().getVBox().composeMachineFilename(template.getName(), group, flags,
                workingDir);
        IMachine clonedMachine = manager.get().getVBox().createMachine(settingsFile, template.getName(), groups,
                source.getOSTypeId(), flags);

        List<CloneOptions> options = Lists.newArrayList();
        if (isLinkedClone)
            options.add(CloneOptions.Link);

        // TODO snapshot name
        ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "pre-image-spawn",
                "before spawning " + template.getName(), logger).apply(source);

        checkNotNull(currentSnapshot);

        // clone
        IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine, CloneMode.MachineState, options);
        progress.waitForCompletion(-1);

        logger.debug(String.format("<< master(%s) is cloned correctly to vm(%s)", source.getName(),
                clonedMachine.getName()));

        // registering
        manager.get().getVBox().registerMachine(clonedMachine);

        return Futures.immediateFuture(imachineToImage.apply(clonedMachine));
    }

    @Override
    public boolean deleteImage(String id) {
        try {
            IMachine machine = manager.get().getVBox().findMachine(VIRTUALBOX_IMAGE_PREFIX + id);
            machineUtils.applyForMachine(machine.getId(),
                    new UnregisterMachineIfExistsAndDeleteItsMedia(new IMachineToVmSpec().apply(machine)));
        } catch (Exception e) {
            logger.error(e, "Could not delete machine with id %s ", id);
            return false;
        }
        return true;
    }

    private Optional<NodeMetadata> getNodeById(final String id) {
        return Iterables.tryFind(Iterables.transform(vboxAdapter.listNodes(), machineToNode),
                new Predicate<NodeMetadata>() {
                    @Override
                    public boolean apply(NodeMetadata input) {
                        return input.getId().equals(id);
                    }
                });
    }

}