org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter.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;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.contains;
import static com.google.common.collect.Iterables.filter;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_NAME_SEPARATOR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;

import java.util.Map;
import java.util.Set;

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

import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.NodeSpec;
import org.jclouds.virtualbox.domain.YamlImage;
import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndForceDeleteItsMedia;
import org.jclouds.virtualbox.util.MachineController;
import org.virtualbox_4_2.IMachine;
import org.virtualbox_4_2.IProgress;
import org.virtualbox_4_2.ISession;
import org.virtualbox_4_2.MachineState;
import org.virtualbox_4_2.VBoxException;
import org.virtualbox_4_2.VirtualBoxManager;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.inject.Singleton;

/**
 * Defines the connection between the {@link org.virtualbox_4_2.VirtualBoxManager} implementation
 * and the jclouds {@link org.jclouds.compute.ComputeService}
 * 
 * @author Mattias Holmqvist, Andrea Turli, David Alves
 */
@Singleton
public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, Hardware, Image, Location> {

    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
    protected Logger logger = Logger.NULL;

    private final Supplier<VirtualBoxManager> manager;
    private final Map<Image, YamlImage> imagesToYamlImages;
    private final LoadingCache<Image, Master> mastersLoader;
    private final Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator;
    private final Function<IMachine, Image> imachineToImage;
    private final MachineController machineController;

    @Inject
    public VirtualBoxComputeServiceAdapter(Supplier<VirtualBoxManager> manager,
            Supplier<Map<Image, YamlImage>> imagesMapper, LoadingCache<Image, Master> mastersLoader,
            Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator,
            Function<IMachine, Image> imachineToImage, MachineController machineController) {
        this.manager = checkNotNull(manager, "virtualbox manager can't be null");
        this.imagesToYamlImages = imagesMapper.get();
        this.mastersLoader = mastersLoader;
        this.cloneCreator = cloneCreator;
        this.imachineToImage = imachineToImage;
        this.machineController = machineController;
    }

    @Override
    public NodeAndInitialCredentials<IMachine> createNodeWithGroupEncodedIntoName(String tag, String name,
            Template template) {
        try {
            checkState(!tag.contains(VIRTUALBOX_NODE_NAME_SEPARATOR),
                    "tag names cannot contain \"" + VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
            checkState(!name.contains(VIRTUALBOX_NODE_NAME_SEPARATOR),
                    "node names cannot contain \"" + VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
            Master master = mastersLoader.get(template.getImage());
            checkState(master != null, "could not find a master for image: " + template.getImage());
            NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build();
            return cloneCreator.apply(nodeSpec);
        } catch (Exception e) {
            throw Throwables.propagate(e);
        }
    }

    @Override
    public Iterable<IMachine> listNodes() {
        return Iterables.filter(manager.get().getVBox().getMachines(), new Predicate<IMachine>() {
            @Override
            public boolean apply(IMachine arg0) {
                return arg0.getName().startsWith(VIRTUALBOX_NODE_PREFIX);
            }
        });
    }

    @Override
    public Iterable<IMachine> listNodesByIds(final Iterable<String> ids) {
        return filter(listNodes(), new Predicate<IMachine>() {

            @Override
            public boolean apply(IMachine machine) {
                return contains(ids, machine.getId());
            }
        });
    }

    @Override
    public Iterable<Hardware> listHardwareProfiles() {
        Set<Hardware> hardware = Sets.newLinkedHashSet();
        hardware.add(
                new HardwareBuilder().ids("t1.micro").hypervisor("VirtualBox").name("t1.micro").ram(512).build());
        hardware.add(
                new HardwareBuilder().ids("m1.small").hypervisor("VirtualBox").name("m1.small").ram(1024).build());
        hardware.add(new HardwareBuilder().ids("m1.medium").hypervisor("VirtualBox").name("m1.medium").ram(3840)
                .build());
        hardware.add(
                new HardwareBuilder().ids("m1.large").hypervisor("VirtualBox").name("m1.large").ram(7680).build());
        return hardware;
    }

    @Override
    public Iterable<Image> listImages() {
        // the set of image vm names that were (or could be) built from the yaml file
        final Set<String> imagesFromYamlNames = Sets
                .newHashSet(Iterables.transform(imagesToYamlImages.keySet(), new Function<Image, String>() {
                    @Override
                    public String apply(Image input) {
                        return VIRTUALBOX_IMAGE_PREFIX + input.getId();
                    }

                }));

        // IMachines that were not built from the yaml file transformed to Images
        Set<Image> imagesFromCloning = Sets
                .newHashSet(Iterables.transform(Iterables.filter(imageMachines(), new Predicate<IMachine>() {
                    @Override
                    public boolean apply(IMachine input) {
                        return !imagesFromYamlNames.contains(input.getName());
                    }
                }), imachineToImage));

        // final set of images are those from yaml and those from vbox that were not a transformation
        // of the yaml ones
        return Sets.union(imagesToYamlImages.keySet(), imagesFromCloning);
    }

    private Iterable<IMachine> imageMachines() {
        final Predicate<? super IMachine> imagePredicate = new Predicate<IMachine>() {
            @Override
            public boolean apply(@Nullable IMachine iMachine) {
                return iMachine.getName().startsWith(VIRTUALBOX_IMAGE_PREFIX);
            }
        };
        final Iterable<IMachine> imageMachines = filter(manager.get().getVBox().getMachines(), imagePredicate);
        return imageMachines;
    }

    @Override
    public Iterable<Location> listLocations() {
        // Not using the adapter to determine locations
        return ImmutableSet.<Location>of();
    }

    @Override
    public IMachine getNode(String vmName) {
        try {
            return manager.get().getVBox().findMachine(vmName);
        } catch (VBoxException e) {
            if (e.getMessage().contains("Could not find a registered machine named")) {
                return null;
            }
            throw Throwables.propagate(e);
        }
    }

    @Override
    public Image getImage(String vmName) {
        IMachine image = getNode(vmName);
        if (image == null)
            return null;
        return imachineToImage.apply(image);
    }

    @Override
    public synchronized void destroyNode(String vmName) {
        IMachine machine = manager.get().getVBox().findMachine(vmName);
        powerDownMachine(machine);
        try {
            new UnregisterMachineIfExistsAndForceDeleteItsMedia().apply(machine);
        } catch (Exception e) {
            logger.error("Machine (%s) not unregistered!", vmName);
        }
    }

    @Override
    public void rebootNode(String vmName) {
        IMachine machine = manager.get().getVBox().findMachine(vmName);
        powerDownMachine(machine);
        launchVMProcess(machine, manager.get().getSessionObject());
    }

    @Override
    public void resumeNode(String vmName) {
        IMachine machine = manager.get().getVBox().findMachine(vmName);
        ISession machineSession;
        try {
            machineSession = manager.get().openMachineSession(machine);
            machineSession.getConsole().resume();
            machineSession.unlockMachine();
        } catch (Exception e) {
            throw Throwables.propagate(e);
        }
    }

    @Override
    public void suspendNode(String vmName) {
        IMachine machine = manager.get().getVBox().findMachine(vmName);
        ISession machineSession;
        try {
            machineSession = manager.get().openMachineSession(machine);
            machineSession.getConsole().pause();
            machineSession.unlockMachine();
        } catch (Exception e) {
            throw Throwables.propagate(e);
        }
    }

    private void launchVMProcess(IMachine machine, ISession session) {
        IProgress prog = machine.launchVMProcess(session, "gui", "");
        prog.waitForCompletion(-1);
        session.unlockMachine();
    }

    private void powerDownMachine(IMachine machine) {
        try {
            if (machine.getState() == MachineState.PoweredOff) {
                logger.debug("vm was already powered down: ", machine.getId());
                return;
            }
            logger.debug("<< powering down vm(%s)", machine.getName());
            machineController.ensureMachineHasPowerDown(machine.getName());
        } catch (Exception e) {
            logger.error(e, "problem in powering down vm(%s)", machine.getName());
            throw Throwables.propagate(e);
        }
    }
}