cloudstack/server/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java
anthony 017146f753 1 use 443 to connect xapi
2. update Java binding to xenserver-5.6.100-1.jar
2011-01-18 20:15:39 -08:00

495 lines
20 KiB
Java

/**
* 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.discoverer;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import com.cloud.agent.AgentManager;
import com.cloud.agent.Listener;
import com.cloud.agent.api.AgentControlAnswer;
import com.cloud.agent.api.AgentControlCommand;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.StartupCommand;
import com.cloud.alert.AlertManager;
import com.cloud.configuration.Config;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.exception.ConnectionException;
import com.cloud.exception.DiscoveryException;
import com.cloud.host.HostInfo;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.xen.resource.CitrixResourceBase;
import com.cloud.hypervisor.xen.resource.XcpServerResource;
import com.cloud.hypervisor.xen.resource.XenServer56FP1Resource;
import com.cloud.hypervisor.xen.resource.XenServerConnectionPool;
import com.cloud.hypervisor.xen.resource.XenServerResource;
import com.cloud.resource.Discoverer;
import com.cloud.resource.DiscovererBase;
import com.cloud.resource.ServerResource;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.TemplateType;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateHostDao;
import com.cloud.user.Account;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.Inject;
import com.cloud.utils.exception.CloudRuntimeException;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Host;
import com.xensource.xenapi.Pool;
import com.xensource.xenapi.Session;
import com.xensource.xenapi.Types.SessionAuthenticationFailed;
import com.xensource.xenapi.Types.XenAPIException;
@Local(value=Discoverer.class)
public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, Listener {
private static final Logger s_logger = Logger.getLogger(XcpServerDiscoverer.class);
protected String _publicNic;
protected String _privateNic;
protected String _storageNic1;
protected String _storageNic2;
protected int _wait;
protected XenServerConnectionPool _connPool;
protected String _increase;
protected boolean _checkHvm;
protected String _guestNic;
@Inject protected AlertManager _alertMgr;
@Inject protected AgentManager _agentMgr;
@Inject protected HostDao _hostDao;
@Inject VMTemplateDao _tmpltDao;
@Inject VMTemplateHostDao _vmTemplateHostDao;
@Inject ClusterDao _clusterDao;
protected XcpServerDiscoverer() {
}
@Override
public Map<? extends ServerResource, Map<String, String>> find(long dcId, Long podId, Long clusterId, URI url, String username, String password) throws DiscoveryException {
Map<CitrixResourceBase, Map<String, String>> resources = new HashMap<CitrixResourceBase, Map<String, String>>();
Connection conn = null;
if (!url.getScheme().equals("http")) {
String msg = "urlString is not http so we're not taking care of the discovery for this: " + url;
s_logger.debug(msg);
return null;
}
if (clusterId == null) {
String msg = "must specify cluster Id when add host";
s_logger.debug(msg);
throw new RuntimeException(msg);
}
if (podId == null) {
String msg = "must specify pod Id when add host";
s_logger.debug(msg);
throw new RuntimeException(msg);
}
ClusterVO cluster = _clusterDao.findById(clusterId);
if(cluster == null || (cluster.getHypervisorType() != HypervisorType.XenServer && cluster.getHypervisorType() != HypervisorType.Xen)) {
if(s_logger.isInfoEnabled())
s_logger.info("invalid cluster id or cluster is not for Xen/XenServer hypervisors");
return null;
}
try {
List<HostVO> eHosts = _hostDao.listByCluster(clusterId);
if( eHosts.size() > 0 ) {
HostVO eHost = eHosts.get(0);
_hostDao.loadDetails(eHost);
}
String hostname = url.getHost();
InetAddress ia = InetAddress.getByName(hostname);
String hostIp = ia.getHostAddress();
String masterIp = _connPool.getMasterIp(hostIp, username, password);
conn = _connPool.masterConnect(masterIp, username, password);
if (conn == null) {
String msg = "Unable to get a connection to " + url;
s_logger.debug(msg);
throw new DiscoveryException(msg);
}
Set<Pool> pools = Pool.getAll(conn);
Pool pool = pools.iterator().next();
Pool.Record pr = pool.getRecord(conn);
String poolUuid = pr.uuid;
Map<Host, Host.Record> hosts = Host.getAllRecords(conn);
/*set cluster hypervisor type to xenserver*/
ClusterVO clu = _clusterDao.findById(clusterId);
if ( clu.getGuid()== null ) {
clu.setGuid(poolUuid);
} else {
if( !clu.getGuid().equals(poolUuid)) {
if (hosts.size() == 1 ) {
if( !addHostsToPool(conn, hostIp, clusterId)){
String msg = "Unable to add host(" + hostIp + ") to cluster " + clusterId;
s_logger.warn(msg);
throw new DiscoveryException(msg);
}
} else {
String msg = "Host (" + hostIp + ") is already in pool(" + poolUuid +"), can to join pool(" + clu.getGuid() + ")";
s_logger.warn(msg);
throw new DiscoveryException(msg);
}
}
}
// can not use this conn after this point, because this host may join a pool, this conn is retired
if (conn != null) {
try{
Session.logout(conn);
} catch (Exception e ) {
}
conn.dispose();
conn = null;
}
poolUuid = clu.getGuid();
_clusterDao.update(clusterId, clu);
if (_checkHvm) {
for (Map.Entry<Host, Host.Record> entry : hosts.entrySet()) {
Host.Record record = entry.getValue();
boolean support_hvm = false;
for ( String capability : record.capabilities ) {
if(capability.contains("hvm")) {
support_hvm = true;
break;
}
}
if( !support_hvm ) {
String msg = "Unable to add host " + record.address + " because it doesn't support hvm";
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, msg, msg);
s_logger.debug(msg);
throw new RuntimeException(msg);
}
}
}
for (Map.Entry<Host, Host.Record> entry : hosts.entrySet()) {
Host.Record record = entry.getValue();
String hostAddr = record.address;
String prodVersion = record.softwareVersion.get("product_version");
String xenVersion = record.softwareVersion.get("xen");
String hostOS = record.softwareVersion.get("product_brand");
String hostOSVer = prodVersion;
String hostKernelVer = record.softwareVersion.get("linux");
if (_hostDao.findByGuid(record.uuid) != null) {
s_logger.debug("Skipping " + record.address + " because " + record.uuid + " is already in the database.");
continue;
}
CitrixResourceBase resource = createServerResource(dcId, podId, record);
s_logger.info("Found host " + record.hostname + " ip=" + record.address + " product version=" + prodVersion);
Map<String, String> details = new HashMap<String, String>();
Map<String, Object> params = new HashMap<String, Object>();
details.put("url", hostAddr);
details.put("username", username);
params.put("username", username);
details.put("password", password);
params.put("password", password);
params.put("zone", Long.toString(dcId));
params.put("guid", record.uuid);
params.put("pod", podId.toString());
params.put("cluster", clusterId.toString());
params.put("pool", poolUuid);
params.put("ipaddress", record.address);
if (_increase != null) {
params.put(Config.XenPreallocatedLunSizeRange.name(), _increase);
}
details.put(HostInfo.HOST_OS, hostOS);
details.put(HostInfo.HOST_OS_VERSION, hostOSVer);
details.put(HostInfo.HOST_OS_KERNEL_VERSION, hostKernelVer);
details.put(HostInfo.HYPERVISOR_VERSION, xenVersion);
if (!params.containsKey("public.network.device") && _publicNic != null) {
params.put("public.network.device", _publicNic);
details.put("public.network.device", _publicNic);
}
if (!params.containsKey("guest.network.device") && _guestNic != null) {
params.put("guest.network.device", _guestNic);
details.put("guest.network.device", _guestNic);
}
if (!params.containsKey("private.network.device") && _privateNic != null) {
params.put("private.network.device", _privateNic);
details.put("private.network.device", _privateNic);
}
if (!params.containsKey("storage.network.device1") && _storageNic1 != null) {
params.put("storage.network.device1", _storageNic1);
details.put("storage.network.device1", _storageNic1);
}
if (!params.containsKey("storage.network.device2") && _storageNic2 != null) {
params.put("storage.network.device2", _storageNic2);
details.put("storage.network.device2", _storageNic2);
}
params.put(Config.Wait.toString().toLowerCase(), Integer.toString(_wait));
details.put(Config.Wait.toString().toLowerCase(), Integer.toString(_wait));
try {
resource.configure("Xen Server", params);
} catch (ConfigurationException e) {
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + record.address, "Error is " + e.getMessage());
s_logger.warn("Unable to instantiate " + record.address, e);
continue;
}
resource.start();
resources.put(resource, details);
}
} catch (SessionAuthenticationFailed e) {
s_logger.warn("Authentication error", e);
return null;
} catch (XenAPIException e) {
s_logger.warn("XenAPI exception", e);
return null;
} catch (XmlRpcException e) {
s_logger.warn("Xml Rpc Exception", e);
return null;
} catch (UnknownHostException e) {
s_logger.warn("Unable to resolve the host name", e);
return null;
} catch (Exception e) {
s_logger.debug("other exceptions: " + e.toString(), e);
return null;
}
return resources;
}
String getPoolUuid(Connection conn) throws XenAPIException, XmlRpcException {
Map<Pool, Pool.Record> pools = Pool.getAllRecords(conn);
assert pools.size() == 1 : "Pools size is " + pools.size();
return pools.values().iterator().next().uuid;
}
protected void addSamePool(Connection conn, Map<CitrixResourceBase, Map<String, String>> resources) throws XenAPIException, XmlRpcException {
Map<Pool, Pool.Record> hps = Pool.getAllRecords(conn);
assert (hps.size() == 1) : "How can it be more than one but it's actually " + hps.size();
// This is the pool.
String poolUuid = hps.values().iterator().next().uuid;
for (Map<String, String> details : resources.values()) {
details.put("pool", poolUuid);
}
}
protected boolean addHostsToPool(Connection conn, String hostIp, Long clusterId) throws XenAPIException, XmlRpcException, DiscoveryException {
List<HostVO> hosts;
hosts = _hostDao.listByCluster(clusterId);
String masterIp = null;
String username = null;
String password = null;
for (HostVO host : hosts) {
_hostDao.loadDetails(host);
username = host.getDetail("username");
password = host.getDetail("password");
String address = host.getPrivateIpAddress();
Connection hostConn = _connPool.slaveConnect(address, username, password);
if (hostConn == null) {
continue;
}
try {
Set<Pool> pools = Pool.getAll(hostConn);
Pool pool = pools.iterator().next();
masterIp = pool.getMaster(hostConn).getAddress(hostConn);
break;
} catch (Exception e ) {
s_logger.warn("Can not get master ip address from host " + address);
} finally {
try{
Session.localLogout(hostConn);
} catch (Exception e ) {
}
hostConn.dispose();
hostConn = null;
}
}
if (masterIp == null) {
s_logger.warn("Unable to reach the pool master of the existing cluster");
throw new CloudRuntimeException("Unable to reach the pool master of the existing cluster");
}
if( !_connPool.joinPool(conn, hostIp, masterIp, username, password) ){
s_logger.warn("Unable to join the pool");
throw new DiscoveryException("Unable to join the pool");
}
return true;
}
protected CitrixResourceBase createServerResource(long dcId, Long podId, Host.Record record) {
String prodBrand = record.softwareVersion.get("product_brand").trim();
String prodVersion = record.softwareVersion.get("product_version").trim();
if(prodBrand.equals("XenCloudPlatform") && prodVersion.equals("0.1.1"))
return new XcpServerResource();
if(prodBrand.equals("XenServer") && prodVersion.equals("5.6.0"))
return new XenServerResource();
if(prodBrand.equals("XenServer") && prodVersion.equals("5.6.100"))
return new XenServer56FP1Resource();
String msg = "Only support XCP 0.1.1, XenServer 5.6 and XenServer 5.6 FP1 , but this one is " + prodBrand + " " + prodVersion;
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, msg, msg);
s_logger.debug(msg);
throw new RuntimeException(msg);
}
protected void serverConfig() {
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
serverConfig();
_publicNic = _params.get(Config.XenPublicNetwork.key());
_privateNic = _params.get(Config.XenPrivateNetwork.key());
_storageNic1 = _params.get(Config.XenStorageNetwork1.key());
_storageNic2 = _params.get(Config.XenStorageNetwork2.key());
_guestNic = _params.get(Config.XenGuestNetwork.key());
_increase = _params.get(Config.XenPreallocatedLunSizeRange.key());
String value = _params.get(Config.Wait.toString());
_wait = NumbersUtil.parseInt(value, Integer.parseInt(Config.Wait.getDefaultValue()));
value = _params.get(Config.XenSetupMultipath.key());
Boolean.parseBoolean(value);
value = _params.get("xen.check.hvm");
_checkHvm = value == null ? true : Boolean.parseBoolean(value);
_connPool = XenServerConnectionPool.getInstance();
_agentMgr.registerForHostEvents(this, true, false, true);
createXsToolsISO();
return true;
}
@Override
public boolean matchHypervisor(String hypervisor) {
if(hypervisor == null)
return true;
return Hypervisor.HypervisorType.XenServer.toString().equalsIgnoreCase(hypervisor);
}
@Override
public Hypervisor.HypervisorType getHypervisorType() {
return Hypervisor.HypervisorType.XenServer;
}
@Override
public void postDiscovery(List<HostVO> hosts, long msId) throws DiscoveryException{
//do nothing
}
@Override
public int getTimeout() {
return 0;
}
@Override
public boolean isRecurring() {
return false;
}
@Override
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
return false;
}
@Override
public boolean processCommands(long agentId, long seq, Command[] commands) {
return false;
}
private void createXsToolsISO() {
String isoName = "xs-tools.iso";
VMTemplateVO tmplt = _tmpltDao.findByTemplateName(isoName);
Long id;
if (tmplt == null) {
id = _tmpltDao.getNextInSequence(Long.class, "id");
VMTemplateVO template = new VMTemplateVO(id, isoName, isoName, ImageFormat.ISO, true, true,
TemplateType.PERHOST, null, null, true, 64,
Account.ACCOUNT_ID_SYSTEM, null, "xen-pv-drv-iso", false, 1, false, HypervisorType.None);
_tmpltDao.persist(template);
} else {
id = tmplt.getId();
tmplt.setTemplateType(TemplateType.PERHOST);
tmplt.setUrl(null);
_tmpltDao.update(id, tmplt);
}
}
@Override
public void processConnect(HostVO agent, StartupCommand cmd) throws ConnectionException {
}
@Override
public AgentControlAnswer processControlCommand(long agentId, AgentControlCommand cmd) {
return null;
}
@Override
public boolean processDisconnect(long agentId, Status state) {
return false;
}
@Override
public boolean processTimeout(long agentId, long seq) {
return false;
}
}