// Copyright 2012 Citrix Systems, Inc. Licensed under the
// Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. Citrix Systems, Inc.
// reserves all rights not expressly granted by the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Automatically generated by addcopyright.py at 04/03/2012
package com.cloud.hypervisor.xen.resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.SocketException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClientException;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.exception.CloudRuntimeException;
import com.xensource.xenapi.APIVersion;
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;
import com.xensource.xenapi.Types.BadServerResponse;
import com.xensource.xenapi.Types.UuidInvalid;
import com.xensource.xenapi.Types.XenAPIException;
public class XenServerConnectionPool {
private static final Logger s_logger = Logger.getLogger(XenServerConnectionPool.class);
protected HashMap<String /* poolUuid */, XenServerConnection> _conns = new HashMap<String, XenServerConnection>();
protected int _retries;
protected int _interval;
protected static boolean s_managePool = true;
protected static long s_sleepOnError = 10 * 1000; // in ms
static {
File file = PropertiesUtil.findConfigFile("environment.properties");
if (file == null) {
s_logger.debug("Unable to find environment.properties");
} else {
FileInputStream finputstream;
try {
finputstream = new FileInputStream(file);
final Properties props = new Properties();
props.load(finputstream);
finputstream.close();
String search = props.getProperty("manage.xenserver.pool.master");
if (search != null) {
s_managePool = Boolean.parseBoolean(search);
}
search = props.getProperty("sleep.interval.on.error");
if (search != null) {
s_sleepOnError = NumbersUtil.parseInterval(search, 10) * 1000;
}
s_logger.info("XenServer Connection Pool Configs: manage.xenserver.pool.master=" + s_managePool + "; sleep.interval.on.error=" + s_sleepOnError);
} catch (FileNotFoundException e) {
s_logger.debug("File is not found", e);
} catch (IOException e) {
s_logger.debug("IO Exception while reading file", e);
}
}
try {
javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager tm = new TrustAllManager();
trustAllCerts[0] = tm;
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, null);
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier hv = new HostnameVerifier() {
@Override
public boolean verify(String hostName, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
} catch (Exception e) {
}
}
protected XenServerConnectionPool() {
_retries = 3;
_interval = 3;
}
private void addConnect(String poolUuid, XenServerConnection conn){
if( poolUuid == null ) return;
if (s_logger.isDebugEnabled()) {
s_logger.debug("Add master connection through " + conn.getIp() + " for pool(" + conn.getPoolUuid() + ")");
}
synchronized (_conns) {
_conns.put(poolUuid, conn);
}
}
private XenServerConnection getConnect(String poolUuid) {
if( poolUuid == null ) return null;
synchronized (_conns) {
return _conns.get(poolUuid);
}
}
private void removeConnect(String poolUuid) {
if( poolUuid == null ) {
return;
}
XenServerConnection conn = null;
synchronized (_conns) {
conn = _conns.remove(poolUuid);
}
if ( conn != null ) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Remove master connection through " + conn.getIp() + " for pool(" + conn.getPoolUuid() + ")");
}
}
}
static void forceSleep(long sec) {
long firetime = System.currentTimeMillis() + (sec * 1000);
long msec = sec * 1000;
while (true) {
if (msec < 100)
break;
try {
Thread.sleep(msec);
return;
} catch (InterruptedException e) {
msec = firetime - System.currentTimeMillis();
}
}
}
public boolean joinPool(Connection conn, String hostIp, String masterIp, String username, Queue<String> password) {
try {
join(conn, masterIp, username, password);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Host(" + hostIp + ") Join the pool at " + masterIp);
}
try {
// slave will restart xapi in 10 sec
Thread.sleep(10000);
} catch (InterruptedException e) {
}
for (int i = 0 ; i < 15; i++) {
Connection slaveConn = null;
Session slaveSession = null;
try {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Logging on as the slave to " + hostIp);
}
slaveConn = new Connection(getURL(hostIp), 10);
slaveSession = slaveLocalLoginWithPassword(slaveConn, username, password);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Slave logon successful. session= " + slaveSession);
}
Pool.Record pr = getPoolRecord(slaveConn);
Host master = pr.master;
String ma = master.getAddress(slaveConn);
if (ma.trim().equals(masterIp.trim())) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Host(" + hostIp + ") Joined the pool at " + masterIp);
}
return true;
}
} catch (Exception e) {
} finally {
if (slaveSession != null) {
try {
Session.logout(slaveConn);
} catch (Exception e) {
}
slaveConn.dispose();
}
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
} catch (Exception e) {
String msg = "Catch " + e.getClass().getName() + " Unable to allow host " + hostIp + " to join pool " + masterIp + " due to " + e.toString();
s_logger.warn(msg, e);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Host(" + hostIp + ") unable to Join the pool at " + masterIp);
}
return false;
}
public void switchMaster(String slaveIp, String poolUuid,
Connection conn, Host host, String username, Queue<String> password,
int wait) throws XmlRpcException, XenAPIException {
synchronized (poolUuid.intern()) {
String masterIp = host.getAddress(conn);
s_logger.debug("Designating the new master to " + masterIp);
Pool.designateNewMaster(conn, host);
Connection slaveConn = null;
Connection masterConn = null;
int retry = 30;
for (int i = 0; i < retry; i++) {
forceSleep(5);
try {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Logging on as the slave to " + slaveIp);
}
slaveConn = null;
masterConn = null;
Session slaveSession = null;
slaveConn = new Connection(getURL(slaveIp), 10);
slaveSession = slaveLocalLoginWithPassword(slaveConn, username, password);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Slave logon successful. session= "
+ slaveSession);
}
Pool.Record pr = getPoolRecord(slaveConn);
Host master = pr.master;
String ma = master.getAddress(slaveConn);
if (!ma.trim().equals(masterIp.trim())) {
continue;
}
s_logger.debug("Logging on as the master to " + masterIp);
masterConn = new Connection(getURL(masterIp), 10);
loginWithPassword(masterConn, username, password, APIVersion.latest().toString());
removeConnect(poolUuid);
ensurePoolIntegrity(masterConn, masterIp, username, password, wait);
return;
} catch (Types.HostIsSlave e) {
s_logger.debug("HostIsSlaveException: Still waiting for the conversion to the master");
} catch (XmlRpcException e) {
s_logger.debug("XmlRpcException: Still waiting for the conversion to the master " + e.getMessage());
} catch (Exception e) {
s_logger.debug("Exception: Still waiting for the conversion to the master" + e.getMessage());
} finally {
if (masterConn != null) {
try {
Session.logout(masterConn);
} catch (Exception e) {
s_logger.debug("Unable to log out of session: "
+ e.getMessage());
}
masterConn.dispose();
masterConn = null;
}
localLogout(slaveConn);
slaveConn = null;
}
}
throw new CloudRuntimeException(
"Unable to logon to the new master after " + retry + " retries");
}
}
private void localLogout(Connection conn) {
if ( conn == null )
return;
try {
if( s_logger.isTraceEnabled()) {
s_logger.trace("Logging out of the session "
+ conn.getSessionReference());
}
Session.localLogout(conn);
} catch (Exception e) {
s_logger.debug("localLogout has problem " + e.getMessage());
} finally {
conn.dispose();
conn = null;
}
}
public Connection slaveConnect(String ip, String username, Queue<String> password) {
Connection conn = null;
try{
conn = new Connection(getURL(ip), 10);
slaveLocalLoginWithPassword(conn, username, password);
return conn;
}catch ( Exception e){
s_logger.debug("Failed to slave local login to " + ip);
}
return null;
}
public Connection masterConnect(String ip, String username, Queue<String> password) {
Connection conn = null;
try{
conn = new Connection(getURL(ip), 10);
s_logger.debug("Logging on as the master to " + ip);
loginWithPassword(conn, username, password, APIVersion.latest().toString());
return conn;
}catch ( Exception e){
s_logger.debug("Failed to slave local login to " + ip);
}
throw new RuntimeException("can not log in to master " + ip);
}
public String getMasterIp(String ip, String username, Queue<String> password) throws XenAPIException {
Connection slaveConn = null;
try{
slaveConn = new Connection(getURL(ip), 10);
slaveLocalLoginWithPassword(slaveConn, username, password);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Slave logon to " + ip);
}
String masterIp = null;
Pool.Record pr = getPoolRecord(slaveConn);
Host master = pr.master;
masterIp = master.getAddress(slaveConn);
return masterIp;
}catch(Types.SessionAuthenticationFailed e){
s_logger.debug("Failed to slave local login to " + ip + " due to " + e.toString());
throw e;
}catch ( Exception e){
s_logger.debug("Failed to slave local login to " + ip + " due to " + e.toString());
} finally {
localLogout(slaveConn);
slaveConn = null;
}
throw new RuntimeException("can not get master ip");
}
void PoolEmergencyTransitionToMaster(String slaveIp, String username, Queue<String> password) {
if (!s_managePool) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Don't manage pool on error so sleeping for " + s_sleepOnError);
try {
Thread.sleep(s_sleepOnError);
} catch (InterruptedException ie) {
}
}
return;
}
Connection slaveConn = null;
Connection c = null;
try{
s_logger.debug("Trying to transition master to " + slaveIp);
slaveConn = new Connection(getURL(slaveIp), 10);
slaveLocalLoginWithPassword(slaveConn, username, password);
Pool.emergencyTransitionToMaster(slaveConn);
// restart xapi in 10 sec
forceSleep(10);
// check if the master of this host is set correctly.
c = new Connection(getURL(slaveIp), 10);
for (int i = 0; i < 30; i++) {
try {
loginWithPassword(c, username, password, APIVersion.latest().toString());
s_logger.debug("Succeeded to transition master to " + slaveIp);
return;
} catch (Types.HostIsSlave e) {
s_logger.debug("HostIsSlave: Still waiting for the conversion to the master " + slaveIp);
} catch (Exception e) {
s_logger.debug("Exception: Still waiting for the conversion to the master");
}
forceSleep(2);
}
throw new RuntimeException("EmergencyTransitionToMaster failed after retry 30 times");
} catch (Exception e) {
throw new RuntimeException("EmergencyTransitionToMaster failed due to " + e.getMessage());
} finally {
localLogout(slaveConn);
slaveConn = null;
if(c != null) {
try {
Session.logout(c);
c.dispose();
} catch (Exception e) {
}
}
}
}
private void PoolEmergencyResetMaster(String slaveIp, String masterIp, String username, Queue<String> password) {
if (!s_managePool) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Don't manage pool on error so sleeping for " + s_sleepOnError);
try {
Thread.sleep(s_sleepOnError);
} catch (InterruptedException ie) {
}
}
return;
}
Connection slaveConn = null;
try {
s_logger.debug("Trying to reset master of slave " + slaveIp
+ " to " + masterIp);
slaveConn = new Connection(getURL(slaveIp), 10);
slaveLocalLoginWithPassword(slaveConn, username, password);
Pool.emergencyResetMaster(slaveConn, masterIp);
forceSleep(10);
for (int i = 0; i < 30; i++) {
try {
slaveLocalLoginWithPassword(slaveConn, username, password);
Pool.Record pr = getPoolRecord(slaveConn);
String mIp = pr.master.getAddress(slaveConn);
if (mIp.trim().equals(masterIp.trim())) {
s_logger.debug("Succeeded to reset master of slave " + slaveIp + " to " + masterIp);
return;
}
} catch (Exception e) {
} finally {
localLogout(slaveConn);
slaveConn = null;
}
// wait 2 second
forceSleep(2);
}
throw new CloudRuntimeException("Unable to reset master of slave " + slaveIp
+ " to " + masterIp + "after 30 retry");
} catch (Exception e) {
throw new CloudRuntimeException("Unable to reset master of slave " + slaveIp
+ " to " + masterIp + " due to " + e.toString());
} finally {
localLogout(slaveConn);
slaveConn = null;
}
}
protected void ensurePoolIntegrity(Connection conn,
String masterIp, String username, Queue<String> password, int wait) {
try {
// try recoverSlave first
Set<Host> rcSlaves = Pool.recoverSlaves(conn);
// wait 10 second
forceSleep(10);
for(Host slave : rcSlaves ) {
for (int i = 0; i < 30; i++) {
Connection slaveConn = null;
try {
String slaveIp = slave.getAddress(conn);
s_logger.debug("Logging on as the slave to " + slaveIp);
slaveConn = new Connection(getURL(slaveIp), 10);
slaveLocalLoginWithPassword(slaveConn, username, password);
Pool.Record pr = getPoolRecord(slaveConn);
String mIp = pr.master.getAddress(slaveConn);
if (mIp.trim().equals(masterIp.trim())) {
break;
}
} catch (Exception e) {
} finally {
localLogout(slaveConn);
slaveConn = null;
}
// wait 2 second
forceSleep(2);
}
}
// then try emergency reset master
Set<Host> slaves = Host.getAll(conn);
for (Host slave : slaves) {
String slaveIp = slave.getAddress(conn);
Connection slaveConn = null;
try {
s_logger.debug("Logging on as the slave to " + slaveIp);
slaveConn = new Connection(getURL(slaveIp), 10);
slaveLocalLoginWithPassword(slaveConn, username, password);
Pool.Record slavePoolr = getPoolRecord(slaveConn);
String ip = slavePoolr.master.getAddress(slaveConn);
if (!masterIp.trim().equals(ip.trim())) {
PoolEmergencyResetMaster(slaveIp, masterIp, username, password);
}
} catch (Exception e) {
s_logger.debug("Unable to login to slave " + slaveIp + " error " + e.getMessage());
} finally {
localLogout(slaveConn);
slaveConn = null;
}
}
} catch (Exception e) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Catch " + e.getClass().getName() + " due to " + e.toString());
}
}
}
public URL getURL(String ip){
try {
return new URL("https://" + ip);
} catch (Exception e) {
String msg = "Unable to convert IP " + ip + " to URL due to " + e.toString();
if (s_logger.isDebugEnabled()) {
s_logger.debug(msg);
}
throw new CloudRuntimeException(msg, e);
}
}
public Connection connect(String hostUuid, String poolUuid, String ipAddress,
String username, Queue<String> password, int wait) {
XenServerConnection mConn = null;
Connection sConn = null;
String masterIp = null;
if (hostUuid == null || poolUuid == null || ipAddress == null || username == null || password == null) {
String msg = "Connect some parameter are null hostUuid:" + hostUuid + " ,poolUuid:" + poolUuid
+ " ,ipAddress:" + ipAddress;
s_logger.debug(msg);
throw new CloudRuntimeException(msg);
}
Host host = null;
synchronized (poolUuid.intern()) {
// Let's see if it is an existing connection.
mConn = getConnect(poolUuid);
if (mConn != null){
try{
host = Host.getByUuid(mConn, hostUuid);
} catch (Types.SessionInvalid e) {
s_logger.debug("Session thgrough ip " + mConn.getIp() + " is invalid for pool(" + poolUuid + ") due to " + e.toString());
try {
loginWithPassword(mConn, mConn.getUsername(), mConn.getPassword(), APIVersion.latest().toString());
} catch (Exception e1) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("connect through IP(" + mConn.getIp() + " for pool(" + poolUuid + ") is broken due to " + e.toString());
}
removeConnect(poolUuid);
mConn = null;
}
} catch (UuidInvalid e) {
String msg = "Host(" + hostUuid + ") doesn't belong to pool(" + poolUuid + "), please execute 'xe pool-join master-address=" + mConn.getIp()
+ " master-username=" + mConn.getUsername() + " master-password=" + mConn.getPassword();
if (s_logger.isDebugEnabled()) {
s_logger.debug(msg);
}
throw new CloudRuntimeException(msg, e);
} catch (Exception e) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("connect through IP(" + mConn.getIp() + " for pool(" + poolUuid + ") is broken due to " + e.toString());
}
removeConnect(poolUuid);
mConn = null;
}
}
if ( mConn == null ) {
try {
try {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Logging on as the slave to " + ipAddress);
}
sConn = new Connection(getURL(ipAddress), 5);
slaveLocalLoginWithPassword(sConn, username, password);
} catch (Exception e){
String msg = "Unable to create slave connection to host(" + hostUuid +") due to " + e.toString();
if (s_logger.isDebugEnabled()) {
s_logger.debug(msg);
}
throw new CloudRuntimeException(msg, e);
}
Pool.Record pr = null;
try {
pr = getPoolRecord(sConn);
} catch (Exception e) {
PoolEmergencyTransitionToMaster(ipAddress, username, password);
mConn = new XenServerConnection(getURL(ipAddress), ipAddress, username, password, _retries, _interval, wait);
try {
loginWithPassword(mConn, username, password, APIVersion.latest().toString());
pr = getPoolRecord(mConn);
} catch (Exception e1) {
String msg = "Unable to create master connection to host(" + hostUuid +") after transition it to master, due to " + e1.toString();
if (s_logger.isDebugEnabled()) {
s_logger.debug(msg);
}
throw new CloudRuntimeException(msg, e1);
}
if ( !pr.uuid.equals(poolUuid) ) {
String msg = "host(" + hostUuid +") should be in pool(" + poolUuid + "), but it is actually in pool(" + pr.uuid + ")";
if (s_logger.isDebugEnabled()) {
s_logger.debug(msg);
}
throw new CloudRuntimeException(msg);
} else {
if (s_managePool) {
ensurePoolIntegrity(mConn, ipAddress, username, password, wait);
}
addConnect(poolUuid, mConn);
return mConn;
}
}
if ( !pr.uuid.equals(poolUuid) ) {
String msg = "host(" + hostUuid +") should be in pool(" + poolUuid + "), but it is actually in pool(" + pr.uuid + ")";
if (s_logger.isDebugEnabled()) {
s_logger.debug(msg);
}
throw new CloudRuntimeException(msg);
}
try {
masterIp = pr.master.getAddress(sConn);
mConn = new XenServerConnection(getURL(masterIp), masterIp, username, password, _retries, _interval, wait);
loginWithPassword(mConn, username, password, APIVersion.latest().toString());
addConnect(poolUuid, mConn);
return mConn;
} catch (Exception e) {
String msg = "Unable to logon in " + masterIp + " as master in pool(" + poolUuid + ")";
if (s_logger.isDebugEnabled()) {
s_logger.debug(msg);
}
throw new CloudRuntimeException(msg);
}
} finally {
localLogout(sConn);
sConn = null;
}
}
}
if ( mConn != null ) {
if (s_managePool) {
try {
Map<String, String> args = new HashMap<String, String>();
host.callPlugin(mConn, "echo", "main", args);
} catch (Types.SessionInvalid e) {
if (s_logger.isDebugEnabled()) {
String msg = "Catch Exception: " + e.getClass().getName() + " Can't connect host " + ipAddress + " due to " + e.toString();
s_logger.debug(msg);
}
PoolEmergencyResetMaster(ipAddress, mConn.getIp(), mConn.getUsername(), mConn.getPassword());
} catch (Types.CannotContactHost e ) {
if (s_logger.isDebugEnabled()) {
String msg = "Catch Exception: " + e.getClass().getName() + " Can't connect host " + ipAddress + " due to " + e.toString();
s_logger.debug(msg);
}
PoolEmergencyResetMaster(ipAddress, mConn.getIp(), mConn.getUsername(), mConn.getPassword());
} catch (Types.HostOffline e ) {
if (s_logger.isDebugEnabled()) {
String msg = "Catch Exception: " + e.getClass().getName() + " Host is offline " + ipAddress + " due to " + e.toString();
s_logger.debug(msg);
}
PoolEmergencyResetMaster(ipAddress, mConn.getIp(), mConn.getUsername(), mConn.getPassword());
} catch (Types.HostNotLive e ) {
String msg = "Catch Exception: " + e.getClass().getName() + " Host Not Live " + ipAddress + " due to " + e.toString();
if (s_logger.isDebugEnabled()) {
s_logger.debug(msg);
}
PoolEmergencyResetMaster(ipAddress, mConn.getIp(), mConn.getUsername(), mConn.getPassword());
} catch (Exception e) {
String msg = "Echo test failed on host " + hostUuid + " IP " + ipAddress;
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg, e);
}
}
}
return mConn;
}
protected Session slaveLocalLoginWithPassword(Connection conn, String username, Queue<String> password) throws
BadServerResponse,
XenAPIException,
XmlRpcException {
Session s = null;
boolean logged_in=false;
Exception ex = null;
while (!logged_in){
try {
s = Session.slaveLocalLoginWithPassword(conn, username, password.peek());
logged_in=true;
} catch (BadServerResponse e) {
logged_in=false; ex = e;
} catch (XenAPIException e) {
logged_in=false; ex = e;
} catch (XmlRpcException e) {
logged_in=false; ex = e;
}
if (logged_in && conn != null){
break;
}
else {
if (password.size() > 1){
password.remove();
continue;
}
else {
// the last password did not work leave it and flag error
if (ex instanceof BadServerResponse){
throw (BadServerResponse)ex;
}
else if (ex instanceof XmlRpcException){
throw (XmlRpcException)ex;
}
else if (ex instanceof Types.SessionAuthenticationFailed){
throw (Types.SessionAuthenticationFailed)ex;
}
else if (ex instanceof XenAPIException){
throw (XenAPIException)ex;
}
break;
}
}
}
return s;
}
protected Session loginWithPassword(Connection conn, String username, Queue<String> password, String version)throws
BadServerResponse,
XenAPIException,
XmlRpcException {
Session s = null;
boolean logged_in=false;
Exception ex = null;
while (!logged_in){
try {
s = Session.loginWithPassword(conn, username, password.peek(), APIVersion.latest().toString());
logged_in=true;
} catch (BadServerResponse e) {
logged_in=false; ex = e;
} catch (XenAPIException e) {
logged_in=false; ex = e;
} catch (XmlRpcException e) {
logged_in=false; ex = e;
}
if (logged_in && conn != null){
break;
}
else {
if (password.size() > 1){
password.remove();
continue;
}
else {
// the last password did not work leave it and flag error
if (ex instanceof BadServerResponse){
throw (BadServerResponse)ex;
}
else if (ex instanceof XmlRpcException){
throw (XmlRpcException)ex;
}
else if (ex instanceof Types.SessionAuthenticationFailed){
throw (Types.SessionAuthenticationFailed)ex;
}
else if (ex instanceof XenAPIException){
throw (XenAPIException)ex;
}
}
}
}
return s;
}
protected void join(Connection conn, String masterIp, String username, Queue<String> password) throws
BadServerResponse,
XenAPIException,
XmlRpcException,
Types.JoiningHostCannotContainSharedSrs {
boolean logged_in=false;
Exception ex = null;
while (!logged_in){
try {
Pool.join(conn, masterIp, username, password.peek());
logged_in=true;
} catch (BadServerResponse e) {
logged_in=false; ex = e;
} catch (XenAPIException e) {
logged_in=false; ex = e;
} catch (XmlRpcException e) {
logged_in=false; ex = e;
}
if (logged_in && conn != null){
break;
}
else {
if (password.size() > 1){
password.remove();
continue;
}
else {
// the last password did not work leave it and flag error
if (ex instanceof BadServerResponse){
throw (BadServerResponse)ex;
}
else if (ex instanceof XmlRpcException){
throw (XmlRpcException)ex;
}
else if (ex instanceof Types.SessionAuthenticationFailed){
throw (Types.SessionAuthenticationFailed)ex;
}
else if (ex instanceof XenAPIException){
throw (XenAPIException)ex;
}
break;
}
}
}
}
static public Pool.Record getPoolRecord(Connection conn)
throws XmlRpcException, XenAPIException {
Map<Pool, Pool.Record> pools = Pool.getAllRecords(conn);
assert pools.size() == 1 : "Pool size is not one....hmmm....wth? "
+ pools.size();
return pools.values().iterator().next();
}
private static final XenServerConnectionPool s_instance = new XenServerConnectionPool();
public static XenServerConnectionPool getInstance() {
return s_instance;
}
public class XenServerConnection extends Connection {
long _interval;
int _retries;
String _ip;
String _username;
Queue<String> _password;
String _poolUuid;
public XenServerConnection(URL url, String ip, String username, Queue<String> password,
int retries, int interval, int wait) {
super(url, wait);
_ip = ip;
_retries = retries;
_username = username;
_password = password;
_interval = (long) interval * 1000;
}
public String getPoolUuid() {
return _poolUuid;
}
public String getUsername() {
return _username;
}
public Queue<String> getPassword() {
return _password;
}
public String getIp() {
return _ip;
}
@Override
protected Map dispatch(String method_call, Object[] method_params) throws XmlRpcException, XenAPIException {
if (method_call.equals("session.local_logout")
|| method_call.equals("session.slave_local_login_with_password")
|| method_call.equals("session.logout")) {
return super.dispatch(method_call, method_params);
}
if (method_call.equals("session.login_with_password")) {
int retries = 0;
while (retries++ < _retries) {
try {
return super.dispatch(method_call, method_params);
} catch (XmlRpcException e) {
Throwable cause = e.getCause();
if (cause == null
|| !(cause instanceof SocketException)) {
throw e;
}
if (retries >= _retries) {
throw e;
}
s_logger.debug("Unable to login...retrying " + retries);
}
try {
Thread.sleep(_interval);
} catch (InterruptedException e) {
s_logger
.debug("Man....I was just getting comfortable there....who woke me up?");
}
}
} else {
int retries = 0;
while (retries++ < _retries) {
try {
return super.dispatch(method_call, method_params);
} catch (Types.SessionInvalid e) {
s_logger.debug("Session is invalid for method: " + method_call + " due to " + e.getMessage() + ". Reconnecting...retry="
+ retries);
if (retries >= _retries) {
removeConnect(_poolUuid);
throw e;
}
loginWithPassword(this, _username, _password, APIVersion.latest().toString());
method_params[0] = getSessionReference();
} catch (XmlRpcClientException e) {
s_logger.debug("XmlRpcClientException for method: " + method_call + " due to " + e.getMessage());
removeConnect(_poolUuid);
throw e;
} catch (XmlRpcException e) {
s_logger.debug("XmlRpcException for method: " + method_call + " due to " + e.getMessage() + ". Reconnecting...retry="
+ retries);
if (retries >= _retries) {
removeConnect(_poolUuid);
throw e;
}
Throwable cause = e.getCause();
if (cause == null || !(cause instanceof SocketException)) {
removeConnect(_poolUuid);
throw e;
}
} catch (Types.HostIsSlave e) {
s_logger.debug("HostIsSlave Exception for method: " + method_call + " due to " + e.getMessage() + ". Reconnecting...retry="
+ retries);
removeConnect(_poolUuid);
throw e;
}
try {
Thread.sleep(_interval);
} catch (InterruptedException e) {
s_logger.info("Who woke me from my slumber?");
}
}
assert false : "We should never get here";
removeConnect(_poolUuid);
}
throw new CloudRuntimeException("After " + _retries
+ " retries, we cannot contact the host ");
}
}
public static class TrustAllManager implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
}
}