/** * Copyright (C) 2010-2013 Eugen Feller, INRIA <eugen.feller@inria.fr> * * This file is part of Snooze, a scalable, autonomic, and * energy-aware virtual machine (VM) management framework. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses>. */ package org.inria.myriads.snoozenode.groupmanager.migration.watchdog; import org.inria.myriads.snoozecommon.communication.NetworkAddress; import org.inria.myriads.snoozecommon.communication.rest.CommunicatorFactory; import org.inria.myriads.snoozecommon.communication.rest.api.LocalControllerAPI; import org.inria.myriads.snoozecommon.communication.virtualcluster.migration.MigrationRequest; import org.inria.myriads.snoozecommon.guard.Guard; import org.inria.myriads.snoozecommon.util.TimeUtils; import org.inria.myriads.snoozenode.groupmanager.migration.listener.MigrationListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Migration watchdog. * * @author Eugen Feller */ public final class MigrationWatchdog implements Runnable, MigrationListener { /** Define the logger. */ private static final Logger log_ = LoggerFactory.getLogger(MigrationWatchdog.class); /** Migration listener. */ private MigrationListener migrationListener_; /**Migration request. */ private MigrationRequest migrationRequest_; /** The lock. */ private Object lockObject_; /** Indicates termination. */ private boolean isTerminated_; /** * Constructor. * * @param migrationRequest The migration request * @param migrationListener The migration listener */ public MigrationWatchdog(MigrationRequest migrationRequest, MigrationListener migrationListener) { Guard.check(migrationRequest, migrationListener); log_.debug("Initializing the migration watchdog thread!"); migrationRequest_ = migrationRequest; migrationListener_ = migrationListener; lockObject_ = new Object(); } /** * Suspends a virtual machine. * * @param virtualMachineId The virtual machine identifier * @param localControllerAddress The local controller address * @return true if everything ok, false otherwise */ private boolean suspendVirtualMachine(String virtualMachineId, NetworkAddress localControllerAddress) { Guard.check(virtualMachineId, localControllerAddress); log_.debug(String.format("Sending request to suspend virtual machine: %s on local controller: %s", virtualMachineId, localControllerAddress.getAddress())); LocalControllerAPI communicator = CommunicatorFactory.newLocalControllerCommunicator(localControllerAddress); return communicator.suspendVirtualMachineOnMigration(virtualMachineId); } /** * Starts watching the migration. */ @Override public void run() { String virtualMachineId = migrationRequest_.getSourceVirtualMachineLocation().getVirtualMachineId(); int convergenceTimeout = migrationRequest_.getDestinationHypervisorSettings().getMigration().getTimeout(); NetworkAddress sourceLocalController = migrationRequest_.getSourceVirtualMachineLocation().getLocalControllerControlDataAddress(); try { log_.debug(String.format("Starting to watch live migration of: %s", virtualMachineId)); synchronized (lockObject_) { lockObject_.wait(TimeUtils.convertSecondsToMilliseconds(convergenceTimeout)); } } catch (InterruptedException exception) { log_.debug(String.format("Migration watchdog thread was interrupted: %s!", exception.getMessage())); } finally { if (isTerminated_) { log_.debug(String.format("Virtual machine %s watchdog terminated gracefully!", virtualMachineId)); return; } log_.debug(String.format("Virtual machine %s is still active! Suspending to force convergence!", virtualMachineId)); boolean isSuspended = suspendVirtualMachine(virtualMachineId, sourceLocalController); if (isSuspended) { log_.debug(String.format("Virtual machine %s suspend finished successfully!!", virtualMachineId)); return; } log_.debug(String.format("Suspending virtual machine %s migration FAILED!", virtualMachineId)); migrationRequest_.setMigrated(false); migrationListener_.onMigrationEnded(migrationRequest_); } } /** * On migration ended callback. * * @param migrationRequest The migration request */ @Override public void onMigrationEnded(MigrationRequest migrationRequest) { synchronized (lockObject_) { isTerminated_ = true; lockObject_.notify(); } } }