blob: 71c520c4256cae7165768b54e40b70613cc3bb15 [file] [log] [blame]
/**
: * Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It 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 3 of the License, or 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 com.cloud.hypervisor.xen.resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.AttachIsoCommand;
import com.cloud.agent.api.AttachVolumeAnswer;
import com.cloud.agent.api.AttachVolumeCommand;
import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.agent.api.BackupSnapshotCommand;
import com.cloud.agent.api.CheckHealthAnswer;
import com.cloud.agent.api.CheckHealthCommand;
import com.cloud.agent.api.CheckOnHostAnswer;
import com.cloud.agent.api.CheckOnHostCommand;
import com.cloud.agent.api.CheckVirtualMachineAnswer;
import com.cloud.agent.api.CheckVirtualMachineCommand;
import com.cloud.agent.api.CleanupNetworkRulesCmd;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
import com.cloud.agent.api.CreateZoneVlanAnswer;
import com.cloud.agent.api.CreateZoneVlanCommand;
import com.cloud.agent.api.DeleteSnapshotBackupAnswer;
import com.cloud.agent.api.DeleteSnapshotBackupCommand;
import com.cloud.agent.api.DeleteSnapshotsDirCommand;
import com.cloud.agent.api.DeleteStoragePoolCommand;
import com.cloud.agent.api.GetHostStatsAnswer;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.GetStorageStatsAnswer;
import com.cloud.agent.api.GetStorageStatsCommand;
import com.cloud.agent.api.GetVmStatsAnswer;
import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.GetVncPortAnswer;
import com.cloud.agent.api.GetVncPortCommand;
import com.cloud.agent.api.HostStatsEntry;
import com.cloud.agent.api.MaintainAnswer;
import com.cloud.agent.api.MaintainCommand;
import com.cloud.agent.api.ManageSnapshotAnswer;
import com.cloud.agent.api.ManageSnapshotCommand;
import com.cloud.agent.api.MigrateAnswer;
import com.cloud.agent.api.MigrateCommand;
import com.cloud.agent.api.ModifySshKeysCommand;
import com.cloud.agent.api.ModifyStoragePoolAnswer;
import com.cloud.agent.api.ModifyStoragePoolCommand;
import com.cloud.agent.api.NetworkIngressRuleAnswer;
import com.cloud.agent.api.NetworkIngressRulesCmd;
import com.cloud.agent.api.NetworkRulesSystemVmCommand;
import com.cloud.agent.api.PingCommand;
import com.cloud.agent.api.PingRoutingCommand;
import com.cloud.agent.api.PingRoutingWithNwGroupsCommand;
import com.cloud.agent.api.PingTestCommand;
import com.cloud.agent.api.PoolEjectCommand;
import com.cloud.agent.api.PrepareForMigrationAnswer;
import com.cloud.agent.api.PrepareForMigrationCommand;
import com.cloud.agent.api.ReadyAnswer;
import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.RebootRouterCommand;
import com.cloud.agent.api.SetupAnswer;
import com.cloud.agent.api.SetupCommand;
import com.cloud.agent.api.StartAnswer;
import com.cloud.agent.api.StartCommand;
import com.cloud.agent.api.StartConsoleProxyAnswer;
import com.cloud.agent.api.StartConsoleProxyCommand;
import com.cloud.agent.api.StartRouterAnswer;
import com.cloud.agent.api.StartRouterCommand;
import com.cloud.agent.api.StartSecStorageVmAnswer;
import com.cloud.agent.api.StartSecStorageVmCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.StartupStorageCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.agent.api.ValidateSnapshotAnswer;
import com.cloud.agent.api.ValidateSnapshotCommand;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.api.WatchNetworkAnswer;
import com.cloud.agent.api.WatchNetworkCommand;
import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand;
import com.cloud.agent.api.proxy.ConsoleProxyLoadAnswer;
import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand;
import com.cloud.agent.api.routing.DhcpEntryCommand;
import com.cloud.agent.api.routing.IPAssocCommand;
import com.cloud.agent.api.routing.LoadBalancerCfgCommand;
import com.cloud.agent.api.routing.SavePasswordCommand;
import com.cloud.agent.api.routing.SetFirewallRuleCommand;
import com.cloud.agent.api.routing.VmDataCommand;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
import com.cloud.agent.api.storage.CreatePrivateTemplateCommand;
import com.cloud.agent.api.storage.DestroyCommand;
import com.cloud.agent.api.storage.DownloadAnswer;
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
import com.cloud.agent.api.storage.ShareAnswer;
import com.cloud.agent.api.storage.ShareCommand;
import com.cloud.agent.api.to.DiskCharacteristicsTO;
import com.cloud.agent.api.to.StoragePoolTO;
import com.cloud.agent.api.to.VolumeTO;
import com.cloud.exception.InternalErrorException;
import com.cloud.host.Host.Type;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.resource.ServerResource;
import com.cloud.storage.StorageLayer;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.Volume.StorageResourceType;
import com.cloud.storage.Volume.VolumeType;
import com.cloud.storage.resource.StoragePoolResource;
import com.cloud.storage.template.TemplateInfo;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.script.Script;
import com.cloud.vm.ConsoleProxyVO;
import com.cloud.vm.DomainRouter;
import com.cloud.vm.SecondaryStorageVmVO;
import com.cloud.vm.State;
import com.cloud.vm.VirtualMachineName;
import com.trilead.ssh2.SCPClient;
import com.xensource.xenapi.APIVersion;
import com.xensource.xenapi.Bond;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Console;
import com.xensource.xenapi.Host;
import com.xensource.xenapi.HostCpu;
import com.xensource.xenapi.HostMetrics;
import com.xensource.xenapi.Network;
import com.xensource.xenapi.PBD;
import com.xensource.xenapi.PIF;
import com.xensource.xenapi.Pool;
import com.xensource.xenapi.SR;
import com.xensource.xenapi.Session;
import com.xensource.xenapi.Types;
import com.xensource.xenapi.VBD;
import com.xensource.xenapi.VDI;
import com.xensource.xenapi.VIF;
import com.xensource.xenapi.VLAN;
import com.xensource.xenapi.VM;
import com.xensource.xenapi.VMGuestMetrics;
import com.xensource.xenapi.XenAPIObject;
import com.xensource.xenapi.Types.BadServerResponse;
import com.xensource.xenapi.Types.IpConfigurationMode;
import com.xensource.xenapi.Types.VmPowerState;
import com.xensource.xenapi.Types.XenAPIException;
/**
* Encapsulates the interface to the XenServer API.
*
*/
@Local(value = ServerResource.class)
public abstract class CitrixResourceBase implements StoragePoolResource, ServerResource {
private static final Logger s_logger = Logger.getLogger(CitrixResourceBase.class);
protected static final XenServerConnectionPool _connPool = XenServerConnectionPool.getInstance();
protected static final String SR_MOUNT_BASE = "/var/run/sr-mount/";
protected static final int MB = 1024 * 1024;
protected String _name;
protected String _username;
protected String _password;
protected String _scriptsDir = "scripts/vm/storage/xenserver";
protected final int _retry = 24;
protected final int _sleep = 10000;
protected long _dcId;
protected String _pod;
protected String _cluster;
protected HashMap<String, State> _vms = new HashMap<String, State>(71);
protected String _patchPath;
protected String _privateNetworkName;
protected String _linkLocalPrivateNetworkName;
protected String _publicNetworkName;
protected String _storageNetworkName1;
protected String _storageNetworkName2;
protected String _guestNetworkName;
protected int _wait;
protected IAgentControl _agentControl;
protected Map<String, String> _domrIPMap = new ConcurrentHashMap<String, String>();
protected final XenServerHost _host = new XenServerHost();
// Guest and Host Performance Statistics
protected boolean _collectHostStats = false;
protected String _consolidationFunction = "AVERAGE";
protected int _pollingIntervalInSeconds = 60;
protected StorageLayer _storage;
protected boolean _canBridgeFirewall = false;
protected HashMap<StoragePoolType, StoragePoolResource> _pools = new HashMap<StoragePoolType, StoragePoolResource>(5);
public enum SRType {
NFS, LVM, ISCSI, ISO, LVMOISCSI;
@Override
public String toString() {
return super.toString().toLowerCase();
}
public boolean equals(String type) {
return super.toString().equalsIgnoreCase(type);
}
}
protected static HashMap<Types.VmPowerState, State> s_statesTable;
protected String _localGateway;
static {
s_statesTable = new HashMap<Types.VmPowerState, State>();
s_statesTable.put(Types.VmPowerState.HALTED, State.Stopped);
s_statesTable.put(Types.VmPowerState.PAUSED, State.Running);
s_statesTable.put(Types.VmPowerState.RUNNING, State.Running);
s_statesTable.put(Types.VmPowerState.SUSPENDED, State.Running);
s_statesTable.put(Types.VmPowerState.UNKNOWN, State.Unknown);
s_statesTable.put(Types.VmPowerState.UNRECOGNIZED, State.Unknown);
}
protected boolean isRefNull(XenAPIObject object) {
return (object == null || object.toWireString().equals("OpaqueRef:NULL"));
}
@Override
public void disconnected() {
s_logger.debug("Logging out of " + _host.uuid);
if (_host.pool != null) {
_connPool.disconnect(_host.uuid, _host.pool);
}
}
protected VDI cloudVDIcopy(VDI vdi, SR sr) throws BadServerResponse, XenAPIException, XmlRpcException{
Connection conn = getConnection();
return vdi.copy(conn, sr);
}
protected void destroyStoppedVm() {
Map<VM, VM.Record> vmentries = null;
Connection conn = getConnection();
for (int i = 0; i < 2; i++) {
try {
vmentries = VM.getAllRecords(conn);
break;
} catch (final Throwable e) {
s_logger.warn("Unable to get vms", e);
}
try {
Thread.sleep(1000);
} catch (final InterruptedException ex) {
}
}
if (vmentries == null) {
return;
}
for (Map.Entry<VM, VM.Record> vmentry : vmentries.entrySet()) {
VM.Record record = vmentry.getValue();
if (record.isControlDomain || record.isASnapshot || record.isATemplate) {
continue; // Skip DOM0
}
if (record.powerState != Types.VmPowerState.HALTED) {
continue;
}
try {
vmentry.getKey().destroy(conn);
} catch (Exception e) {
String msg = "VM destroy failed for " + record.nameLabel + " due to " + e.getMessage();
s_logger.warn(msg, e);
}
}
}
protected void cleanupDiskMounts() {
Connection conn = getConnection();
Map<SR, SR.Record> srs;
try {
srs = SR.getAllRecords(conn);
} catch (XenAPIException e) {
s_logger.warn("Unable to get the SRs " + e.toString(), e);
throw new CloudRuntimeException("Unable to get SRs " + e.toString(), e);
} catch (XmlRpcException e) {
throw new CloudRuntimeException("Unable to get SRs " + e.getMessage());
}
for (Map.Entry<SR, SR.Record> sr : srs.entrySet()) {
SR.Record rec = sr.getValue();
if (SRType.NFS.equals(rec.type) || (SRType.ISO.equals(rec.type) && rec.nameLabel.endsWith("iso"))) {
if (rec.PBDs == null || rec.PBDs.size() == 0) {
cleanSR(sr.getKey(), rec);
continue;
}
for (PBD pbd : rec.PBDs) {
if (isRefNull(pbd)) {
continue;
}
PBD.Record pbdr = null;
try {
pbdr = pbd.getRecord(conn);
} catch (XenAPIException e) {
s_logger.warn("Unable to get pbd record " + e.toString());
} catch (XmlRpcException e) {
s_logger.warn("Unable to get pbd record " + e.getMessage());
}
if (pbdr == null) {
continue;
}
try {
if (pbdr.host.getUuid(conn).equals(_host.uuid)) {
if(!pbdr.currentlyAttached) {
pbdPlug(conn, pbd);
}
}
} catch (XenAPIException e) {
s_logger.warn("Catch XenAPIException due to" + e.toString(), e);
} catch (XmlRpcException e) {
s_logger.warn("Catch XmlRpcException due to" + e.getMessage(), e);
}
}
}
}
}
protected Pair<VM, VM.Record> getVmByNameLabel(Connection conn, Host host, String nameLabel, boolean getRecord) throws XmlRpcException, XenAPIException {
Set<VM> vms = host.getResidentVMs(conn);
for (VM vm : vms) {
VM.Record rec = null;
String name = null;
if (getRecord) {
rec = vm.getRecord(conn);
name = rec.nameLabel;
} else {
name = vm.getNameLabel(conn);
}
if (name.equals(nameLabel)) {
return new Pair<VM, VM.Record>(vm, rec);
}
}
return null;
}
protected boolean pingdomr(String host, String port) {
String status;
status = callHostPlugin("pingdomr", "host", host, "port", port);
if (status == null || status.isEmpty()) {
return false;
}
return true;
}
protected boolean pingxenserver() {
Session slaveSession = null;
Connection slaveConn = null;
try {
URL slaveUrl = null;
slaveUrl = new URL("http://" + _host.ip);
slaveConn = new Connection(slaveUrl, 100);
slaveSession = Session.slaveLocalLoginWithPassword(slaveConn, _username, _password);
return true;
} catch (Exception e) {
return false;
} finally {
if( slaveSession != null ){
try{
Session.localLogout(slaveConn);
} catch (Exception e) {
}
slaveConn.dispose();
}
}
}
protected String logX(XenAPIObject obj, String msg) {
return new StringBuilder("Host ").append(_host.ip).append(" ").append(obj.toWireString()).append(": ").append(msg).toString();
}
protected void cleanSR(SR sr, SR.Record rec) {
Connection conn = getConnection();
if (rec.VDIs != null) {
for (VDI vdi : rec.VDIs) {
VDI.Record vdir;
try {
vdir = vdi.getRecord(conn);
} catch (XenAPIException e) {
s_logger.debug("Unable to get VDI: " + e.toString());
continue;
} catch (XmlRpcException e) {
s_logger.debug("Unable to get VDI: " + e.getMessage());
continue;
}
if (vdir.VBDs == null)
continue;
for (VBD vbd : vdir.VBDs) {
try {
VBD.Record vbdr = vbd.getRecord(conn);
VM.Record vmr = vbdr.VM.getRecord(conn);
if ((!isRefNull(vmr.residentOn) && vmr.residentOn.getUuid(conn).equals(_host.uuid))
|| (isRefNull(vmr.residentOn) && !isRefNull(vmr.affinity) && vmr.affinity.getUuid(conn).equals(_host.uuid))) {
if (vmr.powerState != VmPowerState.HALTED && vmr.powerState != VmPowerState.UNKNOWN && vmr.powerState != VmPowerState.UNRECOGNIZED) {
try {
vbdr.VM.hardShutdown(conn);
} catch (XenAPIException e) {
s_logger.debug("Shutdown hit error " + vmr.nameLabel + ": " + e.toString());
}
}
try {
vbdr.VM.destroy(conn);
} catch (XenAPIException e) {
s_logger.debug("Destroy hit error " + vmr.nameLabel + ": " + e.toString());
} catch (XmlRpcException e) {
s_logger.debug("Destroy hit error " + vmr.nameLabel + ": " + e.getMessage());
}
vbd.destroy(conn);
break;
}
} catch (XenAPIException e) {
s_logger.debug("Unable to get VBD: " + e.toString());
continue;
} catch (XmlRpcException e) {
s_logger.debug("Uanbel to get VBD: " + e.getMessage());
continue;
}
}
}
}
for (PBD pbd : rec.PBDs) {
PBD.Record pbdr = null;
try {
pbdr = pbd.getRecord(conn);
pbd.unplug(conn);
pbd.destroy(conn);
} catch (XenAPIException e) {
s_logger.warn("PBD " + ((pbdr != null) ? "(uuid:" + pbdr.uuid + ")" : "") + "destroy failed due to " + e.toString());
} catch (XmlRpcException e) {
s_logger.warn("PBD " + ((pbdr != null) ? "(uuid:" + pbdr.uuid + ")" : "") + "destroy failed due to " + e.getMessage());
}
}
try {
rec = sr.getRecord(conn);
if (rec.PBDs == null || rec.PBDs.size() == 0) {
sr.forget(conn);
return;
}
} catch (XenAPIException e) {
s_logger.warn("Unable to retrieve sr again: " + e.toString(), e);
} catch (XmlRpcException e) {
s_logger.warn("Unable to retrieve sr again: " + e.getMessage(), e);
}
}
@Override
public Answer executeRequest(Command cmd) {
if (cmd instanceof CreateCommand) {
return execute((CreateCommand) cmd);
} else if (cmd instanceof SetFirewallRuleCommand) {
return execute((SetFirewallRuleCommand) cmd);
} else if (cmd instanceof LoadBalancerCfgCommand) {
return execute((LoadBalancerCfgCommand) cmd);
} else if (cmd instanceof IPAssocCommand) {
return execute((IPAssocCommand) cmd);
} else if (cmd instanceof CheckConsoleProxyLoadCommand) {
return execute((CheckConsoleProxyLoadCommand) cmd);
} else if (cmd instanceof WatchConsoleProxyLoadCommand) {
return execute((WatchConsoleProxyLoadCommand) cmd);
} else if (cmd instanceof SavePasswordCommand) {
return execute((SavePasswordCommand) cmd);
} else if (cmd instanceof DhcpEntryCommand) {
return execute((DhcpEntryCommand) cmd);
} else if (cmd instanceof VmDataCommand) {
return execute((VmDataCommand) cmd);
} else if (cmd instanceof StartCommand) {
return execute((StartCommand) cmd);
} else if (cmd instanceof StartRouterCommand) {
return execute((StartRouterCommand) cmd);
} else if (cmd instanceof ReadyCommand) {
return execute((ReadyCommand) cmd);
} else if (cmd instanceof GetHostStatsCommand) {
return execute((GetHostStatsCommand) cmd);
} else if (cmd instanceof GetVmStatsCommand) {
return execute((GetVmStatsCommand) cmd);
} else if (cmd instanceof WatchNetworkCommand) {
return execute((WatchNetworkCommand) cmd);
} else if (cmd instanceof CheckHealthCommand) {
return execute((CheckHealthCommand) cmd);
} else if (cmd instanceof StopCommand) {
return execute((StopCommand) cmd);
} else if (cmd instanceof RebootRouterCommand) {
return execute((RebootRouterCommand) cmd);
} else if (cmd instanceof RebootCommand) {
return execute((RebootCommand) cmd);
} else if (cmd instanceof CheckVirtualMachineCommand) {
return execute((CheckVirtualMachineCommand) cmd);
} else if (cmd instanceof PrepareForMigrationCommand) {
return execute((PrepareForMigrationCommand) cmd);
} else if (cmd instanceof MigrateCommand) {
return execute((MigrateCommand) cmd);
} else if (cmd instanceof DestroyCommand) {
return execute((DestroyCommand) cmd);
} else if (cmd instanceof ShareCommand) {
return execute((ShareCommand) cmd);
} else if (cmd instanceof ModifyStoragePoolCommand) {
return execute((ModifyStoragePoolCommand) cmd);
} else if (cmd instanceof DeleteStoragePoolCommand) {
return execute((DeleteStoragePoolCommand) cmd);
} else if (cmd instanceof CopyVolumeCommand) {
return execute((CopyVolumeCommand) cmd);
} else if (cmd instanceof AttachVolumeCommand) {
return execute((AttachVolumeCommand) cmd);
} else if (cmd instanceof AttachIsoCommand) {
return execute((AttachIsoCommand) cmd);
} else if (cmd instanceof ValidateSnapshotCommand) {
return execute((ValidateSnapshotCommand) cmd);
} else if (cmd instanceof ManageSnapshotCommand) {
return execute((ManageSnapshotCommand) cmd);
} else if (cmd instanceof BackupSnapshotCommand) {
return execute((BackupSnapshotCommand) cmd);
} else if (cmd instanceof DeleteSnapshotBackupCommand) {
return execute((DeleteSnapshotBackupCommand) cmd);
} else if (cmd instanceof CreateVolumeFromSnapshotCommand) {
return execute((CreateVolumeFromSnapshotCommand) cmd);
} else if (cmd instanceof DeleteSnapshotsDirCommand) {
return execute((DeleteSnapshotsDirCommand) cmd);
} else if (cmd instanceof CreatePrivateTemplateCommand) {
return execute((CreatePrivateTemplateCommand) cmd);
} else if (cmd instanceof CreatePrivateTemplateFromSnapshotCommand) {
return execute((CreatePrivateTemplateFromSnapshotCommand) cmd);
} else if (cmd instanceof GetStorageStatsCommand) {
return execute((GetStorageStatsCommand) cmd);
} else if (cmd instanceof PrimaryStorageDownloadCommand) {
return execute((PrimaryStorageDownloadCommand) cmd);
} else if (cmd instanceof StartConsoleProxyCommand) {
return execute((StartConsoleProxyCommand) cmd);
} else if (cmd instanceof StartSecStorageVmCommand) {
return execute((StartSecStorageVmCommand) cmd);
} else if (cmd instanceof GetVncPortCommand) {
return execute((GetVncPortCommand) cmd);
} else if (cmd instanceof SetupCommand) {
return execute((SetupCommand) cmd);
} else if (cmd instanceof CreateZoneVlanCommand) {
return execute((CreateZoneVlanCommand) cmd);
} else if (cmd instanceof MaintainCommand) {
return execute((MaintainCommand) cmd);
} else if (cmd instanceof PingTestCommand) {
return execute((PingTestCommand) cmd);
} else if (cmd instanceof CheckOnHostCommand) {
return execute((CheckOnHostCommand) cmd);
} else if (cmd instanceof ModifySshKeysCommand) {
return execute((ModifySshKeysCommand) cmd);
} else if (cmd instanceof NetworkIngressRulesCmd) {
return execute((NetworkIngressRulesCmd) cmd);
} else if (cmd instanceof NetworkRulesSystemVmCommand) {
return execute((NetworkRulesSystemVmCommand) cmd);
} else if (cmd instanceof PoolEjectCommand) {
return execute((PoolEjectCommand) cmd);
} else if (cmd instanceof CleanupNetworkRulesCmd){
return execute((CleanupNetworkRulesCmd)cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}
}
/*Override by subclass*/
protected String getGuestOsType(String stdType, boolean bootFromCD) {
return stdType;
}
private Answer execute(CleanupNetworkRulesCmd cmd) {
if (!_canBridgeFirewall) {
return new Answer(cmd, true, null);
}
String result = callHostPlugin("cleanup_rules");
int numCleaned = Integer.parseInt(result);
if (result == null || result.isEmpty() || (numCleaned < 0)) {
s_logger.warn("Failed to cleanup rules for host " + _host.ip);
return new Answer(cmd, false, result);
}
if (numCleaned > 0) {
s_logger.info("Cleaned up rules for " + result + " vms on host " + _host.ip);
}
return new Answer(cmd, true, result);
}
protected Answer execute(ModifySshKeysCommand cmd) {
String publickey = cmd.getPubKey();
String privatekey = cmd.getPrvKey();
com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_host.ip, 22);
try {
sshConnection.connect(null, 60000, 60000);
if (!sshConnection.authenticateWithPassword(_username, _password)) {
throw new Exception("Unable to authenticate");
}
SCPClient scp = new SCPClient(sshConnection);
scp.put(publickey.getBytes(), "id_rsa.pub", "/opt/xensource/bin", "0600");
scp.put(privatekey.getBytes(), "id_rsa", "/opt/xensource/bin", "0600");
scp.put(privatekey.getBytes(), "id_rsa.cloud", "/root/.ssh", "0600");
return new Answer(cmd);
} catch (Exception e) {
String msg = " scp ssh key failed due to " + e.toString() + " - " + e.getMessage();
s_logger.warn(msg);
} finally {
sshConnection.close();
}
return new Answer(cmd, false, "modifySshkeys failed");
}
private boolean doPingTest(final String computingHostIp) {
String args = "-h " + computingHostIp;
String result = callHostPlugin("pingtest", "args", args);
if (result == null || result.isEmpty())
return false;
return true;
}
protected CheckOnHostAnswer execute(CheckOnHostCommand cmd) {
return new CheckOnHostAnswer(cmd, null, "Not Implmeneted");
}
private boolean doPingTest(final String domRIp, final String vmIp) {
String args = "-i " + domRIp + " -p " + vmIp;
String result = callHostPlugin("pingtest", "args", args);
if (result == null || result.isEmpty())
return false;
return true;
}
private Answer execute(PingTestCommand cmd) {
boolean result = false;
final String computingHostIp = cmd.getComputingHostIp(); // TODO, split the command into 2 types
if (computingHostIp != null) {
result = doPingTest(computingHostIp);
} else {
result = doPingTest(cmd.getRouterIp(), cmd.getPrivateIp());
}
if (!result) {
return new Answer(cmd, false, "PingTestCommand failed");
}
return new Answer(cmd);
}
protected MaintainAnswer execute(MaintainCommand cmd) {
Connection conn = getConnection();
try {
Pool pool = Pool.getByUuid(conn, _host.pool);
Pool.Record poolr = pool.getRecord(conn);
Host.Record hostr = poolr.master.getRecord(conn);
if (!_host.uuid.equals(hostr.uuid)) {
s_logger.debug("Not the master node so just return ok: " + _host.ip);
return new MaintainAnswer(cmd);
}
Map<Host, Host.Record> hostMap = Host.getAllRecords(conn);
if (hostMap.size() == 1) {
s_logger.debug("There's no one to take over as master");
return new MaintainAnswer(cmd, "Only master in the pool");
}
Host newMaster = null;
Host.Record newMasterRecord = null;
for (Map.Entry<Host, Host.Record> entry : hostMap.entrySet()) {
if (!_host.uuid.equals(entry.getValue().uuid)) {
newMaster = entry.getKey();
newMasterRecord = entry.getValue();
s_logger.debug("New master for the XenPool is " + newMasterRecord.uuid + " : " + newMasterRecord.address);
try {
_connPool.switchMaster(_host.ip, _host.pool, conn, newMaster, _username, _password, _wait);
return new MaintainAnswer(cmd, "New Master is " + newMasterRecord.address);
} catch (XenAPIException e) {
s_logger.warn("Unable to switch the new master to " + newMasterRecord.uuid + ": " + newMasterRecord.address + " Trying again...");
} catch (XmlRpcException e) {
s_logger.warn("Unable to switch the new master to " + newMasterRecord.uuid + ": " + newMasterRecord.address + " Trying again...");
}
}
}
return new MaintainAnswer(cmd, false, "Unable to find an appropriate host to set as the new master");
} catch (XenAPIException e) {
s_logger.warn("Unable to put server in maintainence mode", e);
return new MaintainAnswer(cmd, false, e.getMessage());
} catch (XmlRpcException e) {
s_logger.warn("Unable to put server in maintainence mode", e);
return new MaintainAnswer(cmd, false, e.getMessage());
}
}
protected SetupAnswer execute(SetupCommand cmd) {
return new SetupAnswer(cmd);
}
protected Answer execute(StartSecStorageVmCommand cmd) {
final String vmName = cmd.getVmName();
SecondaryStorageVmVO storage = cmd.getSecondaryStorageVmVO();
try {
Connection conn = getConnection();
Network network = Network.getByUuid(conn, _host.privateNetwork);
String bootArgs = cmd.getBootArgs();
bootArgs += " zone=" + _dcId;
bootArgs += " pod=" + _pod;
bootArgs += " localgw=" + _localGateway;
String result = startSystemVM(vmName, storage.getVlanId(), network, cmd.getVolumes(), bootArgs, storage.getGuestMacAddress(), storage.getGuestIpAddress(), storage
.getPrivateMacAddress(), storage.getPublicMacAddress(), cmd.getProxyCmdPort(), storage.getRamSize(), storage.getGuestOSId(), cmd.getNetworkRateMbps());
if (result == null) {
return new StartSecStorageVmAnswer(cmd);
}
return new StartSecStorageVmAnswer(cmd, result);
} catch (Exception e) {
String msg = "Exception caught while starting router vm " + vmName + " due to " + e.getMessage();
s_logger.warn(msg, e);
return new StartSecStorageVmAnswer(cmd, msg);
}
}
protected Answer execute(final SetFirewallRuleCommand cmd) {
String args;
if (cmd.isEnable()) {
args = "-A";
} else {
args = "-D";
}
args += " -P " + cmd.getProtocol().toLowerCase();
args += " -l " + cmd.getPublicIpAddress();
args += " -p " + cmd.getPublicPort();
args += " -n " + cmd.getRouterName();
args += " -i " + cmd.getRouterIpAddress();
args += " -r " + cmd.getPrivateIpAddress();
args += " -d " + cmd.getPrivatePort();
args += " -N " + cmd.getVlanNetmask();
String oldPrivateIP = cmd.getOldPrivateIP();
String oldPrivatePort = cmd.getOldPrivatePort();
if (oldPrivateIP != null) {
args += " -w " + oldPrivateIP;
}
if (oldPrivatePort != null) {
args += " -x " + oldPrivatePort;
}
String result = callHostPlugin("setFirewallRule", "args", args);
if (result == null || result.isEmpty()) {
return new Answer(cmd, false, "SetFirewallRule failed");
}
return new Answer(cmd);
}
protected Answer execute(final LoadBalancerCfgCommand cmd) {
String routerIp = cmd.getRouterIp();
if (routerIp == null) {
return new Answer(cmd);
}
String tmpCfgFilePath = "/tmp/" + cmd.getRouterIp().replace('.', '_') + ".cfg";
String tmpCfgFileContents = "";
for (int i = 0; i < cmd.getConfig().length; i++) {
tmpCfgFileContents += cmd.getConfig()[i];
tmpCfgFileContents += "\n";
}
String result = callHostPlugin("createFile", "filepath", tmpCfgFilePath, "filecontents", tmpCfgFileContents);
if (result == null || result.isEmpty()) {
return new Answer(cmd, false, "LoadBalancerCfgCommand failed to create HA proxy cfg file.");
}
String[] addRules = cmd.getAddFwRules();
String[] removeRules = cmd.getRemoveFwRules();
String args = "";
args += "-i " + routerIp;
args += " -f " + tmpCfgFilePath;
StringBuilder sb = new StringBuilder();
if (addRules.length > 0) {
for (int i = 0; i < addRules.length; i++) {
sb.append(addRules[i]).append(',');
}
args += " -a " + sb.toString();
}
sb = new StringBuilder();
if (removeRules.length > 0) {
for (int i = 0; i < removeRules.length; i++) {
sb.append(removeRules[i]).append(',');
}
args += " -d " + sb.toString();
}
result = callHostPlugin("setLoadBalancerRule", "args", args);
if (result == null || result.isEmpty()) {
return new Answer(cmd, false, "LoadBalancerCfgCommand failed");
}
callHostPlugin("deleteFile", "filepath", tmpCfgFilePath);
return new Answer(cmd);
}
protected synchronized Answer execute(final DhcpEntryCommand cmd) {
String args = "-r " + cmd.getRouterPrivateIpAddress();
args += " -v " + cmd.getVmIpAddress();
args += " -m " + cmd.getVmMac();
args += " -n " + cmd.getVmName();
String result = callHostPlugin("saveDhcpEntry", "args", args);
if (result == null || result.isEmpty()) {
return new Answer(cmd, false, "DhcpEntry failed");
}
return new Answer(cmd);
}
protected Answer execute(final VmDataCommand cmd) {
String routerPrivateIpAddress = cmd.getRouterPrivateIpAddress();
String vmIpAddress = cmd.getVmIpAddress();
List<String[]> vmData = cmd.getVmData();
String[] vmDataArgs = new String[vmData.size() * 2 + 4];
vmDataArgs[0] = "routerIP";
vmDataArgs[1] = routerPrivateIpAddress;
vmDataArgs[2] = "vmIP";
vmDataArgs[3] = vmIpAddress;
int i = 4;
for (String[] vmDataEntry : vmData) {
String folder = vmDataEntry[0];
String file = vmDataEntry[1];
String contents = (vmDataEntry[2] != null) ? vmDataEntry[2] : "none";
vmDataArgs[i] = folder + "," + file;
vmDataArgs[i + 1] = contents;
i += 2;
}
String result = callHostPlugin("vm_data", vmDataArgs);
if (result == null || result.isEmpty()) {
return new Answer(cmd, false, "vm_data failed");
} else {
return new Answer(cmd);
}
}
protected Answer execute(final SavePasswordCommand cmd) {
final String password = cmd.getPassword();
final String routerPrivateIPAddress = cmd.getRouterPrivateIpAddress();
final String vmName = cmd.getVmName();
final String vmIpAddress = cmd.getVmIpAddress();
final String local = vmName;
// Run save_password_to_domr.sh
String args = "-r " + routerPrivateIPAddress;
args += " -v " + vmIpAddress;
args += " -p " + password;
args += " " + local;
String result = callHostPlugin("savePassword", "args", args);
if (result == null || result.isEmpty()) {
return new Answer(cmd, false, "savePassword failed");
}
return new Answer(cmd);
}
protected void assignPublicIpAddress(final String vmName, final String privateIpAddress, final String publicIpAddress, final boolean add, final boolean firstIP,
final boolean sourceNat, final String vlanId, final String vlanGateway, final String vlanNetmask, final String vifMacAddress) throws InternalErrorException {
try {
Connection conn = getConnection();
VM router = getVM(conn, vmName);
// Determine the correct VIF on DomR to associate/disassociate the
// IP address with
VIF correctVif = getCorrectVif(router, vlanId);
// If we are associating an IP address and DomR doesn't have a VIF
// for the specified vlan ID, we need to add a VIF
// If we are disassociating the last IP address in the VLAN, we need
// to remove a VIF
boolean addVif = false;
boolean removeVif = false;
if (add && correctVif == null) {
addVif = true;
s_logger.info("ipassoc: Need to add a vif to the virtual router since the ip is in a new subnet " + publicIpAddress);
} else if (!add && firstIP) {
removeVif = true;
s_logger.info("ipassoc: Need to remove a vif to the virtual router since the removed ip is the last one " + publicIpAddress);
}
if (addVif) {
// Add a new VIF to DomR
String vifDeviceNum = getLowestAvailableVIFDeviceNum(router);
if (vifDeviceNum == null) {
throw new InternalErrorException("There were no more available slots for a new VIF on router: " + router.getNameLabel(conn));
}
correctVif = createVIF(conn, router, vifMacAddress, vlanId, 0, vifDeviceNum, true);
correctVif.plug(conn);
// Add iptables rule for network usage
networkUsage(privateIpAddress, "addVif", "eth" + correctVif.getDevice(conn));
}
if (correctVif == null) {
throw new InternalErrorException("Failed to find DomR VIF to associate/disassociate IP with.");
}
String args;
if (add) {
args = "-A";
} else {
args = "-D";
}
String cidrSize = Long.toString(NetUtils.getCidrSize(vlanNetmask));
if (sourceNat) {
args += " -f";
args += " -l ";
args += publicIpAddress + "/" + cidrSize;
s_logger.debug("ipassoc: source nat ip: " + publicIpAddress);
} else if (addVif || removeVif || firstIP) {
args += " -l ";
args += publicIpAddress + "/" + cidrSize;
s_logger.debug("ipassoc: first ip on vif: " + publicIpAddress);
} else {
args += " -l ";
args += publicIpAddress;
}
args += " -i ";
args += privateIpAddress;
args += " -c ";
args += "eth" + correctVif.getDevice(conn);
args += " -g ";
args += vlanGateway;
String result = callHostPlugin("ipassoc", "args", args);
if (result == null || result.isEmpty()) {
throw new InternalErrorException("Xen plugin \"ipassoc\" failed.");
}
if (removeVif) {
Network network = correctVif.getNetwork(conn);
// Mark this vif to be removed from network usage
networkUsage(privateIpAddress, "deleteVif", "eth" + correctVif.getDevice(conn));
// Remove the VIF from DomR
correctVif.unplug(conn);
correctVif.destroy(conn);
// Disable the VLAN network if necessary
disableVlanNetwork(network);
}
} catch (XenAPIException e) {
String msg = "Unable to assign public IP address due to " + e.toString();
s_logger.warn(msg, e);
throw new InternalErrorException(msg);
} catch (final XmlRpcException e) {
String msg = "Unable to assign public IP address due to " + e.getMessage();
s_logger.warn(msg, e);
throw new InternalErrorException(msg);
}
}
protected String networkUsage(final String privateIpAddress, final String option, final String vif) {
String args = null;
if (option.equals("get")) {
args = "-g";
} else if (option.equals("create")) {
args = "-c";
} else if (option.equals("reset")) {
args = "-r";
} else if (option.equals("addVif")) {
args = "-a";
args += vif;
} else if (option.equals("deleteVif")) {
args = "-d";
args += vif;
}
args += " -i ";
args += privateIpAddress;
return callHostPlugin("networkUsage", "args", args);
}
protected Answer execute(final IPAssocCommand cmd) {
try {
assignPublicIpAddress(cmd.getRouterName(), cmd.getRouterIp(), cmd.getPublicIp(), cmd.isAdd(), cmd.isFirstIP(), cmd.isSourceNat(), cmd.getVlanId(),
cmd.getVlanGateway(), cmd.getVlanNetmask(), cmd.getVifMacAddress());
} catch (InternalErrorException e) {
return new Answer(cmd, false, e.getMessage());
}
return new Answer(cmd);
}
protected GetVncPortAnswer execute(GetVncPortCommand cmd) {
Connection conn = getConnection();
try {
Set<VM> vms = VM.getByNameLabel(conn, cmd.getName());
return new GetVncPortAnswer(cmd, getVncPort(vms.iterator().next()));
} catch (XenAPIException e) {
s_logger.warn("Unable to get vnc port " + e.toString(), e);
return new GetVncPortAnswer(cmd, e.toString());
} catch (Exception e) {
s_logger.warn("Unable to get vnc port ", e);
return new GetVncPortAnswer(cmd, e.getMessage());
}
}
protected StorageResourceType getStorageResourceType() {
return StorageResourceType.STORAGE_POOL;
}
protected CheckHealthAnswer execute(CheckHealthCommand cmd) {
boolean result = pingxenserver();
return new CheckHealthAnswer(cmd, result);
}
protected WatchNetworkAnswer execute(WatchNetworkCommand cmd) {
WatchNetworkAnswer answer = new WatchNetworkAnswer(cmd);
for (String domr : _domrIPMap.keySet()) {
long[] stats = getNetworkStats(domr);
answer.addStats(domr, stats[0], stats[1]);
}
return answer;
}
protected long[] getNetworkStats(String domr) {
String result = networkUsage(_domrIPMap.get(domr), "get", null);
long[] stats = new long[2];
if (result != null) {
String[] splitResult = result.split(":");
int i = 0;
while (i < splitResult.length - 1) {
stats[0] += (new Long(splitResult[i++])).longValue();
stats[1] += (new Long(splitResult[i++])).longValue();
}
}
return stats;
}
/**
* This is the method called for getting the HOST stats
*
* @param cmd
* @return
*/
protected GetHostStatsAnswer execute(GetHostStatsCommand cmd) {
// Connection conn = getConnection();
try {
HostStatsEntry hostStats = getHostStats(cmd, cmd.getHostGuid(), cmd.getHostId());
return new GetHostStatsAnswer(cmd, hostStats);
} catch (Exception e) {
String msg = "Unable to get Host stats" + e.toString();
s_logger.warn(msg, e);
return new GetHostStatsAnswer(cmd, null);
}
}
protected HostStatsEntry getHostStats(GetHostStatsCommand cmd, String hostGuid, long hostId) {
HostStatsEntry hostStats = new HostStatsEntry(hostId, 0, 0, 0, 0, "host", 0, 0, 0, 0);
Object[] rrdData = getRRDData(1); // call rrd method with 1 for host
if (rrdData == null) {
return null;
}
Integer numRows = (Integer) rrdData[0];
Integer numColumns = (Integer) rrdData[1];
Node legend = (Node) rrdData[2];
Node dataNode = (Node) rrdData[3];
NodeList legendChildren = legend.getChildNodes();
for (int col = 0; col < numColumns; col++) {
if (legendChildren == null || legendChildren.item(col) == null) {
continue;
}
String columnMetadata = getXMLNodeValue(legendChildren.item(col));
if (columnMetadata == null) {
continue;
}
String[] columnMetadataList = columnMetadata.split(":");
if (columnMetadataList.length != 4) {
continue;
}
String type = columnMetadataList[1];
String param = columnMetadataList[3];
if (type.equalsIgnoreCase("host")) {
if (param.contains("pif_eth0_rx")) {
hostStats.setNetworkReadKBs(getDataAverage(dataNode, col, numRows));
}
if (param.contains("pif_eth0_tx")) {
hostStats.setNetworkWriteKBs(getDataAverage(dataNode, col, numRows));
}
if (param.contains("memory_total_kib")) {
hostStats.setTotalMemoryKBs(getDataAverage(dataNode, col, numRows));
}
if (param.contains("memory_free_kib")) {
hostStats.setFreeMemoryKBs(getDataAverage(dataNode, col, numRows));
}
if (param.contains("cpu")) {
hostStats.setNumCpus(hostStats.getNumCpus() + 1);
hostStats.setCpuUtilization(hostStats.getCpuUtilization() + getDataAverage(dataNode, col, numRows));
}
if (param.contains("loadavg")) {
hostStats.setAverageLoad((hostStats.getAverageLoad() + getDataAverage(dataNode, col, numRows)));
}
}
}
// add the host cpu utilization
if (hostStats.getNumCpus() != 0) {
hostStats.setCpuUtilization(hostStats.getCpuUtilization() / hostStats.getNumCpus());
s_logger.debug("Host cpu utilization " + hostStats.getCpuUtilization());
}
return hostStats;
}
protected GetVmStatsAnswer execute(GetVmStatsCommand cmd) {
List<String> vmNames = cmd.getVmNames();
HashMap<String, VmStatsEntry> vmStatsNameMap = new HashMap<String, VmStatsEntry>();
if( vmNames.size() == 0 ) {
return new GetVmStatsAnswer(cmd, vmStatsNameMap);
}
Connection conn = getConnection();
try {
// Determine the UUIDs of the requested VMs
List<String> vmUUIDs = new ArrayList<String>();
for (String vmName : vmNames) {
VM vm = getVM(conn, vmName);
vmUUIDs.add(vm.getUuid(conn));
}
HashMap<String, VmStatsEntry> vmStatsUUIDMap = getVmStats(cmd, vmUUIDs, cmd.getHostGuid());
if( vmStatsUUIDMap == null )
return new GetVmStatsAnswer(cmd, vmStatsNameMap);
for (String vmUUID : vmStatsUUIDMap.keySet()) {
vmStatsNameMap.put(vmNames.get(vmUUIDs.indexOf(vmUUID)), vmStatsUUIDMap.get(vmUUID));
}
return new GetVmStatsAnswer(cmd, vmStatsNameMap);
} catch (XenAPIException e) {
String msg = "Unable to get VM stats" + e.toString();
s_logger.warn(msg, e);
return new GetVmStatsAnswer(cmd, vmStatsNameMap);
} catch (XmlRpcException e) {
String msg = "Unable to get VM stats" + e.getMessage();
s_logger.warn(msg, e);
return new GetVmStatsAnswer(cmd, vmStatsNameMap);
}
}
protected HashMap<String, VmStatsEntry> getVmStats(GetVmStatsCommand cmd, List<String> vmUUIDs, String hostGuid) {
HashMap<String, VmStatsEntry> vmResponseMap = new HashMap<String, VmStatsEntry>();
for (String vmUUID : vmUUIDs) {
vmResponseMap.put(vmUUID, new VmStatsEntry(0, 0, 0, 0, "vm"));
}
Object[] rrdData = getRRDData(2); // call rrddata with 2 for vm
if (rrdData == null) {
return null;
}
Integer numRows = (Integer) rrdData[0];
Integer numColumns = (Integer) rrdData[1];
Node legend = (Node) rrdData[2];
Node dataNode = (Node) rrdData[3];
NodeList legendChildren = legend.getChildNodes();
for (int col = 0; col < numColumns; col++) {
if (legendChildren == null || legendChildren.item(col) == null) {
continue;
}
String columnMetadata = getXMLNodeValue(legendChildren.item(col));
if (columnMetadata == null) {
continue;
}
String[] columnMetadataList = columnMetadata.split(":");
if (columnMetadataList.length != 4) {
continue;
}
String type = columnMetadataList[1];
String uuid = columnMetadataList[2];
String param = columnMetadataList[3];
if (type.equals("vm") && vmResponseMap.keySet().contains(uuid)) {
VmStatsEntry vmStatsAnswer = vmResponseMap.get(uuid);
vmStatsAnswer.setEntityType("vm");
if (param.contains("cpu")) {
vmStatsAnswer.setNumCPUs(vmStatsAnswer.getNumCPUs() + 1);
vmStatsAnswer.setCPUUtilization(vmStatsAnswer.getCPUUtilization() + getDataAverage(dataNode, col, numRows));
} else if (param.equals("vif_0_rx")) {
vmStatsAnswer.setNetworkReadKBs(getDataAverage(dataNode, col, numRows)/(8*2));
} else if (param.equals("vif_0_tx")) {
vmStatsAnswer.setNetworkWriteKBs(getDataAverage(dataNode, col, numRows)/(8*2));
}
}
}
for (String vmUUID : vmResponseMap.keySet()) {
VmStatsEntry vmStatsAnswer = vmResponseMap.get(vmUUID);
if (vmStatsAnswer.getNumCPUs() != 0) {
vmStatsAnswer.setCPUUtilization(vmStatsAnswer.getCPUUtilization() / vmStatsAnswer.getNumCPUs());
s_logger.debug("Vm cpu utilization " + vmStatsAnswer.getCPUUtilization());
}
}
return vmResponseMap;
}
protected Object[] getRRDData(int flag) {
/*
* Note: 1 => called from host, hence host stats 2 => called from vm, hence vm stats
*/
String stats = "";
try {
if (flag == 1)
stats = getHostStatsRawXML();
if (flag == 2)
stats = getVmStatsRawXML();
} catch (Exception e1) {
s_logger.warn("Error whilst collecting raw stats from plugin:" + e1);
return null;
}
// s_logger.debug("The raw xml stream is:"+stats);
// s_logger.debug("Length of raw xml is:"+stats.length());
//stats are null when the host plugin call fails (host down state)
if(stats == null)
return null;
StringReader statsReader = new StringReader(stats);
InputSource statsSource = new InputSource(statsReader);
Document doc = null;
try {
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(statsSource);
} catch (Exception e) {
}
NodeList firstLevelChildren = doc.getChildNodes();
NodeList secondLevelChildren = (firstLevelChildren.item(0)).getChildNodes();
Node metaNode = secondLevelChildren.item(0);
Node dataNode = secondLevelChildren.item(1);
Integer numRows = 0;
Integer numColumns = 0;
Node legend = null;
NodeList metaNodeChildren = metaNode.getChildNodes();
for (int i = 0; i < metaNodeChildren.getLength(); i++) {
Node n = metaNodeChildren.item(i);
if (n.getNodeName().equals("rows")) {
numRows = Integer.valueOf(getXMLNodeValue(n));
} else if (n.getNodeName().equals("columns")) {
numColumns = Integer.valueOf(getXMLNodeValue(n));
} else if (n.getNodeName().equals("legend")) {
legend = n;
}
}
return new Object[] { numRows, numColumns, legend, dataNode };
}
protected String getXMLNodeValue(Node n) {
return n.getChildNodes().item(0).getNodeValue();
}
protected double getDataAverage(Node dataNode, int col, int numRows) {
double value = 0;
double dummy = 0;
int numRowsUsed = 0;
for (int row = 0; row < numRows; row++) {
Node data = dataNode.getChildNodes().item(numRows - 1 - row).getChildNodes().item(col + 1);
Double currentDataAsDouble = Double.valueOf(getXMLNodeValue(data));
if (!currentDataAsDouble.equals(Double.NaN)) {
numRowsUsed += 1;
value += currentDataAsDouble;
}
}
if(numRowsUsed == 0)
{
if((!Double.isInfinite(value))&&(!Double.isNaN(value)))
{
return value;
}
else
{
s_logger.warn("Found an invalid value (infinity/NaN) in getDataAverage(), numRows=0");
return dummy;
}
}
else
{
if((!Double.isInfinite(value/numRowsUsed))&&(!Double.isNaN(value/numRowsUsed)))
{
return (value/numRowsUsed);
}
else
{
s_logger.warn("Found an invalid value (infinity/NaN) in getDataAverage(), numRows>0");
return dummy;
}
}
}
protected String getHostStatsRawXML() {
Date currentDate = new Date();
String startTime = String.valueOf(currentDate.getTime() / 1000 - 1000);
return callHostPlugin("gethostvmstats", "collectHostStats", String.valueOf("true"), "consolidationFunction", _consolidationFunction, "interval", String
.valueOf(_pollingIntervalInSeconds), "startTime", startTime);
}
protected String getVmStatsRawXML() {
Date currentDate = new Date();
String startTime = String.valueOf(currentDate.getTime() / 1000 - 1000);
return callHostPlugin("gethostvmstats", "collectHostStats", String.valueOf("false"), "consolidationFunction", _consolidationFunction, "interval", String
.valueOf(_pollingIntervalInSeconds), "startTime", startTime);
}
protected void recordWarning(final VM vm, final String message, final Throwable e) {
Connection conn = getConnection();
final StringBuilder msg = new StringBuilder();
try {
final Long domId = vm.getDomid(conn);
msg.append("[").append(domId != null ? domId : -1l).append("] ");
} catch (final BadServerResponse e1) {
} catch (final XmlRpcException e1) {
} catch (XenAPIException e1) {
}
msg.append(message);
}
protected State convertToState(Types.VmPowerState ps) {
final State state = s_statesTable.get(ps);
return state == null ? State.Unknown : state;
}
protected HashMap<String, State> getAllVms() {
final HashMap<String, State> vmStates = new HashMap<String, State>();
Connection conn = getConnection();
Set<VM> vms = null;
for (int i = 0; i < 2; i++) {
try {
Host host = Host.getByUuid(conn, _host.uuid);
vms = host.getResidentVMs(conn);
break;
} catch (final Throwable e) {
s_logger.warn("Unable to get vms", e);
}
try {
Thread.sleep(1000);
} catch (final InterruptedException ex) {
}
}
if (vms == null) {
return null;
}
for (VM vm : vms) {
VM.Record record = null;
for (int i = 0; i < 2; i++) {
try {
record = vm.getRecord(conn);
break;
} catch (XenAPIException e1) {
s_logger.debug("VM.getRecord failed on host:" + _host.uuid + " due to " + e1.toString());
} catch (XmlRpcException e1) {
s_logger.debug("VM.getRecord failed on host:" + _host.uuid + " due to " + e1.getMessage());
}
try {
Thread.sleep(1000);
} catch (final InterruptedException ex) {
}
}
if (record == null) {
continue;
}
if (record.isControlDomain || record.isASnapshot || record.isATemplate) {
continue; // Skip DOM0
}
VmPowerState ps = record.powerState;
final State state = convertToState(ps);
if (s_logger.isTraceEnabled()) {
s_logger.trace("VM " + record.nameLabel + ": powerstate = " + ps + "; vm state=" + state.toString());
}
vmStates.put(record.nameLabel, state);
}
return vmStates;
}
protected State getVmState(final String vmName) {
Connection conn = getConnection();
int retry = 3;
while (retry-- > 0) {
try {
Set<VM> vms = VM.getByNameLabel(conn, vmName);
for (final VM vm : vms) {
return convertToState(vm.getPowerState(conn));
}
} catch (final BadServerResponse e) {
// There is a race condition within xen such that if a vm is
// deleted and we
// happen to ask for it, it throws this stupid response. So
// if this happens,
// we take a nap and try again which then avoids the race
// condition because
// the vm's information is now cleaned up by xen. The error
// is as follows
// com.xensource.xenapi.Types$BadServerResponse
// [HANDLE_INVALID, VM,
// 3dde93f9-c1df-55a7-2cde-55e1dce431ab]
s_logger.info("Unable to get a vm PowerState due to " + e.toString() + ". We are retrying. Count: " + retry);
try {
Thread.sleep(3000);
} catch (final InterruptedException ex) {
}
} catch (XenAPIException e) {
String msg = "Unable to get a vm PowerState due to " + e.toString();
s_logger.warn(msg, e);
break;
} catch (final XmlRpcException e) {
String msg = "Unable to get a vm PowerState due to " + e.getMessage();
s_logger.warn(msg, e);
break;
}
}
return State.Stopped;
}
protected CheckVirtualMachineAnswer execute(final CheckVirtualMachineCommand cmd) {
final String vmName = cmd.getVmName();
final State state = getVmState(vmName);
Integer vncPort = null;
if (state == State.Running) {
synchronized (_vms) {
_vms.put(vmName, State.Running);
}
}
return new CheckVirtualMachineAnswer(cmd, state, vncPort);
}
protected PrepareForMigrationAnswer execute(final PrepareForMigrationCommand cmd) {
/*
*
* String result = null;
*
* List<VolumeVO> vols = cmd.getVolumes(); result = mountwithoutvdi(vols, cmd.getMappings()); if (result !=
* null) { return new PrepareForMigrationAnswer(cmd, false, result); }
*/
final String vmName = cmd.getVmName();
try {
Connection conn = getConnection();
Set<Host> hosts = Host.getAll(conn);
// workaround before implementing xenserver pool
// no migration
if (hosts.size() <= 1) {
return new PrepareForMigrationAnswer(cmd, false, "not in a same xenserver pool");
}
// if the vm have CD
// 1. make iosSR shared
// 2. create pbd in target xenserver
SR sr = getISOSRbyVmName(cmd.getVmName());
if (sr != null) {
Set<PBD> pbds = sr.getPBDs(conn);
boolean found = false;
for (PBD pbd : pbds) {
if (Host.getByUuid(conn, _host.uuid).equals(pbd.getHost(conn))) {
found = true;
break;
}
}
if (!found) {
sr.setShared(conn, true);
PBD pbd = pbds.iterator().next();
PBD.Record pbdr = new PBD.Record();
pbdr.deviceConfig = pbd.getDeviceConfig(conn);
pbdr.host = Host.getByUuid(conn, _host.uuid);
pbdr.SR = sr;
PBD newpbd = PBD.create(conn, pbdr);
newpbd.plug(conn);
}
}
Set<VM> vms = VM.getByNameLabel(conn, vmName);
if (vms.size() != 1) {
String msg = "There are " + vms.size() + " " + vmName;
s_logger.warn(msg);
return new PrepareForMigrationAnswer(cmd, false, msg);
}
VM vm = vms.iterator().next();
// check network
Set<VIF> vifs = vm.getVIFs(conn);
for (VIF vif : vifs) {
Network network = vif.getNetwork(conn);
Set<PIF> pifs = network.getPIFs(conn);
Long vlan = null;
PIF npif = null;
for (PIF pif : pifs) {
try {
vlan = pif.getVLAN(conn);
if (vlan != null) {
VLAN vland = pif.getVLANMasterOf(conn);
npif = vland.getTaggedPIF(conn);
break;
}
}catch (Exception e) {
vlan = null;
continue;
}
}
if (vlan == null) {
continue;
}
network = npif.getNetwork(conn);
String nwuuid = network.getUuid(conn);
String pifuuid = null;
if(nwuuid.equalsIgnoreCase(_host.guestNetwork)) {
pifuuid = _host.guestPif;
} else if(nwuuid.equalsIgnoreCase(_host.publicNetwork)) {
pifuuid = _host.publicPif;
} else if(nwuuid.equalsIgnoreCase(_host.privateNetwork)) {
pifuuid = _host.privatePif;
} else {
continue;
}
Network vlanNetwork = enableVlanNetwork(vlan, pifuuid);
if (vlanNetwork == null) {
throw new InternalErrorException("Failed to enable VLAN network with tag: " + vlan);
}
}
synchronized (_vms) {
_vms.put(cmd.getVmName(), State.Migrating);
}
return new PrepareForMigrationAnswer(cmd, true, null);
} catch (Exception e) {
String msg = "catch exception " + e.getMessage();
s_logger.warn(msg, e);
return new PrepareForMigrationAnswer(cmd, false, msg);
}
}
public DownloadAnswer execute(final PrimaryStorageDownloadCommand cmd) {
SR tmpltsr = null;
String tmplturl = cmd.getUrl();
int index = tmplturl.lastIndexOf("/");
String mountpoint = tmplturl.substring(0, index);
String tmpltname = null;
if (index < tmplturl.length() - 1)
tmpltname = tmplturl.substring(index + 1).replace(".vhd", "");
try {
Connection conn = getConnection();
String pUuid = cmd.getPoolUuid();
SR poolsr = null;
Set<SR> srs = SR.getByNameLabel(conn, pUuid);
if (srs.size() != 1) {
String msg = "There are " + srs.size() + " SRs with same name: " + pUuid;
s_logger.warn(msg);
return new DownloadAnswer(null, 0, msg, com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR, "", "", 0);
} else {
poolsr = srs.iterator().next();
}
/* Does the template exist in primary storage pool? If yes, no copy */
VDI vmtmpltvdi = null;
VDI snapshotvdi = null;
Set<VDI> vdis = VDI.getByNameLabel(conn, "Template " + cmd.getName());
for (VDI vdi : vdis) {
VDI.Record vdir = vdi.getRecord(conn);
if (vdir.SR.equals(poolsr)) {
vmtmpltvdi = vdi;
break;
}
}
String uuid;
if (vmtmpltvdi == null) {
tmpltsr = createNfsSRbyURI(new URI(mountpoint), false);
tmpltsr.scan(conn);
VDI tmpltvdi = null;
if (tmpltname != null) {
tmpltvdi = getVDIbyUuid(tmpltname);
}
if (tmpltvdi == null) {
vdis = tmpltsr.getVDIs(conn);
for (VDI vdi : vdis) {
tmpltvdi = vdi;
break;
}
}
if (tmpltvdi == null) {
String msg = "Unable to find template vdi on secondary storage" + "host:" + _host.uuid + "pool: " + tmplturl;
s_logger.warn(msg);
return new DownloadAnswer(null, 0, msg, com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR, "", "", 0);
}
vmtmpltvdi = cloudVDIcopy(tmpltvdi, poolsr);
snapshotvdi = vmtmpltvdi.snapshot(conn, new HashMap<String, String>());
vmtmpltvdi.destroy(conn);
try{
poolsr.scan(conn);
} catch (Exception e) {
}
snapshotvdi.setNameLabel(conn, "Template " + cmd.getName());
// vmtmpltvdi.setNameDescription(conn, cmd.getDescription());
uuid = snapshotvdi.getUuid(conn);
vmtmpltvdi = snapshotvdi;
} else
uuid = vmtmpltvdi.getUuid(conn);
// Determine the size of the template
long phySize = vmtmpltvdi.getPhysicalUtilisation(conn);
DownloadAnswer answer = new DownloadAnswer(null, 100, cmd, com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED, uuid, uuid);
answer.setTemplateSize(phySize);
return answer;
} catch (XenAPIException e) {
String msg = "XenAPIException:" + e.toString() + "host:" + _host.uuid + "pool: " + tmplturl;
s_logger.warn(msg, e);
return new DownloadAnswer(null, 0, msg, com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR, "", "", 0);
} catch (Exception e) {
String msg = "XenAPIException:" + e.getMessage() + "host:" + _host.uuid + "pool: " + tmplturl;
s_logger.warn(msg, e);
return new DownloadAnswer(null, 0, msg, com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR, "", "", 0);
} finally {
removeSR(tmpltsr);
}
}
protected String removeSRSync(SR sr) {
if (sr == null) {
return null;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug(logX(sr, "Removing SR"));
}
Connection conn = getConnection();
long waittime = 0;
try {
Set<VDI> vdis = sr.getVDIs(conn);
for (VDI vdi : vdis) {
Map<java.lang.String, Types.VdiOperations> currentOperation = vdi.getCurrentOperations(conn);
if (currentOperation == null || currentOperation.size() == 0) {
continue;
}
if (waittime >= 1800000) {
String msg = "This template is being used, try late time";
s_logger.warn(msg);
return msg;
}
waittime += 30000;
try {
Thread.sleep(30000);
} catch (final InterruptedException ex) {
}
}
removeSR(sr);
return null;
} catch (XenAPIException e) {
s_logger.warn(logX(sr, "Unable to get current opertions " + e.toString()), e);
} catch (XmlRpcException e) {
s_logger.warn(logX(sr, "Unable to get current opertions " + e.getMessage()), e);
}
String msg = "Remove SR failed";
s_logger.warn(msg);
return msg;
}
protected void removeSR(SR sr) {
if (sr == null) {
return;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug(logX(sr, "Removing SR"));
}
for (int i = 0; i < 2; i++) {
Connection conn = getConnection();
try {
Set<VDI> vdis = sr.getVDIs(conn);
for (VDI vdi : vdis) {
vdi.forget(conn);
}
Set<PBD> pbds = sr.getPBDs(conn);
for (PBD pbd : pbds) {
if (s_logger.isDebugEnabled()) {
s_logger.debug(logX(pbd, "Unplugging pbd"));
}
if (pbd.getCurrentlyAttached(conn)) {
pbd.unplug(conn);
}
pbd.destroy(conn);
}
pbds = sr.getPBDs(conn);
if (pbds.size() == 0) {
if (s_logger.isDebugEnabled()) {
s_logger.debug(logX(sr, "Forgetting"));
}
sr.forget(conn);
return;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug(logX(sr, "There are still pbd attached"));
if (s_logger.isTraceEnabled()) {
for (PBD pbd : pbds) {
s_logger.trace(logX(pbd, " Still attached"));
}
}
}
} catch (XenAPIException e) {
s_logger.debug(logX(sr, "Catch XenAPIException: " + e.toString()));
} catch (XmlRpcException e) {
s_logger.debug(logX(sr, "Catch Exception: " + e.getMessage()));
}
}
s_logger.warn(logX(sr, "Unable to remove SR"));
}
protected MigrateAnswer execute(final MigrateCommand cmd) {
final String vmName = cmd.getVmName();
State state = null;
synchronized (_vms) {
state = _vms.get(vmName);
_vms.put(vmName, State.Stopping);
}
try {
Connection conn = getConnection();
Set<VM> vms = VM.getByNameLabel(conn, vmName);
String ipaddr = cmd.getDestinationIp();
Set<Host> hosts = Host.getAll(conn);
Host dsthost = null;
for (Host host : hosts) {
if (host.getAddress(conn).equals(ipaddr)) {
dsthost = host;
break;
}
}
// if it is windows, we will not fake it is migrateable,
// windows requires PV driver to migrate
for (VM vm : vms) {
if (!cmd.isWindows()) {
String uuid = vm.getUuid(conn);
String result = callHostPlugin("preparemigration", "uuid", uuid);
if (result == null || result.isEmpty()) {
return new MigrateAnswer(cmd, false, "migration failed", null);
}
// check if pv version is successfully set up
int i = 0;
for (; i < 20; i++) {
try {
Thread.sleep(1000);
} catch (final InterruptedException ex) {
}
VMGuestMetrics vmmetric = vm.getGuestMetrics(conn);
if (isRefNull(vmmetric))
continue;
Map<String, String> PVversion = vmmetric.getPVDriversVersion(conn);
if (PVversion != null && PVversion.containsKey("major")) {
break;
}
}
Set<VBD> vbds = vm.getVBDs(conn);
for( VBD vbd : vbds) {
VBD.Record vbdRec = vbd.getRecord(conn);
if( vbdRec.type.equals(Types.VbdType.CD.toString()) && !vbdRec.empty ) {
vbd.eject(conn);
break;
}
}
if (i >= 20) {
String msg = "migration failed due to can not fake PV driver for " + vmName;
s_logger.warn(msg);
return new MigrateAnswer(cmd, false, msg, null);
}
}
final Map<String, String> options = new HashMap<String, String>();
vm.poolMigrate(conn, dsthost, options);
state = State.Stopping;
}
return new MigrateAnswer(cmd, true, "migration succeeded", null);
} catch (XenAPIException e) {
String msg = "migration failed due to " + e.toString();
s_logger.warn(msg, e);
return new MigrateAnswer(cmd, false, msg, null);
} catch (XmlRpcException e) {
String msg = "migration failed due to " + e.getMessage();
s_logger.warn(msg, e);
return new MigrateAnswer(cmd, false, msg, null);
} finally {
synchronized (_vms) {
_vms.put(vmName, state);
}
}
}
protected State getRealPowerState(String label) {
Connection conn = getConnection();
int i = 0;
s_logger.trace("Checking on the HALTED State");
for (; i < 20; i++) {
try {
Set<VM> vms = VM.getByNameLabel(conn, label);
if (vms == null || vms.size() == 0) {
continue;
}
VM vm = vms.iterator().next();
VmPowerState vps = vm.getPowerState(conn);
if (vps != null && vps != VmPowerState.HALTED && vps != VmPowerState.UNKNOWN && vps != VmPowerState.UNRECOGNIZED) {
return convertToState(vps);
}
} catch (XenAPIException e) {
String msg = "Unable to get real power state due to " + e.toString();
s_logger.warn(msg, e);
} catch (XmlRpcException e) {
String msg = "Unable to get real power state due to " + e.getMessage();
s_logger.warn(msg, e);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
return State.Stopped;
}
protected Pair<VM, VM.Record> getControlDomain(Connection conn) throws XenAPIException, XmlRpcException {
Host host = Host.getByUuid(conn, _host.uuid);
Set<VM> vms = null;
vms = host.getResidentVMs(conn);
for (VM vm : vms) {
if (vm.getIsControlDomain(conn)) {
return new Pair<VM, VM.Record>(vm, vm.getRecord(conn));
}
}
throw new CloudRuntimeException("Com'on no control domain? What the crap?!#@!##$@");
}
protected HashMap<String, State> sync() {
HashMap<String, State> newStates;
HashMap<String, State> oldStates = null;
final HashMap<String, State> changes = new HashMap<String, State>();
synchronized (_vms) {
newStates = getAllVms();
if (newStates == null) {
s_logger.debug("Unable to get the vm states so no state sync at this point.");
return null;
}
oldStates = new HashMap<String, State>(_vms.size());
oldStates.putAll(_vms);
for (final Map.Entry<String, State> entry : newStates.entrySet()) {
final String vm = entry.getKey();
State newState = entry.getValue();
final State oldState = oldStates.remove(vm);
if (newState == State.Stopped && oldState != State.Stopping && oldState != null && oldState != State.Stopped) {
newState = getRealPowerState(vm);
}
if (s_logger.isTraceEnabled()) {
s_logger.trace("VM " + vm + ": xen has state " + newState + " and we have state " + (oldState != null ? oldState.toString() : "null"));
}
if (vm.startsWith("migrating")) {
s_logger.debug("Migrating from xen detected. Skipping");
continue;
}
if (oldState == null) {
_vms.put(vm, newState);
s_logger.debug("Detecting a new state but couldn't find a old state so adding it to the changes: " + vm);
changes.put(vm, newState);
} else if (oldState == State.Starting) {
if (newState == State.Running) {
_vms.put(vm, newState);
} else if (newState == State.Stopped) {
s_logger.debug("Ignoring vm " + vm + " because of a lag in starting the vm.");
}
} else if (oldState == State.Migrating) {
if (newState == State.Running) {
s_logger.debug("Detected that an migrating VM is now running: " + vm);
_vms.put(vm, newState);
}
} else if (oldState == State.Stopping) {
if (newState == State.Stopped) {
_vms.put(vm, newState);
} else if (newState == State.Running) {
s_logger.debug("Ignoring vm " + vm + " because of a lag in stopping the vm. ");
}
} else if (oldState != newState) {
_vms.put(vm, newState);
if (newState == State.Stopped) {
/*
* if (_vmsKilled.remove(vm)) { s_logger.debug("VM " + vm + " has been killed for storage. ");
* newState = State.Error; }
*/
}
changes.put(vm, newState);
}
}
for (final Map.Entry<String, State> entry : oldStates.entrySet()) {
final String vm = entry.getKey();
final State oldState = entry.getValue();
if (s_logger.isTraceEnabled()) {
s_logger.trace("VM " + vm + " is now missing from xen so reporting stopped");
}
if (oldState == State.Stopping) {
s_logger.debug("Ignoring VM " + vm + " in transition state stopping.");
_vms.remove(vm);
} else if (oldState == State.Starting) {
s_logger.debug("Ignoring VM " + vm + " in transition state starting.");
} else if (oldState == State.Stopped) {
_vms.remove(vm);
} else if (oldState == State.Migrating) {
s_logger.debug("Ignoring VM " + vm + " in migrating state.");
} else {
State state = State.Stopped;
/*
* if (_vmsKilled.remove(entry.getKey())) { s_logger.debug("VM " + vm +
* " has been killed by storage monitor"); state = State.Error; }
*/
changes.put(entry.getKey(), state);
}
}
}
return changes;
}
protected ReadyAnswer execute(ReadyCommand cmd) {
Long dcId = cmd.getDataCenterId();
// Ignore the result of the callHostPlugin. Even if unmounting the
// snapshots dir fails, let Ready command
// succeed.
callHostPlugin("unmountSnapshotsDir", "dcId", dcId.toString());
return new ReadyAnswer(cmd);
}
//
// using synchronized on VM name in the caller does not prevent multiple
// commands being sent against
// the same VM, there will be a race condition here in finally clause and
// the main block if
// there are multiple requests going on
//
// Therefore, a lazy solution is to add a synchronized guard here
protected int getVncPort(VM vm) {
Connection conn = getConnection();
VM.Record record;
try {
record = vm.getRecord(conn);
} catch (XenAPIException e) {
String msg = "Unable to get vnc-port due to " + e.toString();
s_logger.warn(msg, e);
return -1;
} catch (XmlRpcException e) {
String msg = "Unable to get vnc-port due to " + e.getMessage();
s_logger.warn(msg, e);
return -1;
}
String hvm = "true";
if (record.HVMBootPolicy.isEmpty()) {
hvm = "false";
}
String vncport = callHostPlugin("getvncport", "domID", record.domid.toString(), "hvm", hvm);
if (vncport == null || vncport.isEmpty()) {
return -1;
}
vncport = vncport.replace("\n", "");
return NumbersUtil.parseInt(vncport, -1);
}
protected Answer execute(final RebootCommand cmd) {
synchronized (_vms) {
_vms.put(cmd.getVmName(), State.Starting);
}
try {
Connection conn = getConnection();
Set<VM> vms = null;
try {
vms = VM.getByNameLabel(conn, cmd.getVmName());
} catch (XenAPIException e0) {
s_logger.debug("getByNameLabel failed " + e0.toString());
return new RebootAnswer(cmd, "getByNameLabel failed " + e0.toString());
} catch (Exception e0) {
s_logger.debug("getByNameLabel failed " + e0.getMessage());
return new RebootAnswer(cmd, "getByNameLabel failed");
}
for (VM vm : vms) {
try {
rebootVM(conn, vm, vm.getNameLabel(conn));
} catch (Exception e) {
String msg = e.toString();
s_logger.warn(msg, e);
return new RebootAnswer(cmd, msg);
}
}
return new RebootAnswer(cmd, "reboot succeeded", null, null);
} finally {
synchronized (_vms) {
_vms.put(cmd.getVmName(), State.Running);
}
}
}
protected Answer execute(RebootRouterCommand cmd) {
long[] stats = getNetworkStats(cmd.getVmName());
Long bytesSent = stats[0];
Long bytesRcvd = stats[1];
_domrIPMap.remove(cmd.getVmName());
RebootAnswer answer = (RebootAnswer) execute((RebootCommand) cmd);
answer.setBytesSent(bytesSent);
answer.setBytesReceived(bytesRcvd);
_domrIPMap.put(cmd.getVmName(), cmd.getPrivateIpAddress());
if (answer.getResult()) {
String cnct = connect(cmd.getVmName(), cmd.getPrivateIpAddress());
networkUsage(cmd.getPrivateIpAddress(), "create", null);
if (cnct == null) {
return answer;
} else {
return new Answer(cmd, false, cnct);
}
}
return answer;
}
protected VM createVmFromTemplate(Connection conn, StartCommand cmd) throws XenAPIException, XmlRpcException {
Set<VM> templates;
VM vm = null;
String guestOsTypeName = getGuestOsType(cmd.getGuestOSDescription(), false);
templates = VM.getByNameLabel(conn, guestOsTypeName);
assert templates.size() == 1 : "Should only have 1 template but found " + templates.size();
VM template = templates.iterator().next();
vm = template.createClone(conn, cmd.getVmName());
vm.removeFromOtherConfig(conn, "disks");
if (!(guestOsTypeName.startsWith("Windows") || guestOsTypeName.startsWith("Citrix") || guestOsTypeName.startsWith("Other"))) {
if (cmd.getBootFromISO()) {
vm.setPVBootloader(conn, "eliloader");
Map<String, String> otherConfig = vm.getOtherConfig(conn);
otherConfig.put( "install-repository", "cdrom");
vm.setOtherConfig(conn, otherConfig);
} else {
vm.setPVBootloader(conn, "pygrub");
}
}
return vm;
}
public boolean joinPool(String masterIp, String username, String password) {
Connection hostConn = null;
Connection poolConn = null;
Session hostSession = null;
URL hostUrl = null;
try {
// Connect and find out about the new connection to the new pool.
poolConn = _connPool.masterConnect(masterIp, username, password);
Set<Pool> pools = Pool.getAll(poolConn);
Pool pool = pools.iterator().next();
String poolUUID = pool.getUuid(poolConn);
//check if this host is already in pool
Set<Host> hosts = Host.getAll(poolConn);
for( Host host : hosts ) {
if(host.getAddress(poolConn).equals(_host.ip)) {
return true;
}
}
hostUrl = new URL("http://" + _host.ip);
hostConn = new Connection(hostUrl, 100);
hostSession = Session.loginWithPassword(hostConn, _username, _password, APIVersion.latest().toString());
// Now join it.
Pool.join(hostConn, masterIp, username, password);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Joined the pool at " + masterIp);
}
try {
// slave will restart xapi in 10 sec
Thread.sleep(10000);
} catch (InterruptedException e) {
}
// check if the master of this host is set correctly.
Connection c = new Connection(hostUrl, 100);
int i;
for (i = 0 ; i < 15; i++) {
try {
Session.loginWithPassword(c, _username, _password, APIVersion.latest().toString());
s_logger.debug(_host.ip + " is still master, waiting for the conversion to the slave");
Session.logout(c);
c.dispose();
} catch (Types.HostIsSlave e) {
try {
Session.logout(c);
c.dispose();
} catch (XmlRpcException e1) {
s_logger.debug("Unable to logout of test connection due to " + e1.getMessage());
} catch (XenAPIException e1) {
s_logger.debug("Unable to logout of test connection due to " + e1.getMessage());
}
break;
} catch (XmlRpcException e) {
s_logger.debug("XmlRpcException: Still waiting for the conversion to the master");
} catch (Exception e) {
s_logger.debug("Exception: Still waiting for the conversion to the master");
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
if( i >= 15 ) {
throw new CloudRuntimeException(_host.ip + " didn't change to slave after waiting 30 secondary");
}
_host.pool = poolUUID;
return true;
} catch (MalformedURLException e) {
throw new CloudRuntimeException("Problem with url " + _host.ip);
} catch (XenAPIException e) {
String msg = "Unable to allow host " + _host.uuid
+ " to join pool " + masterIp + " due to " + e.toString();
s_logger.warn(msg, e);
throw new RuntimeException(msg);
} catch (XmlRpcException e) {
String msg = "Unable to allow host " + _host.uuid
+ " to join pool " + masterIp + " due to " + e.getMessage();
s_logger.warn(msg, e);
throw new RuntimeException(msg);
} finally {
if (poolConn != null) {
try {
Session.logout(poolConn);
} catch (Exception e) {
}
poolConn.dispose();
}
if(hostSession != null) {
try {
Session.logout(hostConn);
} catch (Exception e) {
}
}
}
}
protected void startvmfailhandle(VM vm, List<Ternary<SR, VDI, VolumeVO>> mounts) {
Connection conn = getConnection();
if (vm != null) {
try {
if (vm.getPowerState(conn) == VmPowerState.RUNNING) {
try {
vm.hardShutdown(conn);
} catch (Exception e) {
String msg = "VM hardshutdown failed due to " + e.toString();
s_logger.warn(msg);
}
}
if (vm.getPowerState(conn) == VmPowerState.HALTED) {
try {
vm.destroy(conn);
} catch (Exception e) {
String msg = "VM destroy failed due to " + e.toString();
s_logger.warn(msg);
}
}
} catch (Exception e) {
String msg = "VM getPowerState failed due to " + e.toString();
s_logger.warn(msg);
}
}
if (mounts != null) {
for (Ternary<SR, VDI, VolumeVO> mount : mounts) {
VDI vdi = mount.second();
Set<VBD> vbds = null;
try {
vbds = vdi.getVBDs(conn);
} catch (Exception e) {
String msg = "VDI getVBDS failed due to " + e.toString();
s_logger.warn(msg);
continue;
}
for (VBD vbd : vbds) {
try {
vbd.unplug(conn);
vbd.destroy(conn);
} catch (Exception e) {
String msg = "VBD destroy failed due to " + e.toString();
s_logger.warn(msg);
}
}
}
}
}
protected void setMemory(Connection conn, VM vm, long memsize) throws XmlRpcException, XenAPIException {
vm.setMemoryStaticMin(conn, memsize);
vm.setMemoryDynamicMin(conn, memsize);
vm.setMemoryDynamicMax(conn, memsize);
vm.setMemoryStaticMax(conn, memsize);
}
protected StartAnswer execute(StartCommand cmd) {
State state = State.Stopped;
Connection conn = getConnection();
VM vm = null;
SR isosr = null;
List<Ternary<SR, VDI, VolumeVO>> mounts = null;
try {
synchronized (_vms) {
_vms.put(cmd.getVmName(), State.Starting);
}
List<VolumeVO> vols = cmd.getVolumes();
mounts = mount(vols);
vm = createVmFromTemplate(conn, cmd);
long memsize = cmd.getRamSize() * 1024L * 1024L;
setMemory(conn, vm, memsize);
vm.setIsATemplate(conn, false);
vm.setVCPUsMax(conn, (long) cmd.getCpu());
vm.setVCPUsAtStartup(conn, (long) cmd.getCpu());
Host host = Host.getByUuid(conn, _host.uuid);
vm.setAffinity(conn, host);
Map<String, String> vcpuparam = new HashMap<String, String>();
vcpuparam.put("weight", Integer.toString(cmd.getCpuWeight()));
vcpuparam.put("cap", Integer.toString(cmd.getUtilization()));
vm.setVCPUsParams(conn, vcpuparam);
boolean bootFromISO = cmd.getBootFromISO();
/* create root VBD */
VBD.Record vbdr = new VBD.Record();
Ternary<SR, VDI, VolumeVO> mount = mounts.get(0);
vbdr.VM = vm;
vbdr.VDI = mount.second();
vbdr.bootable = !bootFromISO;
vbdr.userdevice = "0";
vbdr.mode = Types.VbdMode.RW;
vbdr.type = Types.VbdType.DISK;
VBD.create(conn, vbdr);
/* determine available slots to attach data volumes to */
List<String> availableSlots = new ArrayList<String>();
availableSlots.add("1");
availableSlots.add("2");
availableSlots.add("4");
availableSlots.add("5");
availableSlots.add("6");
availableSlots.add("7");
/* create data VBDs */
for (int i = 1; i < mounts.size(); i++) {
mount = mounts.get(i);
// vdi.setNameLabel(conn, cmd.getVmName() + "-DATA");
vbdr.VM = vm;
vbdr.VDI = mount.second();
vbdr.bootable = false;
vbdr.userdevice = Long.toString(mount.third().getDeviceId());
vbdr.mode = Types.VbdMode.RW;
vbdr.type = Types.VbdType.DISK;
vbdr.unpluggable = true;
VBD.create(conn, vbdr);
}
/* create CD-ROM VBD */
VBD.Record cdromVBDR = new VBD.Record();
cdromVBDR.VM = vm;
cdromVBDR.empty = true;
cdromVBDR.bootable = bootFromISO;
cdromVBDR.userdevice = "3";
cdromVBDR.mode = Types.VbdMode.RO;
cdromVBDR.type = Types.VbdType.CD;
VBD cdromVBD = VBD.create(conn, cdromVBDR);
/* insert the ISO VDI if isoPath is not null */
String isopath = cmd.getISOPath();
if (isopath != null) {
int index = isopath.lastIndexOf("/");
String mountpoint = isopath.substring(0, index);
URI uri = new URI(mountpoint);
isosr = createIsoSRbyURI(uri, cmd.getVmName(), false);
String isoname = isopath.substring(index + 1);
VDI isovdi = getVDIbyLocationandSR(isoname, isosr);
if (isovdi == null) {
String msg = " can not find ISO " + cmd.getISOPath();
s_logger.warn(msg);
return new StartAnswer(cmd, msg);
} else {
cdromVBD.insert(conn, isovdi);
}
}
createVIF(conn, vm, cmd.getGuestMacAddress(), cmd.getGuestNetworkId(), cmd.getNetworkRateMbps(), "0", false);
if (cmd.getExternalMacAddress() != null && cmd.getExternalVlan() != null) {
createVIF(conn, vm, cmd.getExternalMacAddress(), cmd.getExternalVlan(), 0, "1", true);
}
/* set action after crash as destroy */
vm.setActionsAfterCrash(conn, Types.OnCrashBehaviour.DESTROY);
startVM(conn, host, vm, cmd.getVmName());
if (_canBridgeFirewall) {
String result = callHostPlugin("default_network_rules", "vmName", cmd.getVmName(), "vmIP", cmd
.getGuestIpAddress(), "vmMAC", cmd.getGuestMacAddress(), "vmID", Long.toString(cmd.getId()));
if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
s_logger.warn("Failed to program default network rules for vm " + cmd.getVmName());
} else {
s_logger.info("Programmed default network rules for vm " + cmd.getVmName());
}
}
state = State.Running;
return new StartAnswer(cmd);
} catch (XenAPIException e) {
String errormsg = e.toString();
String msg = "Exception caught while starting VM due to message:" + errormsg + " ("
+ e.getClass().getName() + ")";
startvmfailhandle(vm, mounts);
removeSR(isosr);
state = State.Stopped;
return new StartAnswer(cmd, msg);
} catch (Exception e) {
String msg = "Exception caught while starting VM due to message:" + e.getMessage();
s_logger.warn(msg, e);
startvmfailhandle(vm, mounts);
removeSR(isosr);
state = State.Stopped;
return new StartAnswer(cmd, msg);
} finally {
synchronized (_vms) {
_vms.put(cmd.getVmName(), state);
}
}
}
protected VIF createVIF(Connection conn, VM vm, String mac, int rate, String devNum, Network network) throws XenAPIException, XmlRpcException,
InternalErrorException {
VIF.Record vifr = new VIF.Record();
vifr.VM = vm;
vifr.device = devNum;
vifr.MAC = mac;
vifr.network = network;
if ( rate == 0 ) rate = 200;
vifr.qosAlgorithmType = "ratelimit";
vifr.qosAlgorithmParams = new HashMap<String, String>();
// convert mbs to kilobyte per second
vifr.qosAlgorithmParams.put("kbps", Integer.toString(rate * 128));
return VIF.create(conn, vifr);
}
protected VIF createVIF(Connection conn, VM vm, String mac, String vlanTag, int rate, String devNum, boolean isPub) throws XenAPIException, XmlRpcException,
InternalErrorException {
String nwUuid = (isPub ? _host.publicNetwork : _host.guestNetwork);
String pifUuid = (isPub ? _host.publicPif : _host.guestPif);
Network vlanNetwork = null;
if ("untagged".equalsIgnoreCase(vlanTag)) {
vlanNetwork = Network.getByUuid(conn, nwUuid);
} else {
vlanNetwork = enableVlanNetwork(Long.valueOf(vlanTag), pifUuid);
}
if (vlanNetwork == null) {
throw new InternalErrorException("Failed to enable VLAN network with tag: " + vlanTag);
}
return createVIF(conn, vm, mac, rate, devNum, vlanNetwork);
}
void shutdownVM(Connection conn, VM vm, String vmName) throws XmlRpcException {
try {
vm.cleanShutdown(conn);
} catch (Types.XenAPIException e) {
s_logger.debug("Unable to cleanShutdown VM(" + vmName + ") on host(" + _host.uuid +") due to " + e.toString() + ", try hard shutdown");
try {
vm.hardShutdown(conn);
} catch (Exception e1) {
String msg = "Unable to hardShutdown VM(" + vmName + ") on host(" + _host.uuid +") due to " + e.toString();
s_logger.warn(msg, e1);
throw new CloudRuntimeException(msg);
}
}
}
void rebootVM(Connection conn, VM vm, String vmName) throws XmlRpcException {
try {
vm.cleanReboot(conn);
} catch (XenAPIException e) {
s_logger.debug("Unable to Clean Reboot VM(" + vmName + ") on host(" + _host.uuid +") due to " + e.toString() + ", try hard reboot");
try {
vm.hardReboot(conn);
} catch (Exception e1) {
String msg = "Unable to hard Reboot VM(" + vmName + ") on host(" + _host.uuid +") due to " + e.toString();
s_logger.warn(msg, e1);
throw new CloudRuntimeException(msg);
}
}
}
void startVM(Connection conn, Host host, VM vm, String vmName) throws XmlRpcException {
try {
vm.startOn(conn, host, false, true);
} catch (Exception e) {
String msg = "Unable to start VM(" + vmName + ") on host(" + _host.uuid +") due to " + e.toString();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg);
}
}
protected StopAnswer execute(final StopCommand cmd) {
String vmName = cmd.getVmName();
try {
Connection conn = getConnection();
Set<VM> vms = VM.getByNameLabel(conn, vmName);
// stop vm which is running on this host or is in halted state
for (VM vm : vms) {
VM.Record vmr = vm.getRecord(conn);
if (vmr.powerState != VmPowerState.RUNNING)
continue;
if (isRefNull(vmr.residentOn))
continue;
if (vmr.residentOn.getUuid(conn).equals(_host.uuid))
continue;
vms.remove(vm);
}
if (vms.size() == 0) {
s_logger.warn("VM does not exist on XenServer" + _host.uuid);
synchronized (_vms) {
_vms.remove(vmName);
}
return new StopAnswer(cmd, "VM does not exist", 0, 0L, 0L);
}
Long bytesSent = 0L;
Long bytesRcvd = 0L;
for (VM vm : vms) {
VM.Record vmr = vm.getRecord(conn);
if (vmr.isControlDomain) {
String msg = "Tring to Shutdown control domain";
s_logger.warn(msg);
return new StopAnswer(cmd, msg);
}
if (vmr.powerState == VmPowerState.RUNNING && !isRefNull(vmr.residentOn) && !vmr.residentOn.getUuid(conn).equals(_host.uuid)) {
String msg = "Stop Vm " + vmName + " failed due to this vm is not running on this host: " + _host.uuid + " but host:" + vmr.residentOn.getUuid(conn);
s_logger.warn(msg);
return new StopAnswer(cmd, msg);
}
State state = null;
synchronized (_vms) {
state = _vms.get(vmName);
_vms.put(vmName, State.Stopping);
}
try {
if (vmr.powerState == VmPowerState.RUNNING) {
/* when stop a vm, set affinity to current xenserver */
vm.setAffinity(conn, vm.getResidentOn(conn));
if (VirtualMachineName.isValidRouterName(vmName)) {
long[] stats = getNetworkStats(vmName);
bytesSent = stats[0];
bytesRcvd = stats[1];
}
if (_canBridgeFirewall) {
String result = callHostPlugin("destroy_network_rules_for_vm", "vmName", cmd.getVmName());
if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
s_logger.warn("Failed to remove network rules for vm " + cmd.getVmName());
} else {
s_logger.info("Removed network rules for vm " + cmd.getVmName());
}
}
shutdownVM(conn, vm, vmName);
}
} catch (Exception e) {
String msg = "Catch exception " + e.getClass().toString() + " when stop VM:" + cmd.getVmName()+ " due to " + e.toString();
s_logger.debug(msg);
return new StopAnswer(cmd, msg);
} finally {
try {
if (vm.getPowerState(conn) == VmPowerState.HALTED) {
Set<VIF> vifs = vm.getVIFs(conn);
List<Network> networks = new ArrayList<Network>();
for (VIF vif : vifs) {
networks.add(vif.getNetwork(conn));
}
List<VDI> vdis = getVdis(vm);
vm.destroy(conn);
for( VDI vdi : vdis ){
umount(vdi);
}
state = State.Stopped;
SR sr = getISOSRbyVmName(cmd.getVmName());
removeSR(sr);
if (VirtualMachineName.isValidRouterName(vmName)) {
_domrIPMap.remove(vmName);
}
// Disable any VLAN networks that aren't used
// anymore
for (Network network : networks) {
if (network.getNameLabel(conn).startsWith("VLAN")) {
disableVlanNetwork(network);
}
}
} else {
String msg = "VM " + vmName + " shutdown succeed, but this vm is not in halted state, it is in " + vm.getPowerState(conn) + " state";
s_logger.warn(msg);
return new StopAnswer(cmd, msg);
}
} catch (XenAPIException e) {
String msg = "VM destroy failed in Stop " + vmName + " Command due to " + e.toString();
s_logger.warn(msg, e);
} catch (Exception e) {
String msg = "VM destroy failed in Stop " + vmName + " Command due to " + e.getMessage();
s_logger.warn(msg, e);
} finally {
synchronized (_vms) {
_vms.put(vmName, state);
}
}
}
}
return new StopAnswer(cmd, "Stop VM " + vmName + " Succeed", 0, bytesSent, bytesRcvd);
} catch (XenAPIException e) {
String msg = "Stop Vm " + vmName + " fail due to " + e.toString();
s_logger.warn(msg, e);
return new StopAnswer(cmd, msg);
} catch (XmlRpcException e) {
String msg = "Stop Vm " + vmName + " fail due to " + e.getMessage();
s_logger.warn(msg, e);
return new StopAnswer(cmd, msg);
}
}
private List<VDI> getVdis(VM vm) {
List<VDI> vdis = new ArrayList<VDI>();
try {
Connection conn = getConnection();
Set<VBD> vbds =vm.getVBDs(conn);
for( VBD vbd : vbds ) {
vdis.add(vbd.getVDI(conn));
}
} catch (XenAPIException e) {
String msg = "getVdis can not get VPD due to " + e.toString();
s_logger.warn(msg, e);
} catch (XmlRpcException e) {
String msg = "getVdis can not get VPD due to " + e.getMessage();
s_logger.warn(msg, e);
}
return vdis;
}
protected String connect(final String vmName, final String ipAddress, final int port) {
for (int i = 0; i <= _retry; i++) {
try {
Connection conn = getConnection();
Set<VM> vms = VM.getByNameLabel(conn, vmName);
if (vms.size() < 1) {
String msg = "VM " + vmName + " is not running";
s_logger.warn(msg);
return msg;
}
} catch (Exception e) {
String msg = "VM.getByNameLabel " + vmName + " failed due to " + e.toString();
s_logger.warn(msg, e);
return msg;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Trying to connect to " + ipAddress);
}
if (pingdomr(ipAddress, Integer.toString(port)))
return null;
try {
Thread.sleep(_sleep);
} catch (final InterruptedException e) {
}
}
String msg = "Timeout, Unable to logon to " + ipAddress;
s_logger.debug(msg);
return msg;
}
protected String connect(final String vmname, final String ipAddress) {
return connect(vmname, ipAddress, 3922);
}
protected StartRouterAnswer execute(StartRouterCommand cmd) {
final String vmName = cmd.getVmName();
final DomainRouter router = cmd.getRouter();
try {
String tag = router.getVnet();
Network network = null;
if ("untagged".equalsIgnoreCase(tag)) {
Connection conn = getConnection();
network = Network.getByUuid(conn, _host.guestNetwork);
} else {
network = enableVlanNetwork(Long.parseLong(tag), _host.guestPif);
}
if (network == null) {
throw new InternalErrorException("Failed to enable VLAN network with tag: " + tag);
}
String bootArgs = cmd.getBootArgs();
String result = startSystemVM(vmName, router.getVlanId(), network, cmd.getVolumes(), bootArgs, router.getGuestMacAddress(), router.getPrivateIpAddress(), router
.getPrivateMacAddress(), router.getPublicMacAddress(), 3922, router.getRamSize(), router.getGuestOSId(), cmd.getNetworkRateMbps());
if (result == null) {
networkUsage(router.getPrivateIpAddress(), "create", null);
_domrIPMap.put(cmd.getVmName(), router.getPrivateIpAddress());
return new StartRouterAnswer(cmd);
}
return new StartRouterAnswer(cmd, result);
} catch (Exception e) {
String msg = "Exception caught while starting router vm " + vmName + " due to " + e.getMessage();
s_logger.warn(msg, e);
return new StartRouterAnswer(cmd, msg);
}
}
protected String startSystemVM(String vmName, String vlanId, Network nw0, List<VolumeVO> vols, String bootArgs, String guestMacAddr, String privateIp, String privateMacAddr,
String publicMacAddr, int cmdPort, long ramSize, long guestOsId, int networkRateMbps) {
VM vm = null;
List<Ternary<SR, VDI, VolumeVO>> mounts = null;
Connection conn = getConnection();
State state = State.Stopped;
String linkLocalBrName = null;
try {
synchronized (_vms) {
_vms.put(vmName, State.Starting);
}
mounts = mount(vols);
assert mounts.size() == 1 : "System VMs should have only 1 partition but we actually have " + mounts.size();
Ternary<SR, VDI, VolumeVO> mount = mounts.get(0);
if (!patchSystemVm(mount.second(), vmName)) { // FIXME make this
// nonspecific
String msg = "patch system vm failed";
s_logger.warn(msg);
return msg;
}
Set<VM> templates = VM.getByNameLabel(conn, "CentOS 5.3");
if (templates.size() == 0) {
templates = VM.getByNameLabel(conn, "CentOS 5.3 (64-bit)");
if (templates.size() == 0) {
String msg = " can not find template CentOS 5.3 ";
s_logger.warn(msg);
return msg;
}
}
VM template = templates.iterator().next();
vm = template.createClone(conn, vmName);
vm.removeFromOtherConfig(conn, "disks");
vm.setPVBootloader(conn, "pygrub");
long memsize = ramSize * 1024L * 1024L;
setMemory(conn, vm, memsize);
vm.setIsATemplate(conn, false);
vm.setVCPUsAtStartup(conn, 1L);
Host host = Host.getByUuid(conn, _host.uuid);
vm.setAffinity(conn, host);
/* create VBD */
VBD.Record vbdr = new VBD.Record();
vbdr.VM = vm;
vbdr.VDI = mount.second();
vbdr.bootable = true;
vbdr.userdevice = "0";
vbdr.mode = Types.VbdMode.RW;
vbdr.type = Types.VbdType.DISK;
VBD.create(conn, vbdr);
/* create VIF0 */
Network network = null;
if (VirtualMachineName.isValidConsoleProxyName(vmName) || VirtualMachineName.isValidSecStorageVmName(vmName, null)) {
network = Network.getByUuid(conn, _host.linkLocalNetwork);
} else {
network = nw0;
}
createVIF(conn, vm, guestMacAddr, networkRateMbps, "0", network);
/* create VIF1 */
/* For routing vm, set its network as link local bridge */
if (VirtualMachineName.isValidRouterName(vmName) && privateIp.startsWith("169.254")) {
network = Network.getByUuid(conn, _host.linkLocalNetwork);
} else {
network = Network.getByUuid(conn, _host.privateNetwork);
}
createVIF(conn, vm, privateMacAddr, networkRateMbps, "1", network);
/* create VIF2 */
if( !publicMacAddr.equalsIgnoreCase("FE:FF:FF:FF:FF:FF") ) {
network = null;
if ("untagged".equalsIgnoreCase(vlanId)) {
network = Network.getByUuid(conn, _host.publicNetwork);
} else {
network = enableVlanNetwork(Long.valueOf(vlanId), _host.publicPif);
if (network == null) {
throw new InternalErrorException("Failed to enable VLAN network with tag: " + vlanId);
}
}
createVIF(conn, vm, publicMacAddr, networkRateMbps, "2", network);
}
/* set up PV dom argument */
String pvargs = vm.getPVArgs(conn);
pvargs = pvargs + bootArgs;
if (s_logger.isInfoEnabled())
s_logger.info("PV args for system vm are " + pvargs);
vm.setPVArgs(conn, pvargs);
/* destroy console */
Set<Console> consoles = vm.getRecord(conn).consoles;
for (Console console : consoles) {
console.destroy(conn);
}
/* set action after crash as destroy */
vm.setActionsAfterCrash(conn, Types.OnCrashBehaviour.DESTROY);
startVM(conn, host, vm, vmName);
if (_canBridgeFirewall) {
String result = callHostPlugin("default_network_rules_systemvm", "vmName", vmName);
if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
s_logger.warn("Failed to program default system vm network rules for " + vmName);
} else {
s_logger.info("Programmed default system vm network rules for " + vmName);
}
}
if (s_logger.isInfoEnabled())
s_logger.info("Ping system vm command port, " + privateIp + ":" + cmdPort);
state = State.Running;
String result = connect(vmName, privateIp, cmdPort);
if (result != null) {
String msg = "Can not ping System vm " + vmName + "due to:" + result;
s_logger.warn(msg);
throw new CloudRuntimeException(msg);
} else {
if (s_logger.isInfoEnabled())
s_logger.info("Ping system vm command port succeeded for vm " + vmName);
}
return null;
} catch (XenAPIException e) {
String msg = "Exception caught while starting System vm " + vmName + " due to " + e.toString();
s_logger.warn(msg, e);
startvmfailhandle(vm, mounts);
state = State.Stopped;
return msg;
} catch (Exception e) {
String msg = "Exception caught while starting System vm " + vmName + " due to " + e.getMessage();
s_logger.warn(msg, e);
startvmfailhandle(vm, mounts);
state = State.Stopped;
return msg;
} finally {
synchronized (_vms) {
_vms.put(vmName, state);
}
}
}
// TODO : need to refactor it to reuse code with StartRouter
protected Answer execute(final StartConsoleProxyCommand cmd) {
final String vmName = cmd.getVmName();
final ConsoleProxyVO proxy = cmd.getProxy();
try {
Connection conn = getConnection();
Network network = Network.getByUuid(conn, _host.privateNetwork);
String bootArgs = cmd.getBootArgs();
bootArgs += " zone=" + _dcId;
bootArgs += " pod=" + _pod;
bootArgs += " guid=Proxy." + proxy.getId();
bootArgs += " proxy_vm=" + proxy.getId();
bootArgs += " localgw=" + _localGateway;
String result = startSystemVM(vmName, proxy.getVlanId(), network, cmd.getVolumes(), bootArgs, proxy.getGuestMacAddress(), proxy.getGuestIpAddress(), proxy
.getPrivateMacAddress(), proxy.getPublicMacAddress(), cmd.getProxyCmdPort(), proxy.getRamSize(), proxy.getGuestOSId(), cmd.getNetworkRateMbps());
if (result == null) {
return new StartConsoleProxyAnswer(cmd);
}
return new StartConsoleProxyAnswer(cmd, result);
} catch (Exception e) {
String msg = "Exception caught while starting router vm " + vmName + " due to " + e.getMessage();
s_logger.warn(msg, e);
return new StartConsoleProxyAnswer(cmd, msg);
}
}
protected boolean patchSystemVm(VDI vdi, String vmName) {
if (vmName.startsWith("r-")) {
return patchSpecialVM(vdi, vmName, "router");
} else if (vmName.startsWith("v-")) {
return patchSpecialVM(vdi, vmName, "consoleproxy");
} else if (vmName.startsWith("s-")) {
return patchSpecialVM(vdi, vmName, "secstorage");
} else {
throw new CloudRuntimeException("Tried to patch unknown type of system vm");
}
}
protected boolean isDeviceUsed(VM vm, Long deviceId) {
// Figure out the disk number to attach the VM to
String msg = null;
try {
Connection conn = getConnection();
Set<String> allowedVBDDevices = vm.getAllowedVBDDevices(conn);
if (allowedVBDDevices.contains(deviceId.toString())) {
return false;
}
return true;
} catch (XmlRpcException e) {
msg = "Catch XmlRpcException due to: " + e.getMessage();
s_logger.warn(msg, e);
} catch (XenAPIException e) {
msg = "Catch XenAPIException due to: " + e.toString();
s_logger.warn(msg, e);
}
throw new CloudRuntimeException("When check deviceId " + msg);
}
protected String getUnusedDeviceNum(VM vm) {
// Figure out the disk number to attach the VM to
try {
Connection conn = getConnection();
Set<String> allowedVBDDevices = vm.getAllowedVBDDevices(conn);
if (allowedVBDDevices.size() == 0)
throw new CloudRuntimeException("Could not find an available slot in VM with name: " + vm.getNameLabel(conn) + " to attach a new disk.");
return allowedVBDDevices.iterator().next();
} catch (XmlRpcException e) {
String msg = "Catch XmlRpcException due to: " + e.getMessage();
s_logger.warn(msg, e);
} catch (XenAPIException e) {
String msg = "Catch XenAPIException due to: " + e.toString();
s_logger.warn(msg, e);
}
throw new CloudRuntimeException("Could not find an available slot in VM with name to attach a new disk.");
}
protected boolean patchSpecialVM(VDI vdi, String vmname, String vmtype) {
// patch special vm here, domr, domp
VBD vbd = null;
Connection conn = getConnection();
try {
Host host = Host.getByUuid(conn, _host.uuid);
Set<VM> vms = host.getResidentVMs(conn);
for (VM vm : vms) {
VM.Record vmrec = null;
try {
vmrec = vm.getRecord(conn);
} catch (Exception e) {
String msg = "VM.getRecord failed due to " + e.toString() + " " + e.getMessage();
s_logger.warn(msg);
continue;
}
if (vmrec.isControlDomain) {
/* create VBD */
VBD.Record vbdr = new VBD.Record();
vbdr.VM = vm;
vbdr.VDI = vdi;
vbdr.bootable = false;
vbdr.userdevice = getUnusedDeviceNum(vm);
vbdr.unpluggable = true;
vbdr.mode = Types.VbdMode.RW;
vbdr.type = Types.VbdType.DISK;
vbd = VBD.create(conn, vbdr);
vbd.plug(conn);
String device = vbd.getDevice(conn);
return patchspecialvm(vmname, device, vmtype);
}
}
} catch (XenAPIException e) {
String msg = "patchSpecialVM faile on " + _host.uuid + " due to " + e.toString();
s_logger.warn(msg, e);
} catch (Exception e) {
String msg = "patchSpecialVM faile on " + _host.uuid + " due to " + e.getMessage();
s_logger.warn(msg, e);
} finally {
if (vbd != null) {
try {
if (vbd.getCurrentlyAttached(conn)) {
vbd.unplug(conn);
}
vbd.destroy(conn);
} catch (XmlRpcException e) {
String msg = "Catch XmlRpcException due to " + e.getMessage();
s_logger.warn(msg, e);
} catch (XenAPIException e) {
String msg = "Catch XenAPIException due to " + e.toString();
s_logger.warn(msg, e);
}
}
}
return false;
}
protected boolean patchspecialvm(String vmname, String device, String vmtype) {
String result = callHostPlugin("patchdomr", "vmname", vmname, "vmtype", vmtype, "device", "/dev/" + device);
if (result == null || result.isEmpty())
return false;
return true;
}
protected String callHostPluginBase(String plugin, String cmd, int timeout, String... params) {
Map<String, String> args = new HashMap<String, String>();
try {
Connection conn = getConnection();
for (int i = 0; i < params.length; i += 2) {
args.put(params[i], params[i + 1]);
}
if (s_logger.isTraceEnabled()) {
s_logger.trace("callHostPlugin executing for command " + cmd + " with " + getArgsString(args));
}
Host host = Host.getByUuid(conn, _host.uuid);
String result = host.callPlugin(conn, plugin, cmd, args);
if (s_logger.isTraceEnabled()) {
s_logger.trace("callHostPlugin Result: " + result);
}
return result.replace("\n", "");
} catch ( Types.HandleInvalid e) {
s_logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to HandleInvalid clazz:" + e.clazz + ", handle:" + e.handle);
} catch (XenAPIException e) {
s_logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e.toString(), e);
} catch (XmlRpcException e) {
s_logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e.getMessage(), e);
}
return null;
}
protected String callHostPlugin(String cmd, String... params) {
return callHostPluginBase("vmops", cmd, 300, params);
}
protected String callHostPluginWithTimeOut(String cmd, int timeout, String... params) {
return callHostPluginBase("vmops", cmd, timeout, params);
}
protected String getArgsString(Map<String, String> args) {
StringBuilder argString = new StringBuilder();
for (Map.Entry<String, String> arg : args.entrySet()) {
argString.append(arg.getKey() + ": " + arg.getValue() + ", ");
}
return argString.toString();
}
protected boolean setIptables() {
String result = callHostPlugin("setIptables");
if (result == null || result.isEmpty())
return false;
return true;
}
protected Nic getManageMentNetwork(Connection conn, String name) throws XmlRpcException, XenAPIException {
Set<Network> networks = Network.getByNameLabel(conn, name);
for (Network network : networks) {
Network.Record nr = network.getRecord(conn);
for (PIF pif : nr.PIFs) {
PIF.Record pr = pif.getRecord(conn);
if (_host.uuid.equals(pr.host.getUuid(conn))) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found a network called " + name + " on host=" + _host.ip + "; Network=" + nr.uuid + "; pif=" + pr.uuid);
}
if (!pr.management && pr.bondMasterOf != null && pr.bondMasterOf.size() > 0) {
if (pr.bondMasterOf.size() > 1) {
String msg = new StringBuilder("Unsupported configuration. Network " + name + " has more than one bond. Network=").append(nr.uuid)
.append("; pif=").append(pr.uuid).toString();
s_logger.warn(msg);
return null;
}
Bond bond = pr.bondMasterOf.iterator().next();
Set<PIF> slaves = bond.getSlaves(conn);
for (PIF slave : slaves) {
PIF.Record spr = slave.getRecord(conn);
if (spr.management) {
Host host = Host.getByUuid(conn, _host.uuid);
if (!transferManagementNetwork(conn, host, slave, spr, pif)) {
String msg = new StringBuilder("Unable to transfer management network. slave=" + spr.uuid + "; master=" + pr.uuid + "; host="
+ _host.uuid).toString();
s_logger.warn(msg);
return null;
}
break;
}
}
}
return new Nic(network, nr, pif, pr);
}
}
}
return null;
}
protected Nic getLocalNetwork(Connection conn, String name) throws XmlRpcException, XenAPIException {
Set<Network> networks = Network.getByNameLabel(conn, name);
for (Network network : networks) {
Network.Record nr = network.getRecord(conn);
for (PIF pif : nr.PIFs) {
PIF.Record pr = pif.getRecord(conn);
if (_host.uuid.equals(pr.host.getUuid(conn))) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found a network called " + name + " on host=" + _host.ip + "; Network=" + nr.uuid + "; pif=" + pr.uuid);
}
return new Nic(network, nr, pif, pr);
}
}
}
return null;
}
protected VIF getCorrectVif(VM router, String vlanId) {
try {
Connection conn = getConnection();
Set<VIF> routerVIFs = router.getVIFs(conn);
for (VIF vif : routerVIFs) {
Network vifNetwork = vif.getNetwork(conn);
if (vlanId.equals("untagged")) {
if (vifNetwork.getUuid(conn).equals(_host.publicNetwork)) {
return vif;
}
} else {
if (vifNetwork.getNameLabel(conn).equals("VLAN" + vlanId)) {
return vif;
}
}
}
} catch (XmlRpcException e) {
String msg = "Caught XmlRpcException: " + e.getMessage();
s_logger.warn(msg, e);
} catch (XenAPIException e) {
String msg = "Caught XenAPIException: " + e.toString();
s_logger.warn(msg, e);
}
return null;
}
protected String getLowestAvailableVIFDeviceNum(VM vm) {
try {
Connection conn = getConnection();
Set<String> availableDeviceNums = vm.getAllowedVIFDevices(conn);
Iterator<String> deviceNumsIterator = availableDeviceNums.iterator();
List<Integer> sortedDeviceNums = new ArrayList<Integer>();
while (deviceNumsIterator.hasNext()) {
try {
sortedDeviceNums.add(Integer.valueOf(deviceNumsIterator.next()));
} catch (NumberFormatException e) {
s_logger.debug("Obtained an invalid value for an available VIF device number for VM: " + vm.getNameLabel(conn));
return null;
}
}
Collections.sort(sortedDeviceNums);
return String.valueOf(sortedDeviceNums.get(0));
} catch (XmlRpcException e) {
String msg = "Caught XmlRpcException: " + e.getMessage();
s_logger.warn(msg, e);
} catch (XenAPIException e) {
String msg = "Caught XenAPIException: " + e.toString();
s_logger.warn(msg, e);
}
return null;
}
protected VDI mount(StoragePoolType pooltype, String volumeFolder, String volumePath) {
return getVDIbyUuid(volumePath);
}
protected List<Ternary<SR, VDI, VolumeVO>> mount(List<VolumeVO> vos) {
ArrayList<Ternary<SR, VDI, VolumeVO>> mounts = new ArrayList<Ternary<SR, VDI, VolumeVO>>(vos.size());
for (VolumeVO vol : vos) {
String vdiuuid = vol.getPath();
SR sr = null;
VDI vdi = null;
// Look up the VDI
vdi = getVDIbyUuid(vdiuuid);
Ternary<SR, VDI, VolumeVO> ter = new Ternary<SR, VDI, VolumeVO>(sr, vdi, vol);
if( vol.getVolumeType() == VolumeType.ROOT ) {
mounts.add(0, ter);
} else {
mounts.add(ter);
}
}
return mounts;
}
protected Network getNetworkByName(String name) throws BadServerResponse, XenAPIException, XmlRpcException {
Connection conn = getConnection();
Set<Network> networks = Network.getByNameLabel(conn, name);
if (networks.size() > 0) {
assert networks.size() == 1 : "How did we find more than one network with this name label" + name + "? Strange....";
return networks.iterator().next(); // Found it.
}
return null;
}
protected Network enableVlanNetwork(long tag, String pifUuid) throws XenAPIException, XmlRpcException {
// In XenServer, vlan is added by
// 1. creating a network.
// 2. creating a vlan associating network with the pif.
// We always create
// 1. a network with VLAN[vlan id in decimal]
// 2. a vlan associating the network created with the pif to private
// network.
Connection conn = getConnection();
Network vlanNetwork = null;
String name = "VLAN" + Long.toString(tag);
synchronized (name.intern()) {
vlanNetwork = getNetworkByName(name);
if (vlanNetwork == null) { // Can't find it, then create it.
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating VLAN Network for " + tag + " on host " + _host.ip);
}
Network.Record nwr = new Network.Record();
nwr.nameLabel = name;
nwr.bridge = name;
vlanNetwork = Network.create(conn, nwr);
}
PIF nPif = PIF.getByUuid(conn, pifUuid);
PIF.Record nPifr = nPif.getRecord(conn);
Network.Record vlanNetworkr = vlanNetwork.getRecord(conn);
if (vlanNetworkr.PIFs != null) {
for (PIF pif : vlanNetworkr.PIFs) {
PIF.Record pifr = pif.getRecord(conn);
if(pifr.host.equals(nPifr.host)) {
if (pifr.device.equals(nPifr.device) ) {
return vlanNetwork;
} else {
throw new CloudRuntimeException("Creating VLAN " + tag + " on " + nPifr.device + " failed due to this VLAN is already created on " + pifr.device);
}
}
}
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating VLAN " + tag + " on host " + _host.ip);
}
VLAN vlan = VLAN.create(conn, nPif, tag, vlanNetwork);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Created VLAN " + tag + " on host " + _host.ip);
}
}
return vlanNetwork;
}
protected void disableVlanNetwork(Network network){
}
protected SR getLocalLVMSR() {
Connection conn = getConnection();
try {
Map<SR, SR.Record> map = SR.getAllRecords(conn);
for (Map.Entry<SR, SR.Record> entry : map.entrySet()) {
SR.Record srRec = entry.getValue();
if (SRType.LVM.equals(srRec.type)) {
Set<PBD> pbds = srRec.PBDs;
if (pbds == null) {
continue;
}
for (PBD pbd : pbds) {
Host host = pbd.getHost(conn);
if (!isRefNull(host) && host.getUuid(conn).equals(_host.uuid)) {
if (!pbd.getCurrentlyAttached(conn)) {
pbd.plug(conn);
}
SR sr = entry.getKey();
sr.scan(conn);
return sr;
}
}
}
}
} catch (XenAPIException e) {
String msg = "Unable to get local LVMSR in host:" + _host.uuid + e.toString();
s_logger.warn(msg);
} catch (XmlRpcException e) {
String msg = "Unable to get local LVMSR in host:" + _host.uuid + e.getCause();
s_logger.warn(msg);
}
return null;
}
protected StartupStorageCommand initializeLocalSR() {
SR lvmsr = getLocalLVMSR();
if (lvmsr == null) {
return null;
}
try {
Connection conn = getConnection();
String lvmuuid = lvmsr.getUuid(conn);
long cap = lvmsr.getPhysicalSize(conn);
if (cap < 0)
return null;
long avail = cap - lvmsr.getPhysicalUtilisation(conn);
lvmsr.setNameLabel(conn, lvmuuid);
String name = "VMOps local storage pool in host : " + _host.uuid;
lvmsr.setNameDescription(conn, name);
Host host = Host.getByUuid(conn, _host.uuid);
String address = host.getAddress(conn);
StoragePoolInfo pInfo = new StoragePoolInfo(name, lvmuuid, address, SRType.LVM.toString(), SRType.LVM.toString(), StoragePoolType.LVM, cap, avail);
StartupStorageCommand cmd = new StartupStorageCommand();
cmd.setPoolInfo(pInfo);
cmd.setGuid(_host.uuid);
cmd.setResourceType(StorageResourceType.STORAGE_POOL);
return cmd;
} catch (XenAPIException e) {
String msg = "build startupstoragecommand err in host:" + _host.uuid + e.toString();
s_logger.warn(msg);
} catch (XmlRpcException e) {
String msg = "build startupstoragecommand err in host:" + _host.uuid + e.getMessage();
s_logger.warn(msg);
}
return null;
}
@Override
public PingCommand getCurrentStatus(long id) {
try {
if (!pingxenserver()) {
Thread.sleep(1000);
if (!pingxenserver()) {
s_logger.warn(" can not ping xenserver " + _host.uuid);
return null;
}
}
HashMap<String, State> newStates = sync();
if (newStates == null) {
newStates = new HashMap<String, State>();
}
if (!_canBridgeFirewall) {
return new PingRoutingCommand(getType(), id, newStates);
} else {
HashMap<String, Pair<Long, Long>> nwGrpStates = syncNetworkGroups(id);
return new PingRoutingWithNwGroupsCommand(getType(), id, newStates, nwGrpStates);
}
} catch (Exception e) {
s_logger.warn("Unable to get current status", e);
return null;
}
}
private HashMap<String, Pair<Long,Long>> syncNetworkGroups(long id) {
HashMap<String, Pair<Long,Long>> states = new HashMap<String, Pair<Long,Long>>();
String result = callHostPlugin("get_rule_logs_for_vms", "host_uuid", _host.uuid);
s_logger.trace("syncNetworkGroups: id=" + id + " got: " + result);
String [] rulelogs = result != null ?result.split(";"): new String [0];
for (String rulesforvm: rulelogs){
String [] log = rulesforvm.split(",");
if (log.length != 6) {
continue;
}
//output = ','.join([vmName, vmID, vmIP, domID, signature, seqno])
try {
states.put(log[0], new Pair<Long,Long>(Long.parseLong(log[1]), Long.parseLong(log[5])));
} catch (NumberFormatException nfe) {
states.put(log[0], new Pair<Long,Long>(-1L, -1L));
}
}
return states;
}
@Override
public Type getType() {
return com.cloud.host.Host.Type.Routing;
}
protected void getPVISO(StartupStorageCommand sscmd) {
Connection conn = getConnection();
try {
Set<VDI> vids = VDI.getByNameLabel(conn, "xs-tools.iso");
if (vids.isEmpty())
return;
VDI pvISO = vids.iterator().next();
String uuid = pvISO.getUuid(conn);
Map<String, TemplateInfo> pvISOtmlt = new HashMap<String, TemplateInfo>();
TemplateInfo tmplt = new TemplateInfo("xs-tools.iso", uuid, pvISO.getVirtualSize(conn), true);
pvISOtmlt.put("xs-tools", tmplt);
sscmd.setTemplateInfo(pvISOtmlt);
} catch (XenAPIException e) {
s_logger.debug("Can't get xs-tools.iso: " + e.toString());
} catch (XmlRpcException e) {
s_logger.debug("Can't get xs-tools.iso: " + e.toString());
}
}
protected boolean can_bridge_firewall() {
return Boolean.valueOf(callHostPlugin("can_bridge_firewall", "host_uuid", _host.uuid));
}
protected boolean getHostInfo() throws IllegalArgumentException{
Connection conn = getConnection();
try {
Host myself = Host.getByUuid(conn, _host.uuid);
_localGateway = callHostPlugin("getgateway", "mgmtIP", myself.getAddress(conn));
if (_localGateway == null || _localGateway.isEmpty()) {
s_logger.warn("can not get gateway for host :" + _host.uuid);
return false;
}
_canBridgeFirewall = can_bridge_firewall();
Nic privateNic = null;
privateNic = getManageMentNetwork(conn, "cloud-private");
if( privateNic == null ) {
privateNic = getManageMentNetwork(conn, _privateNetworkName);
} else {
_privateNetworkName = "cloud-private";
}
String name = _privateNetworkName;
if (privateNic == null) {
s_logger.debug("Unable to find any private network. Trying to determine that by route for host " + _host.ip);
name = callHostPlugin("getnetwork", "mgmtIP", myself.getAddress(conn));
if (name == null || name.isEmpty()) {
s_logger.warn("Unable to determine the private network for host " + _host.ip);
return false;
}
_privateNetworkName = name;
privateNic = getManageMentNetwork(conn, name);
if (privateNic == null) {
s_logger.warn("Unable to get private network " + name);
return false;
}
name = privateNic.nr.nameLabel;
}
Nic guestNic = null;
if (_guestNetworkName != null && !_guestNetworkName.equals(name)) {
guestNic = getLocalNetwork(conn, _guestNetworkName);
if (guestNic == null) {
s_logger.warn("Unable to find guest network " + _guestNetworkName);
throw new IllegalArgumentException("Unable to find guest network " + _guestNetworkName + " for host " + _host.ip);
}
} else {
guestNic = privateNic;
_guestNetworkName = _privateNetworkName;
}
name = guestNic.nr.nameLabel;
Nic publicNic = null;
if (_publicNetworkName != null && !_publicNetworkName.equals(name)) {
publicNic = getLocalNetwork(conn, _publicNetworkName);
if (publicNic == null) {
s_logger.warn("Unable to find public network " + _publicNetworkName + " for host " + _host.ip);
throw new IllegalArgumentException("Unable to find public network " + _publicNetworkName + " for host " + _host.ip);
}
} else {
publicNic = guestNic;
_publicNetworkName = _guestNetworkName;
}
name = publicNic.nr.nameLabel;
_host.privatePif = privateNic.pr.uuid;
_host.privateNetwork = privateNic.nr.uuid;
_host.publicPif = publicNic.pr.uuid;
_host.publicNetwork = publicNic.nr.uuid;
_host.guestNetwork = guestNic.nr.uuid;
_host.guestPif = guestNic.pr.uuid;
Nic storageNic1 = getLocalNetwork(conn, _storageNetworkName1);
if (storageNic1 == null) {
storageNic1 = privateNic;
}
_host.storageNetwork1 = storageNic1.nr.uuid;
_host.storagePif1 = storageNic1.pr.uuid;
Nic storageNic2 = getLocalNetwork(conn, _storageNetworkName2);
if (storageNic2 == null) {
storageNic2 = storageNic1;
}
_host.storageNetwork2 = storageNic2.nr.uuid;
_host.storagePif2 = storageNic2.pr.uuid;
s_logger.info("Private Network is " + _privateNetworkName + " for host " + _host.ip);
s_logger.info("Guest Network is " + _guestNetworkName + " for host " + _host.ip);
s_logger.info("Public Network is " + _publicNetworkName + " for host " + _host.ip);
s_logger.info("Storage Network 1 is " + _storageNetworkName1 + " for host " + _host.ip);
s_logger.info("Storage Network 2 is " + _storageNetworkName2 + " for host " + _host.ip);
return true;
} catch (XenAPIException e) {
s_logger.warn("Unable to get host information for " + _host.ip, e);
return false;
} catch (XmlRpcException e) {
s_logger.warn("Unable to get host information for " + _host.ip, e);
return false;
}
}
private void setupLinkLocalNetwork() {
try {
Network.Record rec = new Network.Record();
Connection conn = getConnection();
Set<Network> networks = Network.getByNameLabel(conn, _linkLocalPrivateNetworkName);
Network linkLocal = null;
if (networks.size() == 0) {
rec.nameDescription = "link local network used by system vms";
rec.nameLabel = _linkLocalPrivateNetworkName;
Map<String, String> configs = new HashMap<String, String>();
configs.put("ip_begin", NetUtils.getLinkLocalGateway());
configs.put("ip_end", NetUtils.getLinkLocalIpEnd());
configs.put("netmask", NetUtils.getLinkLocalNetMask());
rec.otherConfig = configs;
linkLocal = Network.create(conn, rec);
} else {
linkLocal = networks.iterator().next();
}
/* Make sure there is a physical bridge on this network */
VIF dom0vif = null;
Pair<VM, VM.Record> vm = getControlDomain(conn);
VM dom0 = vm.first();
Set<VIF> vifs = dom0.getVIFs(conn);
if (vifs.size() != 0) {
for (VIF vif : vifs) {
Map<String, String> otherConfig = vif.getOtherConfig(conn);
if (otherConfig != null) {
String nameLabel = otherConfig.get("nameLabel");
if ((nameLabel != null) && nameLabel.equalsIgnoreCase("link_local_network_vif")) {
dom0vif = vif;
}
}
}
}
/* create temp VIF0 */
if (dom0vif == null) {
s_logger.debug("Can't find a vif on dom0 for link local, creating a new one");
VIF.Record vifr = new VIF.Record();
vifr.VM = dom0;
vifr.device = getLowestAvailableVIFDeviceNum(dom0);
if (vifr.device == null) {
s_logger.debug("Failed to create link local network, no vif available");
return;
}
Map<String, String> config = new HashMap<String, String>();
config.put("nameLabel", "link_local_network_vif");
vifr.otherConfig = config;
vifr.MAC = "FE:FF:FF:FF:FF:FF";
vifr.network = linkLocal;
dom0vif = VIF.create(conn, vifr);
//dom0vif.plug(conn);
} else {
s_logger.debug("already have a vif on dom0 for link local network");
/*if (!dom0vif.getCurrentlyAttached(conn)) {
dom0vif.plug(conn);
}*/
}
String brName = linkLocal.getBridge(conn);
callHostPlugin("setLinkLocalIP", "brName", brName);
_host.linkLocalNetwork = linkLocal.getUuid(conn);
} catch (XenAPIException e) {
s_logger.warn("Unable to create local link network", e);
} catch (XmlRpcException e) {
// TODO Auto-generated catch block
s_logger.warn("Unable to create local link network", e);
}
}
protected boolean transferManagementNetwork(Connection conn, Host host, PIF src, PIF.Record spr, PIF dest) throws XmlRpcException, XenAPIException {
dest.reconfigureIp(conn, spr.ipConfigurationMode, spr.IP, spr.netmask, spr.gateway, spr.DNS);
Host.managementReconfigure(conn, dest);
String hostUuid = null;
int count = 0;
while (count < 10) {
try {
Thread.sleep(10000);
hostUuid = host.getUuid(conn);
if (hostUuid != null) {
break;
}
} catch (XmlRpcException e) {
s_logger.debug("Waiting for host to come back: " + e.getMessage());
} catch (XenAPIException e) {
s_logger.debug("Waiting for host to come back: " + e.getMessage());
} catch (InterruptedException e) {
s_logger.debug("Gotta run");
return false;
}
}
if (hostUuid == null) {
s_logger.warn("Unable to transfer the management network from " + spr.uuid);
return false;
}
src.reconfigureIp(conn, IpConfigurationMode.NONE, null, null, null, null);
return true;
}
private String getRealPoolUuid() {
Connection conn = null;
conn = _connPool.masterConnect(_host.ip, _username, _password);
if (conn == null) {
String msg = "Unable to get a connection to " + _host.ip;
s_logger.debug(msg);
throw new RuntimeException(msg);
}
Set<Pool> pools;
try {
pools = Pool.getAll(conn);
Pool pool = pools.iterator().next();
Pool.Record pr = pool.getRecord(conn);
return pr.uuid;
} catch (BadServerResponse e) {
throw new RuntimeException(e.toString());
} catch (XenAPIException e) {
throw new RuntimeException(e.toString());
} catch (XmlRpcException e) {
throw new RuntimeException(e.toString());
} finally {
if( conn != null) {
try{
Session.logout(conn);
} catch (Exception e) {
}
conn.dispose();
}
}
}
@Override
public StartupCommand[] initialize() throws IllegalArgumentException {
_host.pool = getRealPoolUuid();
setupServer();
if (!getHostInfo()) {
s_logger.warn("Unable to get host information for " + _host.ip);
return null;
}
setupLinkLocalNetwork();
StartupRoutingCommand cmd = new StartupRoutingCommand();
fillHostInfo(cmd);
cleanupDiskMounts();
Map<String, State> changes = null;
synchronized (_vms) {
_vms.clear();
changes = sync();
}
_domrIPMap.clear();
if (changes != null) {
for (final Map.Entry<String, State> entry : changes.entrySet()) {
final String vm = entry.getKey();
State state = entry.getValue();
if (VirtualMachineName.isValidRouterName(vm) && (state == State.Running)) {
syncDomRIPMap(vm);
}
}
}
cmd.setHypervisorType(Hypervisor.Type.XenServer);
cmd.setChanges(changes);
cmd.setCluster(_cluster);
StartupStorageCommand sscmd = initializeLocalSR();
if (sscmd != null) {
/* report pv driver iso */
getPVISO(sscmd);
return new StartupCommand[] { cmd, sscmd };
}
return new StartupCommand[] { cmd };
}
protected String getPoolUuid() {
Connection conn = getConnection();
try {
Map<Pool, Pool.Record> pools = Pool.getAllRecords(conn);
assert (pools.size() == 1) : "Tell me how pool size can be " + pools.size();
Pool.Record rec = pools.values().iterator().next();
return rec.uuid;
} catch (XenAPIException e) {
throw new CloudRuntimeException("Unable to get pool ", e);
} catch (XmlRpcException e) {
throw new CloudRuntimeException("Unable to get pool ", e);
}
}
protected void setupServer() {
Connection conn = getConnection();
String version = CitrixResourceBase.class.getPackage().getImplementationVersion();
try {
Host host = Host.getByUuid(conn, _host.uuid);
/* enable host in case it is disabled somehow */
host.enable(conn);
/* push patches to XenServer */
Host.Record hr = host.getRecord(conn);
Iterator<String> it = hr.tags.iterator();
while (it.hasNext()) {
String tag = it.next();
if (tag.startsWith("vmops-version-")) {
if (tag.contains(version)) {
s_logger.info(logX(host, "Host " + hr.address + " is already setup."));
return;
} else {
it.remove();
}
}
}
com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(hr.address, 22);
try {
sshConnection.connect(null, 60000, 60000);
if (!sshConnection.authenticateWithPassword(_username, _password)) {
throw new CloudRuntimeException("Unable to authenticate");
}
SCPClient scp = new SCPClient(sshConnection);
List<File> files = getPatchFiles();
if( files == null || files.isEmpty() ) {
throw new CloudRuntimeException("Can not find patch file");
}
for( File file :files) {
String path = file.getParentFile().getAbsolutePath() + "/";
Properties props = new Properties();
props.load(new FileInputStream(file));
for (Map.Entry<Object, Object> entry : props.entrySet()) {
String k = (String) entry.getKey();
String v = (String) entry.getValue();
assert (k != null && k.length() > 0 && v != null && v.length() > 0) : "Problems with " + k + "=" + v;
String[] tokens = v.split(",");
String f = null;
if (tokens.length == 3 && tokens[0].length() > 0) {
if (tokens[0].startsWith("/")) {
f = tokens[0];
} else if (tokens[0].startsWith("~")) {
String homedir = System.getenv("HOME");
f = homedir + tokens[0].substring(1) + k;
} else {
f = path + tokens[0] + '/' + k;
}
} else {
f = path + k;
}
String d = tokens[tokens.length - 1];
f = f.replace('/', File.separatorChar);
String p = "0755";
if (tokens.length == 3) {
p = tokens[1];
} else if (tokens.length == 2) {
p = tokens[0];
}
if (!new File(f).exists()) {
s_logger.warn("We cannot locate " + f);
continue;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Copying " + f + " to " + d + " on " + hr.address + " with permission " + p);
}
scp.put(f, d, p);
}
}
} catch (IOException e) {
throw new CloudRuntimeException("Unable to setup the server correctly", e);
} finally {
sshConnection.close();
}
if (!setIptables()) {
s_logger.warn("set xenserver Iptable failed");
}
hr.tags.add("vmops-version-" + version);
host.setTags(conn, hr.tags);
} catch (XenAPIException e) {
String msg = "Xen setup failed due to " + e.toString();
s_logger.warn(msg, e);
throw new CloudRuntimeException("Unable to get host information " + e.toString(), e);
} catch (XmlRpcException e) {
String msg = "Xen setup failed due to " + e.getMessage();
s_logger.warn(msg, e);
throw new CloudRuntimeException("Unable to get host information ", e);
}
}
protected List<File> getPatchFiles() {
List<File> files = new ArrayList<File>();
File file = new File(_patchPath);
files.add(file);
return files;
}
protected SR getSRByNameLabelandHost(String name) throws BadServerResponse, XenAPIException, XmlRpcException {
Connection conn = getConnection();
Set<SR> srs = SR.getByNameLabel(conn, name);
SR ressr = null;
for (SR sr : srs) {
Set<PBD> pbds;
pbds = sr.getPBDs(conn);
for (PBD pbd : pbds) {
PBD.Record pbdr = pbd.getRecord(conn);
if (pbdr.host != null && pbdr.host.getUuid(conn).equals(_host.uuid)) {
if (!pbdr.currentlyAttached) {
pbd.plug(conn);
}
ressr = sr;
break;
}
}
}
return ressr;
}
protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) {
try {
Connection conn = getConnection();
Set<SR> srs = SR.getByNameLabel(conn, cmd.getStorageId());
if (srs.size() != 1) {
String msg = "There are " + srs.size() + " storageid: " + cmd.getStorageId();
s_logger.warn(msg);
return new GetStorageStatsAnswer(cmd, msg);
}
SR sr = srs.iterator().next();
sr.scan(conn);
long capacity = sr.getPhysicalSize(conn);
long used = sr.getPhysicalUtilisation(conn);
return new GetStorageStatsAnswer(cmd, capacity, used);
} catch (XenAPIException e) {
String msg = "GetStorageStats Exception:" + e.toString() + "host:" + _host.uuid + "storageid: " + cmd.getStorageId();
s_logger.warn(msg);
return new GetStorageStatsAnswer(cmd, msg);
} catch (XmlRpcException e) {
String msg = "GetStorageStats Exception:" + e.getMessage() + "host:" + _host.uuid + "storageid: " + cmd.getStorageId();
s_logger.warn(msg);
return new GetStorageStatsAnswer(cmd, msg);
}
}
private void pbdPlug(Connection conn, PBD pbd) {
String pbdUuid = "";
String hostAddr = "";
try {
pbdUuid = pbd.getUuid(conn);
hostAddr = pbd.getHost(conn).getAddress(conn);
pbd.plug(conn);
} catch (Exception e) {
String msg = "PBD " + pbdUuid + " is not attached! and PBD plug failed due to "
+ e.toString() + ". Please check this PBD in host : " + hostAddr;
s_logger.warn(msg, e);
}
}
protected boolean checkSR(SR sr) {
try {
Connection conn = getConnection();
SR.Record srRec = sr.getRecord(conn);
Set<PBD> pbds = srRec.PBDs;
if (pbds.size() == 0) {
String msg = "There is no PBDs for this SR: " + srRec.nameLabel + " on host:" + _host.uuid;
s_logger.warn(msg);
return false;
}
if (srRec.shared) {
Set<Host> hosts = Host.getAll(conn);
for (Host host : hosts) {
boolean found = false;
for (PBD pbd : pbds) {
if (host.equals(pbd.getHost(conn))) {
PBD.Record pbdr = pbd.getRecord(conn);
if (!pbdr.currentlyAttached) {
pbdPlug(conn, pbd);
}
pbds.remove(pbd);
found = true;
break;
}
}
if (!found) {
PBD.Record pbdr = srRec.PBDs.iterator().next().getRecord(conn);
pbdr.host = host;
pbdr.uuid = "";
PBD pbd = PBD.create(conn, pbdr);
pbdPlug(conn, pbd);
}
}
} else {
for (PBD pbd : pbds) {
PBD.Record pbdr = pbd.getRecord(conn);
if (!pbdr.currentlyAttached) {
pbdPlug(conn, pbd);
}
}
}
} catch (Exception e) {
String msg = "checkSR failed host:" + _host.uuid + " due to " + e.toString();
s_logger.warn(msg);
return false;
}
return true;
}
protected Answer execute(ModifyStoragePoolCommand cmd) {
StoragePoolVO pool = cmd.getPool();
StoragePoolTO poolTO = new StoragePoolTO(pool);
try {
Connection conn = getConnection();
SR sr = getStorageRepository(conn, poolTO);
long capacity = sr.getPhysicalSize(conn);
long available = capacity - sr.getPhysicalUtilisation(conn);
if (capacity == -1) {
String msg = "Pool capacity is -1! pool: " + pool.getName() + pool.getHostAddress() + pool.getPath();
s_logger.warn(msg);
return new Answer(cmd, false, msg);
}
Map<String, TemplateInfo> tInfo = new HashMap<String, TemplateInfo>();
ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd, capacity, available, tInfo);
return answer;
} catch (XenAPIException e) {
String msg = "ModifyStoragePoolCommand XenAPIException:" + e.toString() + " host:" + _host.uuid + " pool: " + pool.getName() + pool.getHostAddress() + pool.getPath();
s_logger.warn(msg, e);
return new Answer(cmd, false, msg);
} catch (Exception e) {
String msg = "ModifyStoragePoolCommand XenAPIException:" + e.getMessage() + " host:" + _host.uuid + " pool: " + pool.getName() + pool.getHostAddress() + pool.getPath();
s_logger.warn(msg, e);
return new Answer(cmd, false, msg);
}
}
protected Answer execute(DeleteStoragePoolCommand cmd) {
StoragePoolVO pool = cmd.getPool();
StoragePoolTO poolTO = new StoragePoolTO(pool);
try {
Connection conn = getConnection();
SR sr = getStorageRepository(conn, poolTO);
removeSR(sr);
Answer answer = new Answer(cmd, true, "success");
return answer;
} catch (Exception e) {
String msg = "DeleteStoragePoolCommand XenAPIException:" + e.getMessage() + " host:" + _host.uuid + " pool: " + pool.getName() + pool.getHostAddress() + pool.getPath();
s_logger.warn(msg, e);
return new Answer(cmd, false, msg);
}
}
public Connection getConnection() {
return _connPool.connect(_host.uuid, _host.pool, _host.ip, _username, _password, _wait);
}
protected void fillHostInfo(StartupRoutingCommand cmd) {
long speed = 0;
int cpus = 0;
long ram = 0;
Connection conn = getConnection();
long dom0Ram = 0;
final StringBuilder caps = new StringBuilder();
try {
Host host = Host.getByUuid(conn, _host.uuid);
Host.Record hr = host.getRecord(conn);
Map<String, String> details = cmd.getHostDetails();
if (details == null) {
details = new HashMap<String, String>();
}
if (_privateNetworkName != null) {
details.put("private.network.device", _privateNetworkName);
}
if (_publicNetworkName != null) {
details.put("public.network.device", _publicNetworkName);
}
if (_guestNetworkName != null) {
details.put("guest.network.device", _guestNetworkName);
}
details.put("can_bridge_firewall", Boolean.toString(_canBridgeFirewall));
cmd.setHostDetails(details);
cmd.setName(hr.nameLabel);
cmd.setGuid(_host.uuid);
cmd.setDataCenter(Long.toString(_dcId));
for (final String cap : hr.capabilities) {
if (cap.length() > 0) {
caps.append(cap).append(" , ");
}
}
if (caps.length() > 0) {
caps.delete(caps.length() - 3, caps.length());
}
cmd.setCaps(caps.toString());
Set<HostCpu> hcs = host.getHostCPUs(conn);
cpus = hcs.size();
for (final HostCpu hc : hcs) {
speed = hc.getSpeed(conn);
}
cmd.setSpeed(speed);
cmd.setCpus(cpus);
long free = 0;
HostMetrics hm = host.getMetrics(conn);
ram = hm.getMemoryTotal(conn);
free = hm.getMemoryFree(conn);
Set<VM> vms = host.getResidentVMs(conn);
for (VM vm : vms) {
if (vm.getIsControlDomain(conn)) {
dom0Ram = vm.getMemoryDynamicMax(conn);
break;
}
}
// assume the memory Virtualization overhead is 1/64
ram = (ram - dom0Ram) * 63/64;
cmd.setMemory(ram);
cmd.setDom0MinMemory(dom0Ram);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Total Ram: " + ram + " Free Ram: " + free + " dom0 Ram: " + dom0Ram);
}
PIF pif = PIF.getByUuid(conn, _host.privatePif);
PIF.Record pifr = pif.getRecord(conn);
if (pifr.IP != null && pifr.IP.length() > 0) {
cmd.setPrivateIpAddress(pifr.IP);
cmd.setPrivateMacAddress(pifr.MAC);
cmd.setPrivateNetmask(pifr.netmask);
}
pif = PIF.getByUuid(conn, _host.storagePif1);
pifr = pif.getRecord(conn);
if (pifr.IP != null && pifr.IP.length() > 0) {
cmd.setStorageIpAddress(pifr.IP);
cmd.setStorageMacAddress(pifr.MAC);
cmd.setStorageNetmask(pifr.netmask);
}
if (_host.storagePif2 != null) {
pif = PIF.getByUuid(conn, _host.storagePif2);
pifr = pif.getRecord(conn);
if (pifr.IP != null && pifr.IP.length() > 0) {
cmd.setStorageIpAddressDeux(pifr.IP);
cmd.setStorageMacAddressDeux(pifr.MAC);
cmd.setStorageNetmaskDeux(pifr.netmask);
}
}
Map<String, String> configs = hr.otherConfig;
cmd.setIqn(configs.get("iscsi_iqn"));
cmd.setPod(_pod);
cmd.setVersion(CitrixResourceBase.class.getPackage().getImplementationVersion());
} catch (final XmlRpcException e) {
throw new CloudRuntimeException("XML RPC Exception" + e.getMessage(), e);
} catch (XenAPIException e) {
throw new CloudRuntimeException("XenAPIException" + e.toString(), e);
}
}
public CitrixResourceBase() {
}
protected String getPatchPath() {
return "scripts/vm/hypervisor/xenserver/xcpserver";
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
_name = name;
_host.uuid = (String) params.get("guid");
try {
_dcId = Long.parseLong((String) params.get("zone"));
} catch (NumberFormatException e) {
throw new ConfigurationException("Unable to get the zone " + params.get("zone"));
}
_name = _host.uuid;
_host.ip = (String) params.get("url");
_host.pool = (String) params.get("pool");
_username = (String) params.get("username");
_password = (String) params.get("password");
_pod = (String) params.get("pod");
_cluster = (String)params.get("cluster");
_privateNetworkName = (String) params.get("private.network.device");
_publicNetworkName = (String) params.get("public.network.device");
_guestNetworkName = (String)params.get("guest.network.device");
_linkLocalPrivateNetworkName = (String) params.get("private.linkLocal.device");
if (_linkLocalPrivateNetworkName == null)
_linkLocalPrivateNetworkName = "cloud_link_local_network";
_storageNetworkName1 = (String) params.get("storage.network.device1");
if (_storageNetworkName1 == null) {
_storageNetworkName1 = "cloud-stor1";
}
_storageNetworkName2 = (String) params.get("storage.network.device2");
if (_storageNetworkName2 == null) {
_storageNetworkName2 = "cloud-stor2";
}
String value = (String) params.get("wait");
_wait = NumbersUtil.parseInt(value, 1800);
if (_pod == null) {
throw new ConfigurationException("Unable to get the pod");
}
if (_host.ip == null) {
throw new ConfigurationException("Unable to get the host address");
}
if (_username == null) {
throw new ConfigurationException("Unable to get the username");
}
if (_password == null) {
throw new ConfigurationException("Unable to get the password");
}
if (_host.uuid == null) {
throw new ConfigurationException("Unable to get the uuid");
}
String patchPath = getPatchPath();
_patchPath = Script.findScript(patchPath, "patch");
if (_patchPath == null) {
throw new ConfigurationException("Unable to find all of patch files for xenserver");
}
_storage = (StorageLayer) params.get(StorageLayer.InstanceConfigKey);
if (_storage == null) {
value = (String) params.get(StorageLayer.ClassConfigKey);
if (value == null) {
value = "com.cloud.storage.JavaStorageLayer";
}
try {
Class<?> clazz = Class.forName(value);
_storage = (StorageLayer) ComponentLocator.inject(clazz);
_storage.configure("StorageLayer", params);
} catch (ClassNotFoundException e) {
throw new ConfigurationException("Unable to find class " + value);
}
}
return true;
}
void destroyVDI(VDI vdi) {
try {
Connection conn = getConnection();
vdi.destroy(conn);
} catch (Exception e) {
String msg = "destroy VDI failed due to " + e.toString();
s_logger.warn(msg);
}
}
public CreateAnswer execute(CreateCommand cmd) {
StoragePoolTO pool = cmd.getPool();
DiskCharacteristicsTO dskch = cmd.getDiskCharacteristics();
VDI vdi = null;
Connection conn = getConnection();
try {
SR poolSr = getStorageRepository(conn, pool);
if (cmd.getTemplateUrl() != null) {
VDI tmpltvdi = null;
tmpltvdi = getVDIbyUuid(cmd.getTemplateUrl());
vdi = tmpltvdi.createClone(conn, new HashMap<String, String>());
vdi.setNameLabel(conn, dskch.getName());
} else {
VDI.Record vdir = new VDI.Record();
vdir.nameLabel = dskch.getName();
vdir.SR = poolSr;
vdir.type = Types.VdiType.USER;
vdir.virtualSize = dskch.getSize();
vdi = VDI.create(conn, vdir);
}
VDI.Record vdir;
vdir = vdi.getRecord(conn);
s_logger.debug("Succesfully created VDI for " + cmd + ". Uuid = " + vdir.uuid);
VolumeTO vol = new VolumeTO(cmd.getVolumeId(), dskch.getType(), StorageResourceType.STORAGE_POOL, pool.getType(), vdir.nameLabel, pool.getPath(), vdir.uuid,
vdir.virtualSize);
return new CreateAnswer(cmd, vol);
} catch (Exception e) {
s_logger.warn("Unable to create volume; Pool=" + pool + "; Disk: " + dskch, e);
return new CreateAnswer(cmd, e);
}
}
protected SR getISOSRbyVmName(String vmName) {
Connection conn = getConnection();
try {
Set<SR> srs = SR.getByNameLabel(conn, vmName + "-ISO");
if (srs.size() == 0) {
return null;
} else if (srs.size() == 1) {
return srs.iterator().next();
} else {
String msg = "getIsoSRbyVmName failed due to there are more than 1 SR having same Label";
s_logger.warn(msg);
}
} catch (XenAPIException e) {
String msg = "getIsoSRbyVmName failed due to " + e.toString();
s_logger.warn(msg, e);
} catch (Exception e) {
String msg = "getIsoSRbyVmName failed due to " + e.getMessage();
s_logger.warn(msg, e);
}
return null;
}
protected SR createNfsSRbyURI(URI uri, boolean shared) {
try {
Connection conn = getConnection();
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating a " + (shared ? "shared SR for " : "not shared SR for ") + uri);
}
Map<String, String> deviceConfig = new HashMap<String, String>();
String path = uri.getPath();
path = path.replace("//", "/");
deviceConfig.put("server", uri.getHost());
deviceConfig.put("serverpath", path);
String name = UUID.nameUUIDFromBytes(new String(uri.getHost() + path).getBytes()).toString();
if (!shared) {
Set<SR> srs = SR.getByNameLabel(conn, name);
for (SR sr : srs) {
SR.Record record = sr.getRecord(conn);
if (SRType.NFS.equals(record.type) && record.contentType.equals("user") && !record.shared) {
removeSRSync(sr);
}
}
}
Host host = Host.getByUuid(conn, _host.uuid);
SR sr = SR.create(conn, host, deviceConfig, new Long(0), name, uri.getHost() + uri.getPath(), SRType.NFS.toString(), "user", shared, new HashMap<String, String>());
if( !checkSR(sr) ) {
throw new Exception("no attached PBD");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug(logX(sr, "Created a SR; UUID is " + sr.getUuid(conn)));
}
sr.scan(conn);
return sr;
} catch (XenAPIException e) {
String msg = "Can not create second storage SR mountpoint: " + uri.getHost() + uri.getPath() + " due to " + e.toString();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
} catch (Exception e) {
String msg = "Can not create second storage SR mountpoint: " + uri.getHost() + uri.getPath() + " due to " + e.getMessage();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
}
}
protected SR createIsoSRbyURI(URI uri, String vmName, boolean shared) {
try {
Connection conn = getConnection();
Map<String, String> deviceConfig = new HashMap<String, String>();
String path = uri.getPath();
path = path.replace("//", "/");
deviceConfig.put("location", uri.getHost() + ":" + uri.getPath());
Host host = Host.getByUuid(conn, _host.uuid);
SR sr = SR.create(conn, host, deviceConfig, new Long(0), uri.getHost() + uri.getPath(), "iso", "iso", "iso", shared, new HashMap<String, String>());
sr.setNameLabel(conn, vmName + "-ISO");
sr.setNameDescription(conn, deviceConfig.get("location"));
sr.scan(conn);
return sr;
} catch (XenAPIException e) {
String msg = "createIsoSRbyURI failed! mountpoint: " + uri.getHost() + uri.getPath() + " due to " + e.toString();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
} catch (Exception e) {
String msg = "createIsoSRbyURI failed! mountpoint: " + uri.getHost() + uri.getPath() + " due to " + e.getMessage();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
}
}
protected VDI getVDIbyLocationandSR(String loc, SR sr) {
Connection conn = getConnection();
try {
Set<VDI> vdis = sr.getVDIs(conn);
for (VDI vdi : vdis) {
if (vdi.getLocation(conn).startsWith(loc)) {
return vdi;
}
}
String msg = "can not getVDIbyLocationandSR " + loc;
s_logger.warn(msg);
return null;
} catch (XenAPIException e) {
String msg = "getVDIbyLocationandSR exception " + loc + " due to " + e.toString();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
} catch (Exception e) {
String msg = "getVDIbyLocationandSR exception " + loc + " due to " + e.getMessage();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
}
}
protected VDI getVDIbyUuid(String uuid) {
try {
Connection conn = getConnection();
return VDI.getByUuid(conn, uuid);
} catch (XenAPIException e) {
String msg = "VDI getByUuid failed " + uuid + " due to " + e.toString();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
} catch (Exception e) {
String msg = "VDI getByUuid failed " + uuid + " due to " + e.getMessage();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
}
}
protected SR getIscsiSR(StoragePoolTO pool) {
Connection conn = getConnection();
synchronized (pool.getUuid().intern()) {
Map<String, String> deviceConfig = new HashMap<String, String>();
try {
String target = pool.getHost();
String path = pool.getPath();
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
String tmp[] = path.split("/");
if (tmp.length != 3) {
String msg = "Wrong iscsi path " + pool.getPath() + " it should be /targetIQN/LUN";
s_logger.warn(msg);
throw new CloudRuntimeException(msg);
}
String targetiqn = tmp[1].trim();
String lunid = tmp[2].trim();
String scsiid = "";
Set<SR> srs = SR.getByNameLabel(conn, pool.getUuid());
for (SR sr : srs) {
if (!SRType.LVMOISCSI.equals(sr.getType(conn)))
continue;
Set<PBD> pbds = sr.getPBDs(conn);
if (pbds.isEmpty())
continue;
PBD pbd = pbds.iterator().next();
Map<String, String> dc = pbd.getDeviceConfig(conn);
if (dc == null)
continue;
if (dc.get("target") == null)
continue;
if (dc.get("targetIQN") == null)
continue;
if (dc.get("lunid") == null)
continue;
if (target.equals(dc.get("target")) && targetiqn.equals(dc.get("targetIQN")) && lunid.equals(dc.get("lunid"))) {
if (checkSR(sr)) {
return sr;
}
throw new CloudRuntimeException("SR check failed for storage pool: " + pool.getUuid() + "on host:" + _host.uuid);
}
}
deviceConfig.put("target", target);
deviceConfig.put("targetIQN", targetiqn);
Host host = Host.getByUuid(conn, _host.uuid);
SR sr = null;
try {
sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), Long.toString(pool.getId()), SRType.LVMOISCSI.toString(), "user", true,
new HashMap<String, String>());
} catch (XenAPIException e) {
String errmsg = e.toString();
if (errmsg.contains("SR_BACKEND_FAILURE_107")) {
String lun[] = errmsg.split("<LUN>");
boolean found = false;
for (int i = 1; i < lun.length; i++) {
int blunindex = lun[i].indexOf("<LUNid>") + 7;
int elunindex = lun[i].indexOf("</LUNid>");
String ilun = lun[i].substring(blunindex, elunindex);
ilun = ilun.trim();
if (ilun.equals(lunid)) {
int bscsiindex = lun[i].indexOf("<SCSIid>") + 8;
int escsiindex = lun[i].indexOf("</SCSIid>");
scsiid = lun[i].substring(bscsiindex, escsiindex);
scsiid = scsiid.trim();
found = true;
break;
}
}
if (!found) {
String msg = "can not find LUN " + lunid + " in " + errmsg;
s_logger.warn(msg);
throw new CloudRuntimeException(msg);
}
} else {
String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
}
}
deviceConfig.put("SCSIid", scsiid);
sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), Long.toString(pool.getId()), SRType.LVMOISCSI.toString(), "user", true,
new HashMap<String, String>());
sr.scan(conn);
return sr;
} catch (XenAPIException e) {
String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
} catch (Exception e) {
String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.getMessage();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
}
}
}
protected SR getNfsSR(StoragePoolTO pool) {
Connection conn = getConnection();
Map<String, String> deviceConfig = new HashMap<String, String>();
try {
String server = pool.getHost();
String serverpath = pool.getPath();
serverpath = serverpath.replace("//", "/");
Map<SR, SR.Record> srMaps = SR.getAllRecords(conn);
for (Map.Entry<SR, SR.Record> entry : srMaps.entrySet()) {
SR sr = entry.getKey();
SR.Record srRec = entry.getValue();
if (!SRType.NFS.equals(srRec.type))
continue;
if (srRec.PBDs.isEmpty())
continue;
PBD pbd = srRec.PBDs.iterator().next();
Map<String, String> dc = pbd.getDeviceConfig(conn);
if (dc == null)
continue;
if (dc.get("server") == null)
continue;
if (dc.get("serverpath") == null)
continue;
if (server.equals(dc.get("server")) && serverpath.equals(dc.get("serverpath"))) {
if (checkSR(sr)) {
return sr;
}
throw new CloudRuntimeException("SR check failed for storage pool: " + pool.getUuid() + "on host:" + _host.uuid);
}
}
deviceConfig.put("server", server);
deviceConfig.put("serverpath", serverpath);
Host host = Host.getByUuid(conn, _host.uuid);
SR sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), Long.toString(pool.getId()), SRType.NFS.toString(), "user", true,
new HashMap<String, String>());
sr.scan(conn);
return sr;
} catch (XenAPIException e) {
throw new CloudRuntimeException("Unable to create NFS SR " + pool.toString(), e);
} catch (XmlRpcException e) {
throw new CloudRuntimeException("Unable to create NFS SR " + pool.toString(), e);
}
}
public Answer execute(DestroyCommand cmd) {
VolumeTO vol = cmd.getVolume();
Connection conn = getConnection();
// Look up the VDI
String volumeUUID = vol.getPath();
VDI vdi = null;
try {
vdi = getVDIbyUuid(volumeUUID);
} catch (Exception e) {
String msg = "getVDIbyUuid for " + volumeUUID + " failed due to " + e.toString();
s_logger.warn(msg);
return new Answer(cmd, true, "Success");
}
Set<VBD> vbds = null;
try {
vbds = vdi.getVBDs(conn);
} catch (Exception e) {
String msg = "VDI getVBDS for " + volumeUUID + " failed due to " + e.toString();
s_logger.warn(msg, e);
return new Answer(cmd, false, msg);
}
for (VBD vbd : vbds) {
try {
vbd.unplug(conn);
vbd.destroy(conn);
} catch (Exception e) {
String msg = "VM destroy for " + volumeUUID + " failed due to " + e.toString();
s_logger.warn(msg, e);
return new Answer(cmd, false, msg);
}
}
try {
vdi.destroy(conn);
} catch (Exception e) {
String msg = "VDI destroy for " + volumeUUID + " failed due to " + e.toString();
s_logger.warn(msg, e);
return new Answer(cmd, false, msg);
}
return new Answer(cmd, true, "Success");
}
public ShareAnswer execute(final ShareCommand cmd) {
if (!cmd.isShare()) {
SR sr = getISOSRbyVmName(cmd.getVmName());
Connection conn = getConnection();
try {
if (sr != null) {
Set<VM> vms = VM.getByNameLabel(conn, cmd.getVmName());
if (vms.size() == 0) {
removeSR(sr);
}
}
} catch (Exception e) {
String msg = "SR.getNameLabel failed due to " + e.getMessage() + e.toString();
s_logger.warn(msg);
}
}
return new ShareAnswer(cmd, new HashMap<String, Integer>());
}
public CopyVolumeAnswer execute(final CopyVolumeCommand cmd) {
String volumeUUID = cmd.getVolumePath();
StoragePoolVO pool = cmd.getPool();
StoragePoolTO poolTO = new StoragePoolTO(pool);
String secondaryStorageURL = cmd.getSecondaryStorageURL();
URI uri = null;
try {
uri = new URI(secondaryStorageURL);
} catch (URISyntaxException e) {
return new CopyVolumeAnswer(cmd, false, "Invalid secondary storage URL specified.", null, null);
}
String remoteVolumesMountPath = uri.getHost() + ":" + uri.getPath() + "/volumes/";
String volumeFolder = String.valueOf(cmd.getVolumeId()) + "/";
boolean toSecondaryStorage = cmd.toSecondaryStorage();
String errorMsg = "Failed to copy volume";
SR primaryStoragePool = null;
SR secondaryStorage = null;
VDI srcVolume = null;
VDI destVolume = null;
Connection conn = getConnection();
try {
if (toSecondaryStorage) {
// Create the volume folder
if (!createSecondaryStorageFolder(remoteVolumesMountPath, volumeFolder)) {
throw new InternalErrorException("Failed to create the volume folder.");
}
// Create a SR for the volume UUID folder
secondaryStorage = createNfsSRbyURI(new URI(secondaryStorageURL + "/volumes/" + volumeFolder), false);
// Look up the volume on the source primary storage pool
srcVolume = getVDIbyUuid(volumeUUID);
// Copy the volume to secondary storage
destVolume = cloudVDIcopy(srcVolume, secondaryStorage);
} else {
// Mount the volume folder
secondaryStorage = createNfsSRbyURI(new URI(secondaryStorageURL + "/volumes/" + volumeFolder), false);
// Look up the volume on secondary storage
Set<VDI> vdis = secondaryStorage.getVDIs(conn);
for (VDI vdi : vdis) {
if (vdi.getUuid(conn).equals(volumeUUID)) {
srcVolume = vdi;
break;
}
}
if (srcVolume == null) {
throw new InternalErrorException("Failed to find volume on secondary storage.");
}
// Copy the volume to the primary storage pool
primaryStoragePool = getStorageRepository(conn, poolTO);
destVolume = cloudVDIcopy(srcVolume, primaryStoragePool);
}
String srUUID;
if (primaryStoragePool == null) {
srUUID = secondaryStorage.getUuid(conn);
} else {
srUUID = primaryStoragePool.getUuid(conn);
}
String destVolumeUUID = destVolume.getUuid(conn);
return new CopyVolumeAnswer(cmd, true, null, srUUID, destVolumeUUID);
} catch (XenAPIException e) {
s_logger.warn(errorMsg + ": " + e.toString(), e);
return new CopyVolumeAnswer(cmd, false, e.toString(), null, null);
} catch (Exception e) {
s_logger.warn(errorMsg + ": " + e.toString(), e);
return new CopyVolumeAnswer(cmd, false, e.getMessage(), null, null);
} finally {
if (!toSecondaryStorage && srcVolume != null) {
// Delete the volume on secondary storage
destroyVDI(srcVolume);
}
removeSR(secondaryStorage);
if (!toSecondaryStorage) {
// Delete the volume folder on secondary storage
deleteSecondaryStorageFolder(remoteVolumesMountPath, volumeFolder);
}
}
}
protected AttachVolumeAnswer execute(final AttachVolumeCommand cmd) {
boolean attach = cmd.getAttach();
String vmName = cmd.getVmName();
Long deviceId = cmd.getDeviceId();
String errorMsg;
if (attach) {
errorMsg = "Failed to attach volume";
} else {
errorMsg = "Failed to detach volume";
}
Connection conn = getConnection();
try {
// Look up the VDI
VDI vdi = mount(cmd.getPooltype(), cmd.getVolumeFolder(),cmd.getVolumePath());
// Look up the VM
VM vm = getVM(conn, vmName);
/* For HVM guest, if no pv driver installed, no attach/detach */
boolean isHVM;
if (vm.getPVBootloader(conn).equalsIgnoreCase(""))
isHVM = true;
else
isHVM = false;
VMGuestMetrics vgm = vm.getGuestMetrics(conn);
boolean pvDrvInstalled = false;
if (!isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) {
pvDrvInstalled = true;
}
if (isHVM && !pvDrvInstalled) {
s_logger.warn(errorMsg + ": You attempted an operation on a VM which requires PV drivers to be installed but the drivers were not detected");
return new AttachVolumeAnswer(cmd, "You attempted an operation that requires PV drivers to be installed on the VM. Please install them by inserting xen-pv-drv.iso.");
}
if (attach) {
// Figure out the disk number to attach the VM to
String diskNumber = null;
if( deviceId != null ) {
if(isDeviceUsed(vm, deviceId)) {
String msg = "Device " + deviceId + " is used in VM " + vmName;
return new AttachVolumeAnswer(cmd,msg);
}
diskNumber = deviceId.toString();
} else {
diskNumber = getUnusedDeviceNum(vm);
}
// Create a new VBD
VBD.Record vbdr = new VBD.Record();
vbdr.VM = vm;
vbdr.VDI = vdi;
vbdr.bootable = false;
vbdr.userdevice = diskNumber;
vbdr.mode = Types.VbdMode.RW;
vbdr.type = Types.VbdType.DISK;
vbdr.unpluggable = true;
VBD vbd = VBD.create(conn, vbdr);
// Attach the VBD to the VM
vbd.plug(conn);
// Update the VDI's label to include the VM name
vdi.setNameLabel(conn, vmName + "-DATA");
return new AttachVolumeAnswer(cmd, Long.parseLong(diskNumber));
} else {
// Look up all VBDs for this VDI
Set<VBD> vbds = vdi.getVBDs(conn);
// Detach each VBD from its VM, and then destroy it
for (VBD vbd : vbds) {
VBD.Record vbdr = vbd.getRecord(conn);
if (vbdr.currentlyAttached) {
vbd.unplug(conn);
}
vbd.destroy(conn);
}
// Update the VDI's label to be "detached"
vdi.setNameLabel(conn, "detached");
umount(vdi);
return new AttachVolumeAnswer(cmd);
}
} catch (XenAPIException e) {
String msg = errorMsg + " for uuid: " + cmd.getVolumePath() + " due to " + e.toString();
s_logger.warn(msg, e);
return new AttachVolumeAnswer(cmd, msg);
} catch (Exception e) {
String msg = errorMsg + " for uuid: " + cmd.getVolumePath() + " due to " + e.getMessage();
s_logger.warn(msg, e);
return new AttachVolumeAnswer(cmd, msg);
}
}
protected void umount(VDI vdi) {
}
protected Answer execute(final AttachIsoCommand cmd) {
boolean attach = cmd.isAttach();
String vmName = cmd.getVmName();
String isoURL = cmd.getIsoPath();
String errorMsg;
if (attach) {
errorMsg = "Failed to attach ISO";
} else {
errorMsg = "Failed to detach ISO";
}
Connection conn = getConnection();
try {
if (attach) {
VBD isoVBD = null;
// Find the VM
VM vm = getVM(conn, vmName);
// Find the ISO VDI
VDI isoVDI = getIsoVDIByURL(conn, vmName, isoURL);
// Find the VM's CD-ROM VBD
Set<VBD> vbds = vm.getVBDs(conn);
for (VBD vbd : vbds) {
String userDevice = vbd.getUserdevice(conn);
Types.VbdType type = vbd.getType(conn);
if (userDevice.equals("3") && type == Types.VbdType.CD) {
isoVBD = vbd;
break;
}
}
if (isoVBD == null) {
throw new CloudRuntimeException("Unable to find CD-ROM VBD for VM: " + vmName);
} else {
// If an ISO is already inserted, eject it
if (isoVBD.getEmpty(conn) == false) {
isoVBD.eject(conn);
}
// Insert the new ISO
isoVBD.insert(conn, isoVDI);
}
return new Answer(cmd);
} else {
// Find the VM
VM vm = getVM(conn, vmName);
String vmUUID = vm.getUuid(conn);
// Find the ISO VDI
VDI isoVDI = getIsoVDIByURL(conn, vmName, isoURL);
SR sr = isoVDI.getSR(conn);
// Look up all VBDs for this VDI
Set<VBD> vbds = isoVDI.getVBDs(conn);
// Iterate through VBDs, and if the VBD belongs the VM, eject
// the ISO from it
for (VBD vbd : vbds) {
VM vbdVM = vbd.getVM(conn);
String vbdVmUUID = vbdVM.getUuid(conn);
if (vbdVmUUID.equals(vmUUID)) {
// If an ISO is already inserted, eject it
if (!vbd.getEmpty(conn)) {
vbd.eject(conn);
}
break;
}
}
if (!sr.getNameLabel(conn).startsWith("XenServer Tools")) {
removeSR(sr);
}
return new Answer(cmd);
}
} catch (XenAPIException e) {
s_logger.warn(errorMsg + ": " + e.toString(), e);
return new Answer(cmd, false, e.toString());
} catch (Exception e) {
s_logger.warn(errorMsg + ": " + e.toString(), e);
return new Answer(cmd, false, e.getMessage());
}
}
protected ValidateSnapshotAnswer execute(final ValidateSnapshotCommand cmd) {
String primaryStoragePoolNameLabel = cmd.getPrimaryStoragePoolNameLabel();
String volumeUuid = cmd.getVolumeUuid(); // Precondition: not null
String firstBackupUuid = cmd.getFirstBackupUuid();
String previousSnapshotUuid = cmd.getPreviousSnapshotUuid();
String templateUuid = cmd.getTemplateUuid();
// By default assume failure
String details = "Could not validate previous snapshot backup UUID " + "because the primary Storage SR could not be created from the name label: "
+ primaryStoragePoolNameLabel;
boolean success = false;
String expectedSnapshotBackupUuid = null;
String actualSnapshotBackupUuid = null;
String actualSnapshotUuid = null;
Boolean isISCSI = false;
String primaryStorageSRUuid = null;
Connection conn = getConnection();
try {
SR primaryStorageSR = getSRByNameLabelandHost(primaryStoragePoolNameLabel);
if (primaryStorageSR != null) {
primaryStorageSRUuid = primaryStorageSR.getUuid(conn);
isISCSI = SRType.LVMOISCSI.equals(primaryStorageSR.getType(conn));
}
} catch (BadServerResponse e) {
details += ", reason: " + e.getMessage();
s_logger.error(details, e);
} catch (XenAPIException e) {
details += ", reason: " + e.getMessage();
s_logger.error(details, e);
} catch (XmlRpcException e) {
details += ", reason: " + e.getMessage();
s_logger.error(details, e);
}
if (primaryStorageSRUuid != null) {
if (templateUuid == null) {
templateUuid = "";
}
if (firstBackupUuid == null) {
firstBackupUuid = "";
}
if (previousSnapshotUuid == null) {
previousSnapshotUuid = "";
}
String result = callHostPlugin("validateSnapshot", "primaryStorageSRUuid", primaryStorageSRUuid, "volumeUuid", volumeUuid, "firstBackupUuid", firstBackupUuid,
"previousSnapshotUuid", previousSnapshotUuid, "templateUuid", templateUuid, "isISCSI", isISCSI.toString());
if (result == null || result.isEmpty()) {
details = "Validating snapshot backup for volume with UUID: " + volumeUuid + " failed because there was an exception in the plugin";
// callHostPlugin exception which has been logged already
} else {
String[] uuids = result.split("#", -1);
if (uuids.length >= 3) {
expectedSnapshotBackupUuid = uuids[1];
actualSnapshotBackupUuid = uuids[2];
}
if (uuids.length >= 4) {
actualSnapshotUuid = uuids[3];
} else {
actualSnapshotUuid = "";
}
if (uuids[0].equals("1")) {
success = true;
details = null;
} else {
details = "Previous snapshot backup on the primary storage is invalid. " + "Expected: " + expectedSnapshotBackupUuid + " Actual: " + actualSnapshotBackupUuid;
// success is still false
}
s_logger.debug("ValidatePreviousSnapshotBackup returned " + " success: " + success + " details: " + details + " expectedSnapshotBackupUuid: "
+ expectedSnapshotBackupUuid + " actualSnapshotBackupUuid: " + actualSnapshotBackupUuid + " actualSnapshotUuid: " + actualSnapshotUuid);
}
}
return new ValidateSnapshotAnswer(cmd, success, details, expectedSnapshotBackupUuid, actualSnapshotBackupUuid, actualSnapshotUuid);
}
protected String getVhdParent(String primaryStorageSRUuid, String snapshotUuid, Boolean isISCSI) {
String parentUuid = callHostPlugin("getVhdParent", "primaryStorageSRUuid", primaryStorageSRUuid,
"snapshotUuid", snapshotUuid, "isISCSI", isISCSI.toString());
if (parentUuid == null || parentUuid.isEmpty()) {
s_logger.debug("Unable to get parent of VHD " + snapshotUuid + " in SR " + primaryStorageSRUuid);
// errString is already logged.
return null;
}
return parentUuid;
}
protected ManageSnapshotAnswer execute(final ManageSnapshotCommand cmd) {
long snapshotId = cmd.getSnapshotId();
String snapshotName = cmd.getSnapshotName();
// By default assume failure
boolean success = false;
String cmdSwitch = cmd.getCommandSwitch();
String snapshotOp = "Unsupported snapshot command." + cmdSwitch;
if (cmdSwitch.equals(ManageSnapshotCommand.CREATE_SNAPSHOT)) {
snapshotOp = "create";
} else if (cmdSwitch.equals(ManageSnapshotCommand.DESTROY_SNAPSHOT)) {
snapshotOp = "destroy";
}
String details = "ManageSnapshotCommand operation: " + snapshotOp + " Failed for snapshotId: " + snapshotId;
String snapshotUUID = null;
Connection conn = getConnection();
try {
if (cmdSwitch.equals(ManageSnapshotCommand.CREATE_SNAPSHOT)) {
// Look up the volume
String volumeUUID = cmd.getVolumePath();
VDI volume = getVDIbyUuid(volumeUUID);
// Create a snapshot
VDI snapshot = volume.snapshot(conn, new HashMap<String, String>());
if (snapshotName != null) {
snapshot.setNameLabel(conn, snapshotName);
}
// Determine the UUID of the snapshot
snapshotUUID = snapshot.getUuid(conn);
String preSnapshotUUID = cmd.getSnapshotPath();
//check if it is a empty snapshot
if( preSnapshotUUID != null) {
SR sr = volume.getSR(conn);
String srUUID = sr.getUuid(conn);
String type = sr.getType(conn);
Boolean isISCSI = SRType.LVMOISCSI.equals(type);
String snapshotParentUUID = getVhdParent(srUUID, snapshotUUID, isISCSI);
String preSnapshotParentUUID = getVhdParent(srUUID, preSnapshotUUID, isISCSI);
if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) {
// this is empty snapshot, remove it
snapshot.destroy(conn);
snapshotUUID = preSnapshotUUID;
}
}
} else if (cmd.getCommandSwitch().equals(ManageSnapshotCommand.DESTROY_SNAPSHOT)) {
// Look up the snapshot
snapshotUUID = cmd.getSnapshotPath();
VDI snapshot = getVDIbyUuid(snapshotUUID);
snapshot.destroy(conn);
snapshotUUID = null;
}
success = true;
details = null;
} catch (XenAPIException e) {
details += ", reason: " + e.toString();
s_logger.warn(details, e);
} catch (Exception e) {
details += ", reason: " + e.toString();
s_logger.warn(details, e);
}
return new ManageSnapshotAnswer(cmd, snapshotId, snapshotUUID, success, details);
}
protected CreatePrivateTemplateAnswer execute(final CreatePrivateTemplateCommand cmd) {
String secondaryStorageURL = cmd.getSecondaryStorageURL();
String snapshotUUID = cmd.getSnapshotPath();
String userSpecifiedName = cmd.getTemplateName();
SR secondaryStorage = null;
VDI privateTemplate = null;
Connection conn = getConnection();
try {
URI uri = new URI(secondaryStorageURL);
String remoteTemplateMountPath = uri.getHost() + ":" + uri.getPath() + "/template/";
String templateFolder = cmd.getAccountId() + "/" + cmd.getTemplateId() + "/";
String templateDownloadFolder = createTemplateDownloadFolder(remoteTemplateMountPath, templateFolder);
String templateInstallFolder = "tmpl/" + templateFolder;
// Create a SR for the secondary storage download folder
secondaryStorage = createNfsSRbyURI(new URI(secondaryStorageURL + "/template/" + templateDownloadFolder), false);
// Look up the snapshot and copy it to secondary storage
VDI snapshot = getVDIbyUuid(snapshotUUID);
privateTemplate = cloudVDIcopy(snapshot, secondaryStorage);
if (userSpecifiedName != null) {
privateTemplate.setNameLabel(conn, userSpecifiedName);
}
// Determine the template file name and install path
VDI.Record vdir = privateTemplate.getRecord(conn);
String templateName = vdir.uuid;
String templateFilename = templateName + ".vhd";
String installPath = "template/" + templateInstallFolder + templateFilename;
// Determine the template's virtual size and then forget the VDI
long virtualSize = privateTemplate.getVirtualSize(conn);
// Create the template.properties file in the download folder, move
// the template and the template.properties file
// to the install folder, and then delete the download folder
if (!postCreatePrivateTemplate(remoteTemplateMountPath, templateDownloadFolder, templateInstallFolder, templateFilename, templateName, userSpecifiedName, null,
virtualSize, cmd.getTemplateId())) {
throw new InternalErrorException("Failed to create the template.properties file.");
}
return new CreatePrivateTemplateAnswer(cmd, true, null, installPath, virtualSize, templateName, ImageFormat.VHD);
} catch (XenAPIException e) {
if (privateTemplate != null) {
destroyVDI(privateTemplate);
}
s_logger.warn("CreatePrivateTemplate Failed due to " + e.toString(), e);
return new CreatePrivateTemplateAnswer(cmd, false, e.toString(), null, 0, null, null);
} catch (Exception e) {
s_logger.warn("CreatePrivateTemplate Failed due to " + e.getMessage(), e);
return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage(), null, 0, null, null);
} finally {
// Remove the secondary storage SR
removeSR(secondaryStorage);
}
}
private String createTemplateDownloadFolder(String remoteTemplateMountPath, String templateFolder) throws InternalErrorException, URISyntaxException {
String templateDownloadFolder = "download/" + _host.uuid + "/" + templateFolder;
// Create the download folder
if (!createSecondaryStorageFolder(remoteTemplateMountPath, templateDownloadFolder)) {
throw new InternalErrorException("Failed to create the template download folder.");
}
return templateDownloadFolder;
}
protected CreatePrivateTemplateAnswer execute(final CreatePrivateTemplateFromSnapshotCommand cmd) {
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
Long dcId = cmd.getDataCenterId();
Long accountId = cmd.getAccountId();
Long volumeId = cmd.getVolumeId();
String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL();
String backedUpSnapshotUuid = cmd.getSnapshotUuid();
String origTemplateInstallPath = cmd.getOrigTemplateInstallPath();
Long newTemplateId = cmd.getNewTemplateId();
String userSpecifiedName = cmd.getTemplateName();
// By default, assume failure
String details = "Failed to create private template " + newTemplateId + " from snapshot for volume: " + volumeId + " with backupUuid: " + backedUpSnapshotUuid;
String newTemplatePath = null;
String templateName = null;
boolean result = false;
long virtualSize = 0;
try {
URI uri = new URI(secondaryStoragePoolURL);
String remoteTemplateMountPath = uri.getHost() + ":" + uri.getPath() + "/template/";
String templateFolder = cmd.getAccountId() + "/" + newTemplateId + "/";
String templateDownloadFolder = createTemplateDownloadFolder(remoteTemplateMountPath, templateFolder);
String templateInstallFolder = "tmpl/" + templateFolder;
// Yes, create a template vhd
Pair<VHDInfo, String> vhdDetails = createVHDFromSnapshot(primaryStorageNameLabel, dcId, accountId, volumeId, secondaryStoragePoolURL, backedUpSnapshotUuid,
origTemplateInstallPath, templateDownloadFolder);
VHDInfo vhdInfo = vhdDetails.first();
String failureDetails = vhdDetails.second();
if (vhdInfo == null) {
if (failureDetails != null) {
details += failureDetails;
}
} else {
templateName = vhdInfo.getUuid();
String templateFilename = templateName + ".vhd";
String templateInstallPath = templateInstallFolder + File.separator + templateFilename;
newTemplatePath = "template" + File.separator + templateInstallPath;
virtualSize = vhdInfo.getVirtualSize();
// create the template.properties file
result = postCreatePrivateTemplate(remoteTemplateMountPath, templateDownloadFolder, templateInstallFolder, templateFilename, templateName, userSpecifiedName, null,
virtualSize, newTemplateId);
if (!result) {
details += ", reason: Could not create the template.properties file on secondary storage dir: " + templateInstallFolder;
} else {
// Aaah, success.
details = null;
}
}
} catch (XenAPIException e) {
details += ", reason: " + e.getMessage();
s_logger.error(details, e);
} catch (Exception e) {
details += ", reason: " + e.getMessage();
s_logger.error(details, e);
}
return new CreatePrivateTemplateAnswer(cmd, result, details, newTemplatePath, virtualSize, templateName, ImageFormat.VHD);
}
protected BackupSnapshotAnswer execute(final BackupSnapshotCommand cmd) {
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
Long dcId = cmd.getDataCenterId();
Long accountId = cmd.getAccountId();
Long volumeId = cmd.getVolumeId();
String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL();
String snapshotUuid = cmd.getSnapshotUuid(); // not null: Precondition.
String prevSnapshotUuid = cmd.getPrevSnapshotUuid();
String prevBackupUuid = cmd.getPrevBackupUuid();
boolean isFirstSnapshotOfRootVolume = cmd.isFirstSnapshotOfRootVolume();
String firstBackupUuid = cmd.getFirstBackupUuid();
// By default assume failure
String details = null;
boolean success = false;
String snapshotBackupUuid = null;
try {
Connection conn = getConnection();
SR primaryStorageSR = getSRByNameLabelandHost(primaryStorageNameLabel);
if (primaryStorageSR == null) {
throw new InternalErrorException("Could not backup snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel);
}
String primaryStorageSRUuid = primaryStorageSR.getUuid(conn);
Boolean isISCSI = SRType.LVMOISCSI.equals(primaryStorageSR.getType(conn));
URI uri = new URI(secondaryStoragePoolURL);
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
if (secondaryStorageMountPath == null) {
details = "Couldn't backup snapshot because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
} else {
boolean gcHappened = true;
if (prevSnapshotUuid != null && !isFirstSnapshotOfRootVolume) {
// For the first snapshot of a root volume, the prevSnapshotUuid is set to the template uuid.
// This is to catch the case where the first snapshot is empty.
// But we need not wait for GC as no snapshot has been taken.
// gcHappened = waitForGC(primaryStorageSRUuid, prevSnapshotUuid, firstBackupUuid, isISCSI);
}
if (gcHappened) {
snapshotBackupUuid = backupSnapshot(primaryStorageSRUuid, dcId, accountId, volumeId, secondaryStorageMountPath, snapshotUuid, prevSnapshotUuid, prevBackupUuid,
isFirstSnapshotOfRootVolume, isISCSI);
success = (snapshotBackupUuid != null);
} else {
s_logger.warn("GC hasn't happened yet for previousSnapshotUuid: " + prevSnapshotUuid + ". Will retry again after 1 min");
}
}
if (!success) {
// Mark the snapshot as removed in the database.
// When the next snapshot is taken, it will be
// 1) deleted from the DB 2) The snapshotUuid will be deleted from the primary
// 3) the snapshotBackupUuid will be copied to secondary
// 4) if possible it will be coalesced with the next snapshot.
} else if (prevSnapshotUuid != null && !isFirstSnapshotOfRootVolume) {
// Destroy the previous snapshot, if it exists.
// We destroy the previous snapshot only if the current snapshot
// backup succeeds.
// The aim is to keep the VDI of the last 'successful' snapshot
// so that it doesn't get merged with the
// new one
// and muddle the vhd chain on the secondary storage.
details = "Successfully backedUp the snapshotUuid: " + snapshotUuid + " to secondary storage.";
String volumeUuid = cmd.getVolumeUUID();
destroySnapshotOnPrimaryStorageExceptThis(volumeUuid, snapshotUuid);
}
} catch (XenAPIException e) {
details = "BackupSnapshot Failed due to " + e.toString();
s_logger.warn(details, e);
} catch (Exception e) {
details = "BackupSnapshot Failed due to " + e.getMessage();
s_logger.warn(details, e);
}
return new BackupSnapshotAnswer(cmd, success, details, snapshotBackupUuid);
}
protected CreateVolumeFromSnapshotAnswer execute(final CreateVolumeFromSnapshotCommand cmd) {
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
Long dcId = cmd.getDataCenterId();
Long accountId = cmd.getAccountId();
Long volumeId = cmd.getVolumeId();
String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL();
String backedUpSnapshotUuid = cmd.getSnapshotUuid();
String templatePath = cmd.getTemplatePath();
// By default, assume the command has failed and set the params to be
// passed to CreateVolumeFromSnapshotAnswer appropriately
boolean result = false;
// Generic error message.
String details = "Failed to create volume from snapshot for volume: " + volumeId + " with backupUuid: " + backedUpSnapshotUuid;
String vhdUUID = null;
SR temporarySROnSecondaryStorage = null;
String mountPointOfTemporaryDirOnSecondaryStorage = null;
try {
VDI vdi = null;
Connection conn = getConnection();
SR primaryStorageSR = getSRByNameLabelandHost(primaryStorageNameLabel);
if (primaryStorageSR == null) {
throw new InternalErrorException("Could not create volume from snapshot because the primary Storage SR could not be created from the name label: "
+ primaryStorageNameLabel);
}
Boolean isISCSI = SRType.LVMOISCSI.equals(primaryStorageSR.getType(conn));
// Get the absolute path of the template on the secondary storage.
URI uri = new URI(secondaryStoragePoolURL);
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
if (secondaryStorageMountPath == null) {
details += " because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
return new CreateVolumeFromSnapshotAnswer(cmd, result, details, vhdUUID);
}
// Create a volume and not a template
String templateDownloadFolder = "";
VHDInfo vhdInfo = createVHDFromSnapshot(dcId, accountId, volumeId, secondaryStorageMountPath, backedUpSnapshotUuid, templatePath, templateDownloadFolder, isISCSI);
if (vhdInfo == null) {
details += " because the vmops plugin on XenServer failed at some point";
} else {
vhdUUID = vhdInfo.getUuid();
String tempDirRelativePath = "snapshots" + File.separator + accountId + File.separator + volumeId + "_temp";
mountPointOfTemporaryDirOnSecondaryStorage = secondaryStorageMountPath + File.separator + tempDirRelativePath;
uri = new URI("nfs://" + mountPointOfTemporaryDirOnSecondaryStorage);
// No need to check if the SR already exists. It's a temporary
// SR destroyed when this method exits.
// And two createVolumeFromSnapshot operations cannot proceed at
// the same time.
temporarySROnSecondaryStorage = createNfsSRbyURI(uri, false);
if (temporarySROnSecondaryStorage == null) {
details += "because SR couldn't be created on " + mountPointOfTemporaryDirOnSecondaryStorage;
} else {
s_logger.debug("Successfully created temporary SR on secondary storage " + temporarySROnSecondaryStorage.getNameLabel(conn) + "with uuid "
+ temporarySROnSecondaryStorage.getUuid(conn) + " and scanned it");
// createNFSSRbyURI also scans the SR and introduces the VDI
vdi = getVDIbyUuid(vhdUUID);
if (vdi != null) {
s_logger.debug("Successfully created VDI on secondary storage SR " + temporarySROnSecondaryStorage.getNameLabel(conn) + " with uuid " + vhdUUID);
s_logger.debug("Copying VDI: " + vdi.getLocation(conn) + " from secondary to primary");
VDI vdiOnPrimaryStorage = cloudVDIcopy(vdi, primaryStorageSR);
// vdi.copy introduces the vdi into the database. Don't
// need to do a scan on the primary
// storage.
if (vdiOnPrimaryStorage != null) {
vhdUUID = vdiOnPrimaryStorage.getUuid(conn);
s_logger.debug("Successfully copied and introduced VDI on primary storage with path " + vdiOnPrimaryStorage.getLocation(conn) + " and uuid " + vhdUUID);
result = true;
details = null;
} else {
details += ". Could not copy the vdi " + vhdUUID + " to primary storage";
}
// The VHD on temporary was scanned and introduced as a VDI
// destroy it as we don't need it anymore.
vdi.destroy(conn);
} else {
details += ". Could not scan and introduce vdi with uuid: " + vhdUUID;
}
}
}
} catch (XenAPIException e) {
details += " due to " + e.toString();
s_logger.warn(details, e);
} catch (Exception e) {
details += " due to " + e.getMessage();
s_logger.warn(details, e);
} finally {
// In all cases, if the temporary SR was created, forget it.
if (temporarySROnSecondaryStorage != null) {
removeSR(temporarySROnSecondaryStorage);
// Delete the temporary directory created.
File folderPath = new File(mountPointOfTemporaryDirOnSecondaryStorage);
String remoteMountPath = folderPath.getParent();
String folder = folderPath.getName();
deleteSecondaryStorageFolder(remoteMountPath, folder);
}
}
if (!result) {
// Is this logged at a higher level?
s_logger.error(details);
}
// In all cases return something.
return new CreateVolumeFromSnapshotAnswer(cmd, result, details, vhdUUID);
}
protected DeleteSnapshotBackupAnswer execute(final DeleteSnapshotBackupCommand cmd) {
Long dcId = cmd.getDataCenterId();
Long accountId = cmd.getAccountId();
Long volumeId = cmd.getVolumeId();
String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL();
String backupUUID = cmd.getSnapshotUuid();
String childUUID = cmd.getChildUUID();
String childChildUUID = cmd.getChildChildUUID();
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
String details = null;
boolean success = false;
SR primaryStorageSR = null;
Boolean isISCSI = false;
try {
Connection conn = getConnection();
primaryStorageSR = getSRByNameLabelandHost(primaryStorageNameLabel);
if (primaryStorageSR == null) {
details = "Primary Storage SR could not be created from the name label: " + primaryStorageNameLabel;
throw new InternalErrorException(details);
}
isISCSI = SRType.LVMOISCSI.equals(primaryStorageSR.getType(conn));
} catch (XenAPIException e) {
details = "Couldn't determine primary SR type " + e.getMessage();
s_logger.error(details, e);
} catch (Exception e) {
details = "Couldn't determine primary SR type " + e.getMessage();
s_logger.error(details, e);
}
if (primaryStorageSR != null) {
URI uri = null;
try {
uri = new URI(secondaryStoragePoolURL);
} catch (URISyntaxException e) {
details = "Error finding the secondary storage URL" + e.getMessage();
s_logger.error(details, e);
}
if (uri != null) {
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
if (secondaryStorageMountPath == null) {
details = "Couldn't delete snapshot because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
} else {
details = deleteSnapshotBackup(dcId, accountId, volumeId, secondaryStorageMountPath, backupUUID, childUUID, childChildUUID, isISCSI);
success = (details != null && details.equals("1"));
if (success) {
s_logger.debug("Successfully deleted snapshot backup " + backupUUID);
}
}
}
}
return new DeleteSnapshotBackupAnswer(cmd, success, details);
}
protected Answer execute(DeleteSnapshotsDirCommand cmd) {
Long dcId = cmd.getDataCenterId();
Long accountId = cmd.getAccountId();
Long volumeId = cmd.getVolumeId();
String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL();
String snapshotUUID = cmd.getSnapshotUuid();
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
String details = null;
boolean success = false;
SR primaryStorageSR = null;
try {
primaryStorageSR = getSRByNameLabelandHost(primaryStorageNameLabel);
if (primaryStorageSR == null) {
details = "Primary Storage SR could not be created from the name label: " + primaryStorageNameLabel;
}
} catch (XenAPIException e) {
details = "Couldn't determine primary SR type " + e.getMessage();
s_logger.error(details, e);
} catch (Exception e) {
details = "Couldn't determine primary SR type " + e.getMessage();
s_logger.error(details, e);
}
if (primaryStorageSR != null) {
if (snapshotUUID != null) {
VDI snapshotVDI = getVDIbyUuid(snapshotUUID);
if (snapshotVDI != null) {
destroyVDI(snapshotVDI);
}
}
}
URI uri = null;
try {
uri = new URI(secondaryStoragePoolURL);
} catch (URISyntaxException e) {
details = "Error finding the secondary storage URL" + e.getMessage();
s_logger.error(details, e);
}
if (uri != null) {
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
if (secondaryStorageMountPath == null) {
details = "Couldn't delete snapshotsDir because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
} else {
details = deleteSnapshotsDir(dcId, accountId, volumeId, secondaryStorageMountPath);
success = (details != null && details.equals("1"));
if (success) {
s_logger.debug("Successfully deleted snapshotsDir for volume: " + volumeId);
}
}
}
return new Answer(cmd, success, details);
}
private VM getVM(Connection conn, String vmName) {
// Look up VMs with the specified name
Set<VM> vms;
try {
vms = VM.getByNameLabel(conn, vmName);
} catch (XenAPIException e) {
throw new CloudRuntimeException("Unable to get " + vmName + ": " + e.toString(), e);
} catch (Exception e) {
throw new CloudRuntimeException("Unable to get " + vmName + ": " + e.getMessage(), e);
}
// If there are no VMs, throw an exception
if (vms.size() == 0)
throw new CloudRuntimeException("VM with name: " + vmName + " does not exist.");
// If there is more than one VM, print a warning
if (vms.size() > 1)
s_logger.warn("Found " + vms.size() + " VMs with name: " + vmName);
// Return the first VM in the set
return vms.iterator().next();
}
protected VDI getIsoVDIByURL(Connection conn, String vmName, String isoURL) {
SR isoSR = null;
String mountpoint = null;
if (isoURL.startsWith("xs-tools")) {
try {
Set<VDI> vdis = VDI.getByNameLabel(conn, isoURL);
if (vdis.isEmpty()) {
throw new CloudRuntimeException("Could not find ISO with URL: " + isoURL);
}
return vdis.iterator().next();
} catch (XenAPIException e) {
throw new CloudRuntimeException("Unable to get pv iso: " + isoURL + " due to " + e.toString());
} catch (Exception e) {
throw new CloudRuntimeException("Unable to get pv iso: " + isoURL + " due to " + e.toString());
}
}
int index = isoURL.lastIndexOf("/");
mountpoint = isoURL.substring(0, index);
URI uri;
try {
uri = new URI(mountpoint);
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
throw new CloudRuntimeException("isoURL is wrong: " + isoURL);
}
isoSR = getISOSRbyVmName(vmName);
if (isoSR == null) {
isoSR = createIsoSRbyURI(uri, vmName, false);
}
String isoName = isoURL.substring(index + 1);
VDI isoVDI = getVDIbyLocationandSR(isoName, isoSR);
if (isoVDI != null) {
return isoVDI;
} else {
throw new CloudRuntimeException("Could not find ISO with URL: " + isoURL);
}
}
protected SR getStorageRepository(Connection conn, StoragePoolTO pool) {
Set<SR> srs;
try {
srs = SR.getByNameLabel(conn, pool.getUuid());
} catch (XenAPIException e) {
throw new CloudRuntimeException("Unable to get SR " + pool.getUuid() + " due to " + e.toString(), e);
} catch (Exception e) {
throw new CloudRuntimeException("Unable to get SR " + pool.getUuid() + " due to " + e.getMessage(), e);
}
if (srs.size() > 1) {
throw new CloudRuntimeException("More than one storage repository was found for pool with uuid: " + pool.getUuid());
} else if (srs.size() == 1) {
SR sr = srs.iterator().next();
if (s_logger.isDebugEnabled()) {
s_logger.debug("SR retrieved for " + pool.getId() + " is mapped to " + sr.toString());
}
if (checkSR(sr)) {
return sr;
}
throw new CloudRuntimeException("SR check failed for storage pool: " + pool.getUuid() + "on host:" + _host.uuid);
} else {
if (pool.getType() == StoragePoolType.NetworkFilesystem)
return getNfsSR(pool);
else if (pool.getType() == StoragePoolType.IscsiLUN)
return getIscsiSR(pool);
else
throw new CloudRuntimeException("The pool type: " + pool.getType().name() + " is not supported.");
}
}
protected Answer execute(final CheckConsoleProxyLoadCommand cmd) {
return executeProxyLoadScan(cmd, cmd.getProxyVmId(), cmd.getProxyVmName(), cmd.getProxyManagementIp(), cmd.getProxyCmdPort());
}
protected Answer execute(final WatchConsoleProxyLoadCommand cmd) {
return executeProxyLoadScan(cmd, cmd.getProxyVmId(), cmd.getProxyVmName(), cmd.getProxyManagementIp(), cmd.getProxyCmdPort());
}
protected CreateZoneVlanAnswer execute(CreateZoneVlanCommand cmd) {
Connection conn = getConnection();
try {
final DomainRouter router = cmd.getRouter();
VM vm = getVM(conn, router.getInstanceName());
// ToDo: Using vif 3 for now. Sync with multiple public VLAN feature
// to avoid conflict
createVIF(conn, vm, router.getGuestZoneMacAddress(), router.getZoneVlan(), 0, "3", true);
return new CreateZoneVlanAnswer(cmd);
} catch (XenAPIException e) {
String msg = "Exception caught while creating zone vlan: " + e.toString();
s_logger.warn(msg, e);
return new CreateZoneVlanAnswer(cmd, msg);
} catch (Exception e) {
String msg = "Exception caught while creating zone vlan: " + e.getMessage();
s_logger.warn(msg, e);
return new CreateZoneVlanAnswer(cmd, msg);
}
}
protected Answer executeProxyLoadScan(final Command cmd, final long proxyVmId, final String proxyVmName, final String proxyManagementIp, final int cmdPort) {
String result = null;
final StringBuffer sb = new StringBuffer();
sb.append("http://").append(proxyManagementIp).append(":" + cmdPort).append("/cmd/getstatus");
boolean success = true;
try {
final URL url = new URL(sb.toString());
final URLConnection conn = url.openConnection();
// setting TIMEOUTs to avoid possible waiting until death situations
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
final InputStream is = conn.getInputStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(is));
final StringBuilder sb2 = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null)
sb2.append(line + "\n");
result = sb2.toString();
} catch (final IOException e) {
success = false;
} finally {
try {
is.close();
} catch (final IOException e) {
s_logger.warn("Exception when closing , console proxy address : " + proxyManagementIp);
success = false;
}
}
} catch (final IOException e) {
s_logger.warn("Unable to open console proxy command port url, console proxy address : " + proxyManagementIp);
success = false;
}
return new ConsoleProxyLoadAnswer(cmd, proxyVmId, proxyVmName, success, result);
}
protected boolean createSecondaryStorageFolder(String remoteMountPath, String newFolder) {
String result = callHostPlugin("create_secondary_storage_folder", "remoteMountPath", remoteMountPath, "newFolder", newFolder);
return (result != null);
}
protected boolean deleteSecondaryStorageFolder(String remoteMountPath, String folder) {
String result = callHostPlugin("delete_secondary_storage_folder", "remoteMountPath", remoteMountPath, "folder", folder);
return (result != null);
}
protected boolean postCreatePrivateTemplate(String remoteTemplateMountPath, String templateDownloadFolder, String templateInstallFolder, String templateFilename,
String templateName, String templateDescription, String checksum, long virtualSize, long templateId) {
if (templateDescription == null) {
templateDescription = "";
}
if (checksum == null) {
checksum = "";
}
String result = callHostPluginWithTimeOut("post_create_private_template", 110*60, "remoteTemplateMountPath", remoteTemplateMountPath, "templateDownloadFolder", templateDownloadFolder,
"templateInstallFolder", templateInstallFolder, "templateFilename", templateFilename, "templateName", templateName, "templateDescription", templateDescription,
"checksum", checksum, "virtualSize", String.valueOf(virtualSize), "templateId", String.valueOf(templateId));
boolean success = false;
if (result != null && !result.isEmpty()) {
// Else, command threw an exception which has already been logged.
String[] tmp = result.split("#");
String status = tmp[0];
if (status != null && status.equalsIgnoreCase("1")) {
s_logger.debug("Successfully created template.properties file on secondary storage dir: " + templateInstallFolder);
success = true;
} else {
s_logger.warn("Could not create template.properties file on secondary storage dir: " + templateInstallFolder + " for templateId: " + templateId
+ ". Failed with status " + status);
}
}
return success;
}
// Each argument is put in a separate line for readability.
// Using more lines does not harm the environment.
protected String backupSnapshot(String primaryStorageSRUuid, Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath, String snapshotUuid,
String prevSnapshotUuid, String prevBackupUuid, Boolean isFirstSnapshotOfRootVolume, Boolean isISCSI) {
String backupSnapshotUuid = null;
if (prevSnapshotUuid == null) {
prevSnapshotUuid = "";
}
if (prevBackupUuid == null) {
prevBackupUuid = "";
}
// Each argument is put in a separate line for readability.
// Using more lines does not harm the environment.
String results = callHostPluginWithTimeOut("backupSnapshot", 110*60, "primaryStorageSRUuid", primaryStorageSRUuid, "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId",
volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath, "snapshotUuid", snapshotUuid, "prevSnapshotUuid", prevSnapshotUuid, "prevBackupUuid",
prevBackupUuid, "isFirstSnapshotOfRootVolume", isFirstSnapshotOfRootVolume.toString(), "isISCSI", isISCSI.toString());
if (results == null || results.isEmpty()) {
// errString is already logged.
return null;
}
String[] tmp = results.split("#");
String status = tmp[0];
backupSnapshotUuid = tmp[1];
// status == "1" if and only if backupSnapshotUuid != null
// So we don't rely on status value but return backupSnapshotUuid as an
// indicator of success.
String failureString = "Could not copy backupUuid: " + backupSnapshotUuid + " of volumeId: " + volumeId + " from primary storage " + primaryStorageSRUuid
+ " to secondary storage " + secondaryStorageMountPath;
if (status != null && status.equalsIgnoreCase("1") && backupSnapshotUuid != null) {
s_logger.debug("Successfully copied backupUuid: " + backupSnapshotUuid + " of volumeId: " + volumeId + " to secondary storage");
} else {
s_logger.debug(failureString + ". Failed with status: " + status);
}
return backupSnapshotUuid;
}
private boolean destroySnapshotOnPrimaryStorageExceptThis(String volumeUuid, String avoidSnapshotUuid){
try {
Connection conn = getConnection();
VDI volume = getVDIbyUuid(volumeUuid);
if (volume == null) {
throw new InternalErrorException("Could not destroy snapshot on volume " + volumeUuid + " due to can not find it");
}
Set<VDI> snapshots = volume.getSnapshots(conn);
for( VDI snapshot : snapshots ) {
try {
if(! snapshot.getUuid(conn).equals(avoidSnapshotUuid)) {
snapshot.destroy(conn);
}
} catch (Exception e) {
String msg = "Destroying snapshot: " + snapshot+ " on primary storage failed due to " + e.toString();
s_logger.warn(msg, e);
}
}
s_logger.debug("Successfully destroyed snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid );
return true;
} catch (XenAPIException e) {
String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
s_logger.error(msg, e);
} catch (Exception e) {
String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
s_logger.warn(msg, e);
}
return false;
}
protected boolean destroySnapshotOnPrimaryStorage(String snapshotUuid) {
// Precondition snapshotUuid != null
try {
Connection conn = getConnection();
VDI snapshot = getVDIbyUuid(snapshotUuid);
if (snapshot == null) {
throw new InternalErrorException("Could not destroy snapshot " + snapshotUuid + " because the snapshot VDI was null");
}
snapshot.destroy(conn);
s_logger.debug("Successfully destroyed snapshotUuid: " + snapshotUuid + " on primary storage");
return true;
} catch (XenAPIException e) {
String msg = "Destroy snapshotUuid: " + snapshotUuid + " on primary storage failed due to " + e.toString();
s_logger.error(msg, e);
} catch (Exception e) {
String msg = "Destroy snapshotUuid: " + snapshotUuid + " on primary storage failed due to " + e.getMessage();
s_logger.warn(msg, e);
}
return false;
}
protected String deleteSnapshotBackup(Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath, String backupUUID, String childUUID, String childChildUUID, Boolean isISCSI) {
// If anybody modifies the formatting below again, I'll skin them
String result = callHostPlugin("deleteSnapshotBackup", "backupUUID", backupUUID, "childUUID", childUUID, "childChildUUID", childChildUUID, "dcId", dcId.toString(), "accountId", accountId.toString(),
"volumeId", volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath, "isISCSI", isISCSI.toString());
return result;
}
protected String deleteSnapshotsDir(Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath) {
// If anybody modifies the formatting below again, I'll skin them
String result = callHostPlugin("deleteSnapshotsDir", "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId", volumeId.toString(),
"secondaryStorageMountPath", secondaryStorageMountPath);
return result;
}
// If anybody messes up with the formatting, I'll skin them
protected Pair<VHDInfo, String> createVHDFromSnapshot(String primaryStorageNameLabel, Long dcId, Long accountId, Long volumeId, String secondaryStoragePoolURL,
String backedUpSnapshotUuid, String templatePath, String templateDownloadFolder) throws XenAPIException, IOException, XmlRpcException, InternalErrorException,
URISyntaxException {
// Return values
String details = null;
Connection conn = getConnection();
SR primaryStorageSR = getSRByNameLabelandHost(primaryStorageNameLabel);
if (primaryStorageSR == null) {
throw new InternalErrorException("Could not create volume from snapshot " + "because the primary Storage SR could not be created from the name label: "
+ primaryStorageNameLabel);
}
Boolean isISCSI = SRType.LVMOISCSI.equals(primaryStorageSR.getType(conn));
// Get the absolute path of the template on the secondary storage.
URI uri = new URI(secondaryStoragePoolURL);
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
VHDInfo vhdInfo = null;
if (secondaryStorageMountPath == null) {
details = " because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
} else {
vhdInfo = createVHDFromSnapshot(dcId, accountId, volumeId, secondaryStorageMountPath, backedUpSnapshotUuid, templatePath, templateDownloadFolder, isISCSI);
if (vhdInfo == null) {
details = " because the vmops plugin on XenServer failed at some point";
}
}
return new Pair<VHDInfo, String>(vhdInfo, details);
}
protected VHDInfo createVHDFromSnapshot(Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath, String backedUpSnapshotUuid, String templatePath,
String templateDownloadFolder, Boolean isISCSI) {
String vdiUUID = null;
String failureString = "Could not create volume from " + backedUpSnapshotUuid;
templatePath = (templatePath == null) ? "" : templatePath;
String results = callHostPluginWithTimeOut("createVolumeFromSnapshot", 110*60, "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId", volumeId.toString(),
"secondaryStorageMountPath", secondaryStorageMountPath, "backedUpSnapshotUuid", backedUpSnapshotUuid, "templatePath", templatePath, "templateDownloadFolder",
templateDownloadFolder, "isISCSI", isISCSI.toString());
if (results == null || results.isEmpty()) {
// Command threw an exception which has already been logged.
return null;
}
String[] tmp = results.split("#");
String status = tmp[0];
vdiUUID = tmp[1];
Long virtualSizeInMB = 0L;
if (tmp.length == 3) {
virtualSizeInMB = Long.valueOf(tmp[2]);
}
// status == "1" if and only if vdiUUID != null
// So we don't rely on status value but return vdiUUID as an indicator
// of success.
if (status != null && status.equalsIgnoreCase("1") && vdiUUID != null) {
s_logger.debug("Successfully created vhd file with all data on secondary storage : " + vdiUUID);
} else {
s_logger.debug(failureString + ". Failed with status " + status + " with vdiUuid " + vdiUUID);
}
return new VHDInfo(vdiUUID, virtualSizeInMB * MB);
}
protected void syncDomRIPMap(String vm) {
// VM is a DomR, get its IP and add to domR-IP map
Connection conn = getConnection();
VM vm1 = getVM(conn, vm);
try {
String pvargs = vm1.getPVArgs(conn);
if (pvargs != null) {
pvargs = pvargs.replaceAll(" ", "\n");
Properties pvargsProps = new Properties();
pvargsProps.load(new StringReader(pvargs));
String ip = pvargsProps.getProperty("eth1ip");
if (ip != null) {
_domrIPMap.put(vm, ip);
}
}
} catch (BadServerResponse e) {
String msg = "Unable to update domR IP map due to: " + e.toString();
s_logger.warn(msg, e);
} catch (XenAPIException e) {
String msg = "Unable to update domR IP map due to: " + e.toString();
s_logger.warn(msg, e);
} catch (XmlRpcException e) {
String msg = "Unable to update domR IP map due to: " + e.toString();
s_logger.warn(msg, e);
} catch (IOException e) {
String msg = "Unable to update domR IP map due to: " + e.toString();
s_logger.warn(msg, e);
}
}
@Override
public boolean start() {
return true;
}
@Override
public boolean stop() {
disconnected();
return true;
}
@Override
public String getName() {
return _name;
}
@Override
public IAgentControl getAgentControl() {
return _agentControl;
}
@Override
public void setAgentControl(IAgentControl agentControl) {
_agentControl = agentControl;
}
private Answer execute(NetworkIngressRulesCmd cmd) {
if (s_logger.isTraceEnabled()) {
s_logger.trace("Sending network rules command to " + _host.ip);
}
if (!_canBridgeFirewall) {
s_logger.info("Host " + _host.ip + " cannot do bridge firewalling");
return new NetworkIngressRuleAnswer(cmd, false, "Host " + _host.ip + " cannot do bridge firewalling");
}
String result = callHostPlugin("network_rules",
"vmName", cmd.getVmName(),
"vmIP", cmd.getGuestIp(),
"vmMAC", cmd.getGuestMac(),
"vmID", Long.toString(cmd.getVmId()),
"signature", cmd.getSignature(),
"seqno", Long.toString(cmd.getSeqNum()),
"rules", cmd.stringifyRules());
if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
s_logger.warn("Failed to program network rules for vm " + cmd.getVmName());
return new NetworkIngressRuleAnswer(cmd, false, "programming network rules failed");
} else {
s_logger.info("Programmed network rules for vm " + cmd.getVmName() + " guestIp=" + cmd.getGuestIp() + ", numrules=" + cmd.getRuleSet().length);
return new NetworkIngressRuleAnswer(cmd);
}
}
private Answer execute(NetworkRulesSystemVmCommand cmd) {
boolean success = false;
if (_canBridgeFirewall) {
String result = callHostPlugin("default_network_rules_systemvm", "vmName", cmd.getVmName());
if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
s_logger.warn("Failed to program default system vm network rules for " + cmd.getVmName());
success = false;
} else {
s_logger.info("Programmed default system vm network rules for " + cmd.getVmName());
success = true;
}
} else {
s_logger.warn("Cannot program ingress rules for system vm -- bridge firewalling not supported on host");
}
return new Answer(cmd, success, "");
}
private Answer execute(PoolEjectCommand cmd) {
Connection conn = getConnection();
String hostuuid = cmd.getHostuuid();
try {
Map<Host, Host.Record> hostrs = Host.getAllRecords(conn);
boolean found = false;
for( Host.Record hr : hostrs.values() ) {
if( hr.uuid.equals(hostuuid)) {
found = true;
}
}
if( ! found) {
s_logger.debug("host " + hostuuid + " has already been ejected from pool " + _host.pool);
return new Answer(cmd);
}
Host host = Host.getByUuid(conn, hostuuid);
try {
Pool.eject(conn, host);
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
}
} catch (XenAPIException e) {
String msg = "Unable to eject host " + _host.uuid + " due to " + e.toString();
s_logger.warn(msg);
host.destroy(conn);
}
return new Answer(cmd);
} catch (XenAPIException e) {
String msg = "XenAPIException Unable to destroy host " + _host.uuid + " in xenserver database due to " + e.toString();
s_logger.warn(msg, e);
return new Answer(cmd, false, msg);
} catch (Exception e) {
String msg = "Exception Unable to destroy host " + _host.uuid + " in xenserver database due to " + e.getMessage();
s_logger.warn(msg, e);
return new Answer(cmd, false, msg);
}
}
protected class Nic {
public Network n;
public Network.Record nr;
public PIF p;
public PIF.Record pr;
public Nic(Network n, Network.Record nr, PIF p, PIF.Record pr) {
this.n = n;
this.nr = nr;
this.p = p;
this.pr = pr;
}
}
// A list of UUIDs that are gathered from the XenServer when
// the resource first connects to XenServer. These UUIDs do
// not change over time.
protected class XenServerHost {
public String uuid;
public String ip;
public String publicNetwork;
public String privateNetwork;
public String linkLocalNetwork;
public String storageNetwork1;
public String storageNetwork2;
public String guestNetwork;
public String guestPif;
public String publicPif;
public String privatePif;
public String storagePif1;
public String storagePif2;
public String pool;
}
class VHDInfo {
private final String uuid;
private final Long virtualSize;
public VHDInfo(String uuid, Long virtualSize) {
this.uuid = uuid;
this.virtualSize = virtualSize;
}
/**
* @return the uuid
*/
public String getUuid() {
return uuid;
}
/**
* @return the virtualSize
*/
public Long getVirtualSize() {
return virtualSize;
}
}
}