package com.yahoo.dtf.deploy;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.SocketException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Properties;
import java.util.Map.Entry;
import org.apache.commons.net.telnet.TelnetClient;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.yahoo.dtf.DTFProperties;
import com.yahoo.dtf.actions.Action;
import com.yahoo.dtf.actions.ActionFactory;
import com.yahoo.dtf.actions.properties.Property;
import com.yahoo.dtf.actions.protocol.deploy.DTFNode;
import com.yahoo.dtf.actions.protocol.deploy.Dtfa;
import com.yahoo.dtf.actions.protocol.deploy.Dtfc;
import com.yahoo.dtf.actions.protocol.deploy.Dtfx;
import com.yahoo.dtf.actions.protocol.deploy.Setup;
import com.yahoo.dtf.config.Config;
import com.yahoo.dtf.exception.DTFException;
import com.yahoo.dtf.exception.DebugServerException;
import com.yahoo.dtf.exception.ParseException;
import com.yahoo.dtf.logger.DTFLogger;
import com.yahoo.dtf.util.JarUtil;
import com.yahoo.dtf.util.ThreadUtil;
/**
* @dtf.feature XML Configuration File
* @dtf.feature.group Deployment
* @dtf.feature.desc
* <p>
* The deployment feature is used by identifying a deployment configuration file
* as explained in the {@dtf.link Command Line Usage} section. This
* configuration file is written in XML and is quite simple to use. Here is a
* basic configuration file to start understanding how to write your own
* configuration file:
* <p>
*
* {@dtf.xml
* <?xml version="1.0" encoding="UTF-8"?>
* <setup xmlns="http://dtf.org/v1" >
* <dtfc host="${host}" user="${user}" path="dtf/dtfc">
* <dtfa host="${host}" user="${user}" path="dtf/dtfa1">
* <property name="node.id" value="1"/>
* </dtfa>
* <dtfa host="${host}" user="${user}" path="dtf/dtfa2">
* <property name="node.id" value="2"/>
* </dtfa>
* <dtfa host="${host}" user="${user}" path="dtf/dtfa3">
* <property name="node.id" value="3"/>
* </dtfa>
* <dtfx host="${host}"
* user="${user}"
* path="dtf/dtfx"
* test="tests/ut/echo.xml"
* logs="tests/ut/output/ut_results.xml">
* </dtfx>
* </dtfc>
* </setup>}
*
* <p>
* Now from the previous example you can see that the configuration file is
* very easy to read and you could easily get started writing your own quickly.
* Just as any other DTF XML file you can use properties that you can easily
* then specify on the command line and control the deployment setup easily
* from the command line.
* </p>
* <p>
* Aside from being able to use the properties you can also specify the exact
* properties to load into each component at startup. The property loading is
* done the same way as it would be when you're using the <b>dtf.defaults</b>
* property but the loading is handled by the deployment feature itself. You
* can read more on the <b>dtf.defaults</b> feature at
* {@dtf.link Loading Default Properties}.
* </p>
* <p>
* There are a few other important attributes to be specified when identifying
* the various components that make up your DTF setup. These attributes are all
* well documented at {@dtf.link Deployment Tags}.
* </p>
* <p>
* Another few things to remember when writing these configuration files is
* that you don't have to identify the DTFX and can instead use this file to
* simply startup and run your tests against the same setup many times. You
* can also use the deploy-status to check the status of the setup and easily
* restart the deployment before running your existing tests against a well
* known and well defined setup.
* </p>
*
* @author rlgomes
*/
public class DeployDTF {
static DTFLogger _logger = DTFLogger.getLogger(DeployDTF.class);
public static void main(String[] args) {
try {
com.yahoo.dtf.DTFNode.init();
String command = "start";
if ( args.length > 0 ) command = args[0];
Config conf = Action.getConfig();
String config = conf.getProperty("deploy.config");
String user = conf.getProperty("deploy.user");
String script = conf.getProperty("deploy.script");
_logger.info("Reading [" + config + "] config file");
if ( command.equals("setup-ssh") ) {
String host = conf.getProperty("setup.host");
user = conf.getProperty("setup.user");
if ( host == null )
throw new DTFException("Set the setup.host property.");
if ( user == null ) {
user = System.getProperty("user.name");
_logger.info("Defaulting to user [" + user + "]");
}
setupSSH(host, user, _logger);
return;
}
FileInputStream fis;
try {
fis = new FileInputStream(config);
} catch (FileNotFoundException e) {
throw new DTFException("Error reading [" + config +"]", e);
}
/*
* Load any default properties identified by the deploy.defaults
* property
*/
String defaults = Action.getConfig().getProperty("deploy.defaults");
if ( defaults != null && new File(defaults).exists() ) {
try {
FileInputStream pfis = null;
try {
pfis = new FileInputStream(defaults);
Action.getConfig().loadProperties(pfis, true);
} finally {
if ( pfis != null ) pfis.close();
}
} catch (IOException e) {
throw new DTFException("Error reading properties file ["
+ defaults + "]",e);
}
}
Action root = ActionFactory.parseAction(fis, config);
if ( !(root instanceof Setup) )
throw new DTFException("Root element of document is not <setup>.");
Setup setup = (Setup) root;
initJar();
if ( command.equals("start") ) {
setupStart(setup);
} else if ( command.equals("status")) {
setupStatus(setup);
} else if ( command.equals("stop") ) {
setupStop(setup);
} else if ( command.equals("wait") ) {
waitForCompletion(setup);
} else if ( command.equals("watch") ) {
setupWatch(setup);
} else if ( command.equals("savelogs") ) {
setupSaveLogs(setup);
} else if ( command.equals("script") ) {
user = ( user.equals("N/A") ? null : user );
setupInit(setup, user, script);
}
} catch (Throwable t) {
/*
* Its bad practice to catch Throwables but we need to be able
* to report errors correctly and with a stack trace when this
* happens
*/
_logger.error("Error deploying.",t);
System.exit(-1);
}
}
public static void initJar() throws DTFException {
File dtf_jar = new File("dtf.jar");
if ( dtf_jar.exists() ) {
if ( !dtf_jar.delete() )
throw new DTFException("Unable to delete [" + dtf_jar + "]");
}
String dtfhome = Action.getConfig().getProperty(DTFProperties.DTF_HOME);
JarUtil.jarUp(new File(dtfhome), dtf_jar);
}
private static void setupSSH(String host, String user, DTFLogger logger)
throws DTFException {
try {
Session session = DTFSSHSetup.setupSSH(host, user, logger);
session.disconnect();
} catch (FileNotFoundException e) {
throw new DTFException("Unable to setup passwordless ssh.",e);
} catch (JSchException e) {
throw new DTFException("Unable to setup passwordless ssh.",e);
} catch (IOException e) {
throw new DTFException("Unable to setup passwordless ssh.",e);
} catch (SftpException e) {
throw new DTFException("Unable to setup passwordless ssh.",e);
}
}
private static void waitForCompletion(Setup setup) throws DTFException {
ArrayList<Dtfc> dtfcs = setup.findAllActions(Dtfc.class);
Config conf = Action.getConfig();
int check_interval = conf.getPropertyAsInt("deploy.wait.interval",60000);
for (int i = 0; i < dtfcs.size(); i++) {
Dtfc dtfc = dtfcs.get(i);
// lets startup this DTFC on the machine specified
String host = dtfc.getHost();
String user = dtfc.getUser();
String hostkey = user + "@" + host;
try {
_logger.info("Status of dtfc on " + host);
TelnetClient telnet = new TelnetClient();
telnet.connect(host, 40000);
OutputStream os = telnet.getOutputStream();
InputStream is = telnet.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
try {
os.write("status\nquit\n".getBytes());
os.flush();
String line = null;
while ( ( line = br.readLine() ) != null ) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// read the props for each component
while ( line != null && !line.trim().equals("") &&
!line.equals("Bye")) {
line = line.replaceFirst("^#","");
baos.write((line + "\n").getBytes());
line = br.readLine();
}
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
Properties props = new Properties();
props.load(bais);
if ( props.getProperty("Bye") != null )
break;
String type =
props.getProperty(DTFProperties.DTF_NODE_TYPE);
String hostname = props.getProperty("dtf.node.host");
if ( type.equals("dtfc") ) {
_logger.info("DTFC on " + hostname);
}
}
} finally {
br.close();
os.close();
is.close();
}
} catch (IOException e) {
_logger.info("DTFC not running at " + hostkey);
return;
}
boolean done = false;
while ( !done ) {
ThreadUtil.pause(check_interval);
Dtfx dtfx = (Dtfx) dtfc.findFirstAction(Dtfx.class);
if ( dtfx != null ) {
String dtfx_host = dtfx.getHost();
String dtfx_user = dtfx.getUser();
String dtfx_path = dtfx.getPath();
String dtfx_rsakey = dtfx.getRsakey();
String dtfx_passphrase = dtfx.getPassphrase();
try {
Properties state = getState("dtfx",
dtfx_host,
dtfx_user,
dtfx_path,
dtfx_rsakey,
dtfx_passphrase);
_logger.info("DTFX running at [" + dtfx_host + "]");
String exited = state.getProperty("dtf.node.exited");
if ( exited != null && exited.equals("true") ) {
String succeeded = state.getProperty("dtf.node.succeeded");
if ( succeeded.equals("true") ) {
_logger.info("DTFX has completed successfully at [" + dtfx_host + "]");
} else {
throw new DTFException("DTFX has completed with an error at [" + dtfx_host + "]");
}
done = true;
}
} catch (IOException e) {
_logger.info("DTFX on " + dtfx_host + " not running.",e);
} catch (JSchException e) {
_logger.info("DTFX on " + dtfx_host + " not running.",e);
} catch (SftpException e) {
_logger.info("DTFX on " + dtfx_host + " not running.",e);
}
}
}
}
}
private static void setupStatus(Setup setup) throws DTFException {
ArrayList<Dtfc> dtfcs = setup.findAllActions(Dtfc.class);
for (int i = 0; i < dtfcs.size(); i++) {
Dtfc dtfc = dtfcs.get(i);
ArrayList<Dtfa> dtfas = dtfc.findAllActions(Dtfa.class);
ArrayList<Dtfa> dtfas_connected = new ArrayList<Dtfa>();
// lets startup this DTFC on the machine specified
String host = dtfc.getHost();
String user = dtfc.getUser();
String hostkey = user + "@" + host;
try {
_logger.info("Status of dtfc on " + host);
TelnetClient telnet = new TelnetClient();
telnet.connect(host, 40000);
OutputStream os = telnet.getOutputStream();
InputStream is = telnet.getInputStream();
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
try {
os.write("status\nquit\n".getBytes());
os.flush();
String line = null;
while ( ( line = br.readLine() ) != null ) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// read the props for each component
while ( line != null && !line.trim().equals("") && !line.equals("Bye")) {
line = line.replaceFirst("^#","");
baos.write((line + "\n").getBytes());
line = br.readLine();
}
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
Properties props = new Properties();
props.load(bais);
if ( props.getProperty("Bye") != null )
break;
String type = props.getProperty(DTFProperties.DTF_NODE_TYPE);
String id = props.getProperty("dtf.node.id");
String hostname = props.getProperty("dtf.node.host");
String node_user = props.getProperty("dtf.node.user");
String path = props.getProperty("dtf.node.home");
boolean locked = Boolean.valueOf(props.getProperty("dtf.node.locked"));
if ( type.equals("dtfc") ) {
_logger.info("DTFC on " + hostname);
} else if ( type.equals("dtfa") ) {
Dtfa aux = new Dtfa();
aux.setHost(hostname);
aux.setUser(node_user);
aux.setPath(path);
dtfas_connected.add(aux);
if ( locked ) {
_logger.info("DTFA [" + id + "] on " + hostname +
" is locked");
} else {
_logger.info("DTFA [" + id + "] on " + hostname +
" is free");
}
}
}
} finally {
br.close();
}
/*
* Validate that there are no agents not accounted for
*/
} finally {
os.close();
is.close();
}
for (int a = 0; a < dtfas.size(); a++) {
Dtfa dtfa = dtfas.get(a);
boolean found = false;
for (int x = 0; x < dtfas_connected.size(); x++) {
if ( dtfa.equals(dtfas_connected.get(x)) ) {
dtfas_connected.remove(x);
found = true;
break;
}
}
if ( !found ) {
_logger.warn("DTFA [dtfa-" + a + "] NOT running on " +
dtfa.getUser() + "@" + dtfa.getHost() +
":" + dtfa.getPath());
}
}
} catch (IOException e) {
_logger.info("DTFC not running at " + hostkey);
return;
} catch (DTFException e) {
_logger.info("DTFC not running at " + hostkey);
return;
}
Dtfx dtfx = (Dtfx) dtfc.findFirstAction(Dtfx.class);
if ( dtfx != null ) {
String dtfx_host = dtfx.getHost();
String dtfx_user = dtfx.getUser();
String dtfx_path = dtfx.getPath();
String dtfx_rsakey = dtfx.getRsakey();
try {
Properties state = getState("dtfx",
dtfx_host,
dtfx_user,
dtfx_path,
dtfx_rsakey,
dtfx.getPassphrase());
int dport = Integer.valueOf(state.getProperty("dtf.debug.port"));
String exited = state.getProperty("dtf.node.exited");
if ( exited != null && exited.equals("true") ) {
String msg = state.getProperty("dtf.node.succeeded");
msg = ( msg.equals("true") ? "succeeded" : "failed");
_logger.info("DTFX on " + dtfx_host +
" not running, last run has " + msg + ".");
} else {
try {
Properties status = getStatus(dtfx_host, dport);
String xml = status.getProperty("dtf.xml.filename");
String xmlcol = status.getProperty("dtf.xml.column");
String xmlline = status.getProperty("dtf.xml.line");
_logger.info("DTFX on " + dtfx_host + " running " +
xml + ":" + xmlline + "," + xmlcol);
} catch (IOException e) {
_logger.info("DTFX on " + dtfx_host + " not running.");
}
}
} catch (IOException e) {
_logger.info("DTFX on " + dtfx_host + " not running.",e);
} catch (JSchException e) {
_logger.info("DTFX on " + dtfx_host + " not running.",e);
} catch (SftpException e) {
_logger.info("DTFX on " + dtfx_host + " not running.",e);
}
}
}
}
private static void setupWatch(Setup setup) throws DTFException {
ArrayList<Dtfc> dtfcs = setup.findAllActions(Dtfc.class);
for (int i = 0; i < dtfcs.size(); i++) {
Dtfc dtfc = dtfcs.get(i);
Dtfx dtfx = (Dtfx) dtfc.findFirstAction(Dtfx.class);
if ( dtfx != null ) {
String dtfx_host = dtfx.getHost();
String dtfx_user = dtfx.getUser();
String dtfx_path = dtfx.getPath();
String dtfx_rsakey = dtfx.getRsakey();
String dtfx_passphrase = dtfx.getPassphrase();
if ( dtfx_path == null )
dtfx_path = "dtf";
try {
Session session = SSHUtil.connectToHost(dtfx_host,
dtfx_user,
dtfx_rsakey,
dtfx_passphrase);
try {
SSHUtil.execute(session,
"tail -f " + dtfx_path + "/dtfx.log",
true);
} finally {
session.disconnect();
}
} catch (JSchException e) {
throw new DTFException("Unable to connect to dtfx.",e);
} catch (IOException e) {
throw new DTFException("Unable to connect to dtfx.",e);
}
}
}
}
public static Properties getState(String component,
String host,
String user,
String path,
String rsakey,
String passphrase)
throws JSchException, SftpException, IOException {
Properties props = new Properties();
Session session = SSHUtil.connectToHost(host,
user,
rsakey,
passphrase);
Channel sChannel = session.openChannel("sftp");
sChannel.connect();
ChannelSftp csftp = (ChannelSftp)sChannel;
if ( path == null )
path = csftp.getHome() + "/dtf";
File tmp = new File(component + ".state");
tmp.deleteOnExit();
FileOutputStream fos = null;
FileInputStream fis = null;
try {
fos = new FileOutputStream(tmp);
csftp.get(path + "/state/" + component + ".state", fos);
fos.close();
fis = new FileInputStream(tmp);
props.load(fis);
} finally {
if ( fos != null ) fos.close();
if ( fis != null ) fis.close();
}
return props;
}
public static Properties getStatus(String host,
int port) throws SocketException, IOException {
TelnetClient telnet = new TelnetClient();
OutputStream os = null;
InputStream is = null;
try {
telnet.connect(host, port);
os = telnet.getOutputStream();
is = telnet.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
try {
os.write("status\nquit\n".getBytes());
os.flush();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String line = br.readLine();
while ( line != null && !line.trim().equals("") && !line.equals("Bye")) {
line = line.replaceFirst("^#","");
baos.write((line + "\n").getBytes());
line = br.readLine();
}
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
Properties props = new Properties();
props.load(bais);
return props;
} finally {
br.close();
}
} finally {
if ( os != null ) os.close();
if ( is != null ) is.close();
}
}
public static void status(String component,
String host,
String user,
int port)
throws JSchException, IOException, SftpException, DTFException {
}
public static boolean isUp(String component,
String host,
int port)
throws IOException {
TelnetClient telnet = new TelnetClient();
OutputStream os = null;
InputStream is = null;
try {
try {
telnet.connect(host, port);
} catch (IOException e ) {
return false;
}
os = telnet.getOutputStream();
is = telnet.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
try {
os.write("status\nquit\n".getBytes());
os.flush();
String line = null;
while ((line = br.readLine()) != null && !line.startsWith("#"));
while ( (line = br.readLine()) != null && !line.equals("# Bye"));
return true;
} finally {
br.close();
}
} finally {
if ( os != null) os.close();
if ( is != null ) is.close();
if ( telnet.isConnected() ) telnet.disconnect();
}
}
public static void waitForComponentToStart(String component,
String host,
int port)
throws JSchException, IOException, SftpException {
TelnetClient telnet = new TelnetClient();
OutputStream os = null;
BufferedReader br = null;
long start = System.currentTimeMillis();
try {
while ( (System.currentTimeMillis() - start) < 10000 ) {
try {
telnet.connect(host, port);
} catch (IOException e ) {
_logger.info("Waiting for [" + component + "] on " + host);
ThreadUtil.pause(1000);
continue;
}
os = telnet.getOutputStream();
InputStream is = telnet.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
br = new BufferedReader(isr);
os.write("status\nquit\n".getBytes());
os.flush();
String line = null;
while ((line = br.readLine()) != null && !line.startsWith("#"));
while ( (line = br.readLine()) != null && !line.equals("# Bye") )
break;
}
} finally {
if ( os != null ) os.close();
if ( br != null ) br.close();
if ( telnet.isConnected() ) telnet.disconnect();
}
}
public static void waitForComponentToStop(String component,
String host,
int debug_port)
throws JSchException, IOException, SftpException {
TelnetClient telnet = new TelnetClient();
OutputStream os = null;
InputStream is = null;
long start = System.currentTimeMillis();
try {
boolean shutdown = false;
while ((System.currentTimeMillis() - start) < 10000) {
try {
telnet.connect(host, debug_port);
} catch (IOException e) {
// debug server is down so the node should be down
shutdown = true;
break;
}
_logger.info("Waiting for [" + component +
"] to stop on " + host);
ThreadUtil.pause(500);
os = telnet.getOutputStream();
is = telnet.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
try {
os.write("shutdown\nquit\n".getBytes());
os.flush();
String line = null;
while ((line = br.readLine()) != null && !line.startsWith("#"));
while ((line = br.readLine()) != null && !line.equals("# Bye"))
ThreadUtil.pause(500);
} finally {
br.close();
}
}
if ( !shutdown )
_logger.info(component + " refuses to shutdown.");
} finally {
if ( os != null ) os.close();
if ( is != null ) is.close();
if ( telnet.isConnected() ) telnet.disconnect();
}
}
private static void setupStart(Setup setup) throws DTFException {
ArrayList<Dtfc> dtfcs = setup.findAllActions(Dtfc.class);
for (int i = 0; i < dtfcs.size(); i++) {
Dtfc dtfc = dtfcs.get(i);
String dtfc_host = dtfc.getHost();
String dtfc_user = dtfc.getUser();
String hostkey = dtfc_user + "@" + dtfc_host;
try {
HashMap<String, String> properties = new HashMap<String, String>();
ArrayList<Property> props = dtfc.findActions(Property.class);
for (int c = 0; c < props.size(); c++) {
Property prop = props.get(c);
properties.put(prop.getName(),prop.getValue());
}
startup("dtfc", dtfc, properties, "dtfc.log");
waitForComponentToStart("dtfc", dtfc_host, 40000);
} catch (JSchException e ) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (IOException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (SftpException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
}
/*
* Startup the DTFA's
*/
ArrayList<Dtfa> dtfas = dtfc.findAllActions(Dtfa.class);
AdminClient dsc = null;
try {
dsc = new AdminClient(dtfc_host, 40000, _logger);
} catch (DebugServerException e) {
_logger.error("Unable to connect to debugserver on [" +
dtfc_host + "], check the logs at " + hostkey +
"/dtfc.log for more information.");
System.exit(-1);
}
try {
for (int a = 0; a < dtfas.size(); a++) {
Dtfa dtfa = dtfas.get(a);
StringBuffer properties = new StringBuffer();
ArrayList<Property> props = dtfa.findActions(Property.class);
for (int c = 0; c < props.size(); c++) {
Property prop = props.get(c);
properties.append(prop.getName() + "=" + prop.getValue());
if ( c+1 < props.size() ) properties.append(",");
}
String dtfa_host = dtfa.getHost();
String dtfa_user = dtfa.getUser();
String dtfa_path = dtfa.getPath();
String dtfa_rsakey = dtfa.getRsakey();
String passphrase = dtfa.getPassphrase();
String wrapcmd = dtfa.getWrapcmd();
if ( wrapcmd != null ) {
wrapcmd = URLEncoder.encode(wrapcmd,"UTF8");
}
String propstring = URLEncoder.encode(properties.toString(),
"UTF8");
String start = "start dtfa " + dtfa_host + " " +
dtfa_user +
" dtfa-" + a + ".log " +
dtfa_path + " " +
dtfa_rsakey + " " +
wrapcmd + " " +
passphrase + " " +
propstring;
if ( _logger.isDebugEnabled() )
_logger.info("Executing [" + start + "]");
dsc.execute(start);
}
/*
* Startup the DTFX if it was defined
*/
Dtfx dtfx = (Dtfx) dtfc.findFirstAction(Dtfx.class);
if ( dtfx != null ) {
ArrayList<Property> props = dtfx.findActions(Property.class);
HashMap<String, String> properties = new HashMap<String, String>();
for (int c = 0; c < props.size(); c++) {
Property prop = props.get(c);
properties.put(prop.getName(), prop.getValue());
}
properties.put("dtf.xml.filename",dtfx.getTest());
properties.put("dtf.listen.addr",dtfx.getHost());
startup("dtfx", dtfx, properties, "dtfx.log");
}
} catch (JSchException e ) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (IOException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (SftpException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} finally {
dsc.close();
}
}
}
private static void setupInit(Setup setup,
String guser,
String script) throws DTFException {
ArrayList<Dtfc> dtfcs = setup.findAllActions(Dtfc.class);
for (int i = 0; i < dtfcs.size(); i++) {
Dtfc dtfc = dtfcs.get(i);
String dtfc_host = dtfc.getHost();
String dtfc_user = dtfc.getUser();
String dtfc_path = dtfc.getPath();
String hostkey = dtfc_user + "@" + dtfc_host;
try {
String user = (guser == null ? dtfc_user : guser);
init(dtfc_host, user, dtfc_path, script, dtfc.getWrapcmd());
} catch (JSchException e ) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (IOException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (SftpException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
}
/*
* init the DTFA's
*/
ArrayList<Dtfa> dtfas = dtfc.findAllActions(Dtfa.class);
try {
for (int a = 0; a < dtfas.size(); a++) {
Dtfa dtfa = dtfas.get(a);
String dtfa_host = dtfa.getHost();
String dtfa_user = dtfa.getUser();
String dtfa_path = dtfa.getPath();
String user = (guser == null ? dtfa_user : guser);
hostkey = user + "@" + dtfa_host;
init(dtfa_host, user, dtfa_path, script, dtfa.getWrapcmd());
}
/*
* init the DTFX if it was defined
*/
Dtfx dtfx = (Dtfx) dtfc.findFirstAction(Dtfx.class);
if ( dtfx != null ) {
String dtfx_host = dtfx.getHost();
String dtfx_user = dtfx.getUser();
String dtfx_path = dtfx.getPath();
String user = (guser == null ? dtfx_user : guser);
hostkey = user + "@" + dtfx_host;
init(dtfx_host, user, dtfx_path, script, dtfx.getWrapcmd());
}
} catch (JSchException e ) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (IOException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (SftpException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
}
}
}
private static void setupStop(Setup setup) throws ParseException {
ArrayList<Dtfc> dtfcs = setup.findAllActions(Dtfc.class);
for (int i = 0; i < dtfcs.size(); i++) {
Dtfc dtfc = dtfcs.get(i);
String host = dtfc.getHost();
String user = dtfc.getUser();
String path = dtfc.getPath();
String rsakey = dtfc.getRsakey();
String hostkey = user + "@" + host;
try {
if ( isUp("dtfc", host, 40000) ) {
stop("dtfc", host, user, path, rsakey, dtfc.getPassphrase());
} else {
_logger.info("DTFC not running on " + hostkey);
}
} catch (JSchException e ) {
_logger.error("Unable to stop dtf setup on [" + hostkey + "]",e);
System.exit(-1);
} catch (IOException e) {
_logger.error("Unable to stop dtf setup on [" + hostkey + "]",e);
System.exit(-1);
} catch (SftpException e) {
_logger.error("Unable to stop dtf setup on [" + hostkey + "]",e);
System.exit(-1);
}
}
}
private static void setupSaveLogs(Setup setup) throws DTFException {
ArrayList<Dtfc> dtfcs = setup.findAllActions(Dtfc.class);
for (int i = 0; i < dtfcs.size(); i++) {
Dtfc dtfc = dtfcs.get(i);
String host = dtfc.getHost();
String user = dtfc.getUser();
String path = dtfc.getPath();
String rsakey = dtfc.getRsakey();
String passphrase = dtfc.getPassphrase();
String hostkey = user + "@" + host;
File file = new File("dtf_logs");
while ( file.exists() ) {
File bklogs = new File("dtf_logs_bk");
if ( !bklogs.exists() && !bklogs.mkdirs() ) {
_logger.error("Unable to create [" + bklogs + "]");
System.exit(-1);
}
File ren = new File("dtf_logs_bk/dtf_logs-" + System.currentTimeMillis());
if ( !file.renameTo(ren) ) {
_logger.error("Unable to rename [" + file + "] to [" +ren + "]");
System.exit(-1);
}
_logger.info("Old logs at dtf_logs_bk/" + ren.getName());
}
if ( !file.exists() && !file.mkdir() ) {
_logger.error("Unable to create [" + file + "]");
System.exit(-1);
}
try {
collect("dtfc",
host,
user,
path,
rsakey,
passphrase,
"dtfc.log",
file.getAbsolutePath());
} catch (JSchException e ) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (IOException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (SftpException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
}
try {
ArrayList<Dtfa> dtfas = dtfc.findAllActions(Dtfa.class);
for (int a = 0; a < dtfas.size(); a++) {
Dtfa dtfa = dtfas.get(a);
String dtfa_host = dtfa.getHost();
String dtfa_user = dtfa.getUser();
String dtfa_path = dtfa.getPath();
String dtfa_rsakey = dtfa.getRsakey();
hostkey = user + "@" + host;
collect("dtfa",
dtfa_host,
dtfa_user,
dtfa_path,
dtfa_rsakey,
dtfa.getPassphrase(),
"dtfa-" + a + ".log",
file.getAbsolutePath());
}
Dtfx dtfx = (Dtfx) dtfc.findFirstAction(Dtfx.class);
if ( dtfx != null ) {
String dtfx_host = dtfx.getHost();
String dtfx_user = dtfx.getUser();
String dtfx_path = dtfx.getPath();
String dtfx_rsakey = dtfx.getRsakey();
String dtfx_logs = dtfx.getLogs();
hostkey = user + "@" + host;
collect("dtfx",
dtfx_host,
dtfx_user,
dtfx_path,
dtfx_rsakey,
dtfx.getPassphrase(),
"dtfx.log",
file.getAbsolutePath());
if ( dtfx_logs != null ) {
String[] logs = dtfx_logs.split(",");
for (int l = 0; l < logs.length; l++) {
collect("dtfx",
dtfx_host,
dtfx_user,
dtfx_path,
dtfx_rsakey,
dtfx.getPassphrase(),
logs[l],
file.getAbsolutePath());
}
}
}
} catch (JSchException e ) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (IOException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
System.exit(-1);
} catch (SftpException e) {
_logger.error("Unable to deploy DTF to [" + hostkey + "]",e);
}
_logger.info("Logs at " + file);
}
}
public static void startup(String component,
DTFNode node,
HashMap<String, String > properties,
String logname)
throws JSchException, IOException, SftpException, DTFException {
startup(component, node, properties, logname, _logger);
}
public static void startup(String component,
DTFNode node,
HashMap<String, String> properties,
String logname,
DTFLogger logger)
throws JSchException, IOException, SftpException, DTFException {
String host = node.getHost();
String user = node.getUser();
String path = node.getPath();
String wrapcmd = node.getWrapcmd();
Session session = DTFSSHSetup.setupHost(node, component, logger);
int rc = 0;
Channel sChannel = session.openChannel("sftp");
sChannel.connect();
if ( path == null ) {
String home = SSHUtil.getHomeDir(session, node);
path = home + "/dtf";
}
String hostkey = user + "@" + host + "/" + path;
// don't setup the same machine with the same build if its exactly the
// same machine + user + path
logger.info("");
logger.info("Starting [" + component + "] on " + host);
logger.info("Logs at " + hostkey + "/" + logname);
properties.put("dtf.listen.addr", host);
StringBuffer props = new StringBuffer();
props.append("# properties file create by DTF deploy task\n");
for (Entry<String, String> entry : properties.entrySet())
props.append(entry.getKey() + "=" + entry.getValue() + "\n");
File tmp = new File("deploy.props");
tmp.deleteOnExit();
FileOutputStream fos = null;
FileInputStream fis = null;
try {
fos = new FileOutputStream(tmp);
fos.write(props.toString().getBytes());
fis = new FileInputStream(tmp);
String cmd = "cat > " + path + "/" + logname + ".props";
cmd = wrap(wrapcmd,cmd);
rc = SSHUtil.execute(session,
cmd,
fis,
new ByteArrayOutputStream(),
new ByteArrayOutputStream());
if ( rc != 0 ) {
throw new DTFException("Unable to copy props file on " +
hostkey + ", got rc " + rc);
}
} finally {
if ( fos != null ) fos.close();
if ( fis != null ) fis.close();
}
String cmd = DTFSSHSetup.CD_CMD + " " + path + " ; " +
DTFSSHSetup.BG_CMD + " ./ant.sh run_" + component +
" -Ddtf.defaults=" + logname + ".props > " + logname +
" 2>&1 &";
cmd = wrap(wrapcmd,cmd);
if ( logger.isDebugEnabled() )
logger.debug("cmd [" + cmd + "]");
rc = SSHUtil.execute(session, cmd, logger.isDebugEnabled());
if ( rc != 0 ) {
throw new DTFException("Unable to start " + component + " on " +
hostkey + " rc " + rc);
}
session.disconnect();
}
public static String wrap(String wrapcmd, String cmd) {
if ( wrapcmd != null ) {
return wrapcmd.replace("%u", "\"" + cmd + "\"");
} else {
return cmd;
}
}
private static ArrayList<String> alreadyInit = new ArrayList<String>();
public static void init(String host,
String user,
String path,
String script,
String wrapcmd)
throws JSchException, IOException, SftpException, DTFException {
Session session = DTFSSHSetup.setupSSH(host, user, _logger);
String escript = wrap(wrapcmd,
DTFSSHSetup.CD_CMD + " " + path + "; ./" + script);
String hostkey = user + "@" + host + "{" + script + "} in [" + wrapcmd + "]" ;
if ( alreadyInit.contains(hostkey ) ) {
_logger.info("Already executed [" + escript + "] on [" + user +
"@" + host + "]");
} else {
alreadyInit.add(hostkey);
FileInputStream fis = null;
ChannelExec exec = null;
int rc = 0;
try {
String cmd = DTFSSHSetup.MKDIR_CMD + " -p " + path;
cmd = wrap(wrapcmd,cmd);
rc = SSHUtil.execute(session, cmd, _logger.isDebugEnabled());
if ( rc != 0 ) {
throw new DTFException("Unable to create [" + path +
"] rc " + rc);
}
fis = new FileInputStream(script);
String scriptname = new File(script).getName();
cmd = "cat > " + path + "/" + scriptname;
cmd = wrap(wrapcmd,cmd);
rc = SSHUtil.execute(session,
cmd,
fis,
new ByteArrayOutputStream(),
new ByteArrayOutputStream());
if ( rc != 0 ) {
throw new DTFException("Unable to copy script [" +
scriptname + "], got rc " + rc);
}
// fix permissions
cmd = "chmod +x " + path + "/" + scriptname;
cmd = wrap(wrapcmd,cmd);
rc = SSHUtil.execute(session, cmd, _logger.isDebugEnabled());
if ( rc != 0 ) {
throw new DTFException("Unable to fix script permissions ["
+ scriptname + "], got rc " + rc);
}
exec = (ChannelExec) session.openChannel("exec");
exec.setCommand(escript);
_logger.info("executing [" + escript + "]");
final ChannelExec fexec = exec;
OutputStream aux = new OutputStream() {
StringBuffer line = new StringBuffer();
@Override
public void write(int b) throws IOException {
System.out.write(b);
line.append((char)b);
if ( line.toString().matches(".*Password:.*") ) {
System.out.flush();
OutputStream os = fexec.getOutputStream();
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String password = br.readLine();
os.write((password + "\n").getBytes());
os.flush();
line = new StringBuffer();
}
if ( b == '\n') {
line = new StringBuffer();
}
}
@Override
public void flush() throws IOException {
System.out.flush();
}
};
exec.setErrStream(aux);
exec.setExtOutputStream(aux);
exec.setOutputStream(aux);
exec.connect();
// wait for completion
while ( exec.getExitStatus() == -1 )
ThreadUtil.pause(1000);
if ( exec.getExitStatus() != 0 ) {
throw new DTFException("Error executing script [" +
exec.getExitStatus() + "]");
}
} finally {
if ( fis != null ) fis.close();
if ( exec != null ) exec.disconnect();
session.disconnect();
}
}
}
public static void stop(String component,
String host,
String user,
String path,
String rsakey,
String passphrase)
throws JSchException, IOException, SftpException {
Session session = SSHUtil.connectToHost(host, user, rsakey, passphrase);
Channel sChannel = session.openChannel("sftp");
sChannel.connect();
ChannelSftp csftp = (ChannelSftp)sChannel;
if ( path == null )
path = csftp.getHome() + "/dtf";
try {
_logger.info("");
waitForComponentToStop(component, host, 40000);
} finally {
csftp.disconnect();
session.disconnect();
}
}
public static void collect(String component,
String host,
String user,
String path,
String rsakey,
String passphrase,
String logpath,
String savepath)
throws JSchException,
IOException, SftpException, DTFException {
Session session = SSHUtil.connectToHost(host, user, rsakey, passphrase);
int rc = 0;
Channel sChannel = session.openChannel("sftp");
sChannel.connect();
ChannelSftp csftp = (ChannelSftp) sChannel;
if (path == null)
path = csftp.getHome() + "/dtf";
String hostkey = user + "@" + host + ":" + path;
String outputname = new File(logpath).getName();
try {
_logger.info("");
if ( csftp.lstat(path + "/" + logpath).isDir() ) {
_logger.info("Compressing " + logpath + " to " + outputname + ".tgz");
String cmd = DTFSSHSetup.CD_CMD + " dtf ; tar cvfz " +
outputname + ".tgz " + logpath;
rc = SSHUtil.execute(session, cmd, _logger.isDebugEnabled());
if ( rc != 0 ) {
throw new DTFException("Unable to compress log directory ["
+ logpath + "]");
}
_logger.info("Saving " + hostkey + "/" + outputname
+ ".tgz to " + savepath);
csftp.get(path + "/" + outputname + ".tgz",
savepath + "/" + outputname + ".tgz");
csftp.rm(path + "/" + outputname + ".tgz");
} else {
_logger.info("Saving " + hostkey + "/" + logpath
+ " to " + savepath);
csftp.get(path + "/" + logpath, savepath + "/" + outputname);
}
} catch (SftpException e) {
_logger.warn("Unable to save [" + logpath + "] from [" + hostkey + "]");
} finally {
csftp.disconnect();
session.disconnect();
}
}
}