All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jclouds.virtualbox.util.MachineUtils Maven / Gradle / Ivy

There is a newer version: 1.6.0
Show newest version
/**
 * Licensed to jclouds, Inc. (jclouds) under one or more
 * contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  jclouds 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.util;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.callables.RunScriptOnNode.Factory;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.util.Throwables2;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.LockType;
import org.virtualbox_4_1.SessionState;
import org.virtualbox_4_1.VBoxException;
import org.virtualbox_4_1.VirtualBoxManager;

import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Inject;

/**
 * Utilities for executing functions on a VirtualBox machine.
 * 
 * @author Adrian Cole, Mattias Holmqvist, Andrea Turli, David Alves
 */

@Singleton
public class MachineUtils {
   
   public final String IP_V4_ADDRESS_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
            + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
            + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
   
   @Resource
   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
   protected Logger logger = Logger.NULL;

   private final Supplier manager;
   private final Factory scriptRunner;

   @Inject
   public MachineUtils(Supplier manager, RunScriptOnNode.Factory scriptRunner) {
      super();
      this.manager = manager;
      this.scriptRunner = scriptRunner;
   }

   public ListenableFuture runScriptOnNode(NodeMetadata metadata, Statement statement,
            RunScriptOptions options) {
      return scriptRunner.submit(metadata, statement, options);
   }

   /**
    * Locks the machine and executes the given function using the machine matching the given id.
    * Since the machine is locked it is possible to perform some modifications to the IMachine.
    * 

* Unlocks the machine before returning. * * @param machineId * the id of the machine * @param function * the function to execute * @return the result from applying the function to the machine. */ public T writeLockMachineAndApply(final String machineId, final Function function) { return lockSessionOnMachineAndApply(machineId, LockType.Write, new Function() { @Override public T apply(ISession session) { return function.apply(session.getMachine()); } @Override public String toString() { return function.toString(); } }); } /** * Locks the machine and executes the given function using the machine matching the given id. The * machine is write locked and modifications to the session that reflect on the machine can be * done safely. *

* Unlocks the machine before returning. * * @param machineId * the id of the machine * @param function * the function to execute * @return the result from applying the function to the machine. */ public T writeLockMachineAndApplyToSession(final String machineId, final Function function) { return lockSessionOnMachineAndApply(machineId, LockType.Write, function); } /** * Locks the machine and executes the given function using the machine matching the given id. The * machine is read locked, which means that settings can be read safely (but not changed) by * function. *

* Unlocks the machine before returning. * * @param machineId * the id of the machine * @param function * the function to execute * @return the result from applying the function to the machine. */ public T sharedLockMachineAndApply(final String machineId, final Function function) { return lockSessionOnMachineAndApply(machineId, LockType.Shared, new Function() { @Override public T apply(ISession session) { return function.apply(session.getMachine()); } @Override public String toString() { return function.toString(); } }); } /** * Locks the machine and executes the given function to the session using the machine matching * the given id. The machine is read locked, which means that settings can be read safely (but * not changed) by function. *

* Unlocks the machine before returning. * * @param machineId * the id of the machine * @param function * the function to execute * @return the result from applying the function to the machine. */ public T sharedLockMachineAndApplyToSession(final String machineId, final Function function) { return lockSessionOnMachineAndApply(machineId, LockType.Shared, function); } /** * Locks the machine and executes the given function using the current session. Since the machine * is locked it is possible to perform some modifications to the IMachine. *

* Unlocks the machine before returning. * * Tries to obtain a lock 5 times before giving up waiting 1 sec between tries. When no machine * is found null is returned. * * @param type * the kind of lock to use when initially locking the machine. * @param machineId * the id of the machine * @param function * the function to execute * @return the result from applying the function to the session. */ protected T lockSessionOnMachineAndApply(String machineId, LockType type, Function function) { int retries = 15; ISession session = lockSession(machineId, type, retries); try { return function.apply(session); } catch (VBoxException e) { throw new RuntimeException(String.format("error applying %s to %s with %s lock: %s", function, machineId, type, e.getMessage()), e); } finally { if (session != null && session.getState().equals(SessionState.Locked)) session.unlockMachine(); } } private ISession lockSession(String machineId, LockType type, int retries) { int count = 0; ISession session; while (true) { try { IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); session = manager.get().getSessionObject(); immutableMachine.lockMachine(session, type); break; } catch (VBoxException e) { VBoxException vbex = Throwables2.getFirstThrowableOfType(e, VBoxException.class); if (vbex != null && machineNotFoundException(vbex)) { return null; } count++; logger.warn(e, "Could not lock machine (try %d of %d). Error: %s", count, retries, e.getMessage()); if (count == retries) { throw new RuntimeException(String.format("error locking %s with %s lock: %s", machineId, type, e.getMessage()), e); } try { Thread.sleep(1000L); } catch (InterruptedException e1) { } } } checkState(session.getState().equals(SessionState.Locked)); return checkNotNull(session, "session"); } void print() { for (StackTraceElement element : Thread.currentThread().getStackTrace()){ System.err.println(element.toString()); } } /** * @param machineId * @param function * @return */ public T applyForMachine(final String machineId, final Function function) { final IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); return new Function() { @Override public T apply(IMachine machine) { return function.apply(machine); } @Override public String toString() { return function.toString(); } }.apply(immutableMachine); } public static boolean machineNotFoundException(VBoxException e) { return e.getMessage().contains("VirtualBox error: Could not find a registered machine named ") || e.getMessage().contains("Could not find a registered machine with UUID {"); } public String getIpAddressFromBridgedNIC(String machineName) { String ip = ""; int attempt = 0; while (!isIpv4(ip) && attempt < 10) { ip = this.lockSessionOnMachineAndApply(machineName, LockType.Shared, new Function() { @Override public String apply(ISession session) { String ip = session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP"); return ip; } }); attempt++; long sleepTime = 1000 * attempt; logger.debug("Instance %s is still not ready. Attempt n:%d. Sleeping for %d millisec", machineName, attempt, sleepTime); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { Throwables.propagate(e); } } return ip; } private boolean isIpv4(String s) { Pattern pattern = Pattern.compile(this.IP_V4_ADDRESS_PATTERN); Matcher matcher = pattern.matcher(s); return matcher.matches(); } public String getIpAddressFromHostOnlyNIC(String machineName) { // TODO using a caching mechanism to avoid to call everytime this vboxmanage api call String currentIp = "", previousIp = "1.1.1.1"; int attempt = 0, count = 0; while(count < 5) { currentIp = ""; attempt = 0; while (!isIpv4(currentIp) && attempt < 5) { currentIp = this.lockSessionOnMachineAndApply(machineName, LockType.Shared, new Function() { @Override public String apply(ISession session) { return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP"); } }); attempt++; } if(previousIp.equals(currentIp)) { count++; delayer(500l * (count + 1)); } else { count = 0; delayer(5000l); } previousIp = currentIp; } return currentIp; } private void delayer(long millisec) { try { Thread.sleep(millisec); } catch (InterruptedException e) { Throwables.propagate(e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy