package org.hyperic.hq.maven.HQplugins;
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with 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.
*/
import com.jcraft.jsch.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
/**
* @goal run
*/
public class RunPlugin extends AbstractMojo implements UserInfo, UIKeyboardInteractive {
Log log = getLog();
private String remotePass;
/**
* @parameter expression="${project.basedir}"
*/
private File dir;
/**
* @parameter expression="${project.version}"
*/
private String version;
/**
* @parameter expression="${args}"
*/
protected String config;
public void execute() throws MojoExecutionException {
JSch.setLogger(new MyLogger());
log.info("dir=" + dir);
log.info("version=" + version);
String plugin = dir.getName().split("-plugin")[0];
File hq = new File(System.getProperty("user.home"), ".hq");
File configFile;
if (config != null) {
configFile = new File(config);
} else {
configFile = new File(hq, dir.getName() + ".properties");
}
log.info("Config file:" + configFile);
File jar = new File(dir, "/target/" + plugin + "-plugin-" + version + ".jar");
SuperProps props = new SuperProps();
try {
props.load(new FileInputStream(configFile));
} catch (IOException ex) {
log.error(ex.getMessage());
throw new MojoExecutionException("error", ex);
}
String javaBin = props.getProperty("java.bin");
String sudo = props.getProperty("sudo", null);
String agentBundle = props.getProperty("agent.bundle");
String server = props.getProperty("server.install", null);
String logL = props.getProperty("log", "info");
String method = props.getProperty("method", null);
String action = props.getProperty("action", null);
String type = props.getProperty("type", null);
String pluginArgsS = props.getProperty("plugin.args", "");
List<String> pluginArgs = Arrays.asList(pluginArgsS.replaceAll("([^\\s]*=)", "-D$1").split(" "));
boolean debug = props.getProperty("debug", "false").equalsIgnoreCase("true");
boolean pause = props.getProperty("pause", "false").equalsIgnoreCase("true");
String agentV = new File(agentBundle).getName().substring("agent-".length());
String pdkJar = "hq-pdk-" + agentV + ".jar";
boolean oldStyle = props.getProperty("oldStyle", "false").equalsIgnoreCase("true");
if (oldStyle) {
pdkJar = "hq-product.jar";
}
List<String> cmd = new ArrayList();
cmd.add(javaBin);
if (debug) {
cmd.add("-Xdebug");
cmd.add("-Xrunjdwp:transport=dt_socket,address=8998,server=y,suspend=y");
}
cmd.add("-ea");
cmd.add("-jar");
cmd.add(agentBundle + "/pdk/lib/" + pdkJar);
cmd.add("-p");
cmd.add(plugin);
cmd.add("-m");
cmd.add(method);
if (action != null) {
cmd.add("-a");
cmd.add(action);
}
if (type != null) {
cmd.add("-t");
cmd.add("\"" + type + "\"");
}
if ((pluginArgs.size() > 0) && (pluginArgs.get(0).trim().length() > 0)) {
cmd.addAll(pluginArgs);
}
cmd.add("-Dpause-on-error=" + pause);
cmd.add("-Dplugins.include=" + plugin);
cmd.add("-Dlog=" + logL);
// if (sudo != null) {
// cmd = "sudo -u " + sudo + " " + cmd;
// }
boolean remote = props.getProperty("remote", "false").equalsIgnoreCase("true");
boolean copy = props.getProperty("copy", "false").equalsIgnoreCase("true");
File jarAgentDest = new File(new File(agentBundle), "/pdk/plugins/" + plugin + "-plugin.jar");
File jarServerDest = null;
if (server != null) {
jarServerDest = new File(new File(server), "/hq-engine/hq-server/webapps/ROOT/WEB-INF/hq-plugins/" + plugin + "-plugin.jar");
}
log.info("Plugin => '" + plugin + "'");
log.info("version => '" + version + "'");
log.info("jar => '" + jar + "' (" + jar.exists() + ")");
log.info("jarAgentDest => '" + jarAgentDest + "'");
log.info("jarServerDest => '" + jarServerDest + "'");
log.info("copy => '" + copy + "'");
log.info("debug => '" + debug + "'");
log.info("pause => '" + pause + "'");
log.info("cmd => '" + join(cmd) + "'");
boolean copyPdk = props.getProperty("copy-pdk", "false").equalsIgnoreCase("true");
File pdkOrg = null;
File pdkDest = null;
if (copyPdk && !remote) {
try {
File pdkLib = new File(new File(agentBundle), "/pdk/lib/");
String names[] = pdkLib.list(new FilenameFilter() {
public boolean accept(File file, String name) {
return name.startsWith("hq-pdk") && name.endsWith(".jar");
}
});
if (names.length != 1) {
throw new MojoExecutionException("hq-pdk*.jar not found");
}
pdkOrg = new File(dir, "../../hq-pdk/target/hq-pdk-" + version + ".jar");
pdkDest = new File(pdkLib, names[0]);
log.info("pdkOrg => '" + pdkOrg.getCanonicalPath() + "' (" + pdkOrg.exists() + ")");
log.info("pdkDest => '" + pdkDest.getCanonicalPath() + "' (" + pdkDest.exists() + ")");
copy(pdkOrg, pdkDest);
} catch (IOException ex) {
throw new MojoExecutionException("error", ex);
}
}
log.info("remote => '" + remote + "'");
if (remote) {
String remoteUser = props.getProperty("remote.user");
remotePass = props.getProperty("remote.pass");
String remoteHost = props.getProperty("remote.host");
log.info("host => '" + remoteHost + "'");
log.info("user => '" + remoteUser + "'");
if (copy) {
scpToRemote(remoteUser, remoteHost, jar.getAbsolutePath(), jarAgentDest.getAbsolutePath());
if (server != null) {
scpToRemote(remoteUser, remoteHost, jar.getAbsolutePath(), jarServerDest.getAbsolutePath());
}
}
if (method != null) {
executeRemote(remoteUser, remoteHost, join(cmd) + " 2>&1");
}
} else {
if (copy) {
copy(jar, jarAgentDest);
if (server != null) {
copy(jar, jarServerDest);
}
}
if (method != null) {
executeLocal(cmd, agentBundle);
}
}
}
private void executeLocal(List<String> argl, String agentBundle) throws MojoExecutionException {
try {
String[] args = (String[]) argl.toArray(new String[argl.size()]);
File workingDir = new File(agentBundle, "../..");
log.info("user => '" + workingDir + "'");
Process cmd = Runtime.getRuntime().exec(args, null, workingDir);
StreamConnector stdOut = new StreamConnector(cmd.getErrorStream(), System.out);
StreamConnector errOut = new StreamConnector(cmd.getInputStream(), System.out);
stdOut.start();
errOut.start();
cmd.waitFor();
} catch (Exception ex) {
throw new MojoExecutionException("error", ex);
}
}
private void executeRemote(String user, String host, String cmd) throws MojoExecutionException {
Session session = null;
Channel channel = null;
try {
JSch jsch = new JSch();
session = jsch.getSession(user, host, 22);
session.setConfig("PreferredAuthentications", "password");
session.setUserInfo(this);
session.setTimeout(10 * 1000);
session.connect();
channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(cmd);
channel.setInputStream(System.in);
InputStream in = channel.getInputStream();
channel.connect();
byte[] tmp = new byte[1024];
while (!channel.isClosed()) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
System.out.print(new String(tmp, 0, i));
}
Thread.sleep(0);
}
System.out.println("exit-status: " + channel.getExitStatus());
} catch (Exception ex) {
ex.printStackTrace();
throw new MojoExecutionException("error", ex);
} finally {
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
}
void copy(File src, File dst) throws MojoExecutionException {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(src);
out = new FileOutputStream(dst);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
System.out.print(".");
}
System.out.println(".");
} catch (Exception ex) {
throw new MojoExecutionException("error", ex);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
throw new MojoExecutionException("error", ex);
}
}
if (out != null) {
try {
out.close();
} catch (IOException ex) {
throw new MojoExecutionException("error", ex);
}
}
}
}
public void scpToRemote(String user, String host, String lfile, String rfile) {
FileInputStream fis = null;
try {
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, 22);
session.setConfig("PreferredAuthentications", "password");
session.setUserInfo(this);
session.connect();
// exec 'scp -t rfile' remotely
String command = "scp -p -t " + rfile;
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command);
// get I/O streams for remote scp
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
channel.connect();
if (checkAck(in) != 0) {
System.exit(0);
}
// send "C0644 filesize filename", where filename should not include '/'
long filesize = (new File(lfile)).length();
command = "C0644 " + filesize + " ";
if (lfile.lastIndexOf('/') > 0) {
command += lfile.substring(lfile.lastIndexOf('/') + 1);
} else {
command += lfile;
}
command += "\n";
out.write(command.getBytes());
out.flush();
if (checkAck(in) != 0) {
System.exit(0);
}
// send a content of lfile
fis = new FileInputStream(lfile);
byte[] buf = new byte[1024];
while (true) {
int len = fis.read(buf, 0, buf.length);
if (len <= 0) {
break;
}
out.write(buf, 0, len); //out.flush();
System.out.print(".");
}
System.out.println(".");
fis.close();
fis = null;
// send '\0'
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
if (checkAck(in) != 0) {
System.exit(0);
}
out.close();
channel.disconnect();
session.disconnect();
} catch (Exception e) {
e.printStackTrace();
try {
if (fis != null) {
fis.close();
}
} catch (Exception ee) {
}
}
}
static int checkAck(InputStream in) throws IOException {
int b = in.read();
// b may be 0 for success,
// 1 for error,
// 2 for fatal error,
// -1
if (b == 1 || b == 2) {
StringBuilder sb = new StringBuilder();
int c;
do {
c = in.read();
sb.append((char) c);
} while (c != '\n');
if (b == 1) { // error
System.out.print(sb.toString());
}
if (b == 2) { // fatal error
System.out.print(sb.toString());
}
}
return b;
}
static String inputStreamAsString(InputStream stream) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
StringBuilder sb = new StringBuilder();
try {
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
} finally {
br.close();
}
return sb.toString();
}
public String getPassphrase() {
System.out.println("-->getPassphrase");
throw new UnsupportedOperationException("Not supported yet.");
}
public String getPassword() {
System.out.println("-->getPassword");
return remotePass;
}
public boolean promptPassword(String string) {
System.out.println("-->promptPassword");
return true;
}
public boolean promptPassphrase(String string) {
System.out.println("-->promptPassphrase");
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean promptYesNo(String string) {
System.out.println("-->promptYesNo");
return true;
}
public void showMessage(String string) {
System.out.println("-->showMessage");
throw new UnsupportedOperationException("Not supported yet.");
}
private String join(List<String> l) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < l.size(); i++) {
sb.append(l.get(i)).append(" ");
}
return sb.toString().trim();
}
public String[] promptKeyboardInteractive(String string, String string1, String string2, String[] strings, boolean[] blns) {
return null;
}
public static class MyLogger implements com.jcraft.jsch.Logger {
static Map<Integer, String> name = new java.util.HashMap<Integer, String>();
static {
name.put(new Integer(DEBUG), "DEBUG: ");
name.put(new Integer(INFO), "INFO: ");
name.put(new Integer(WARN), "WARN: ");
name.put(new Integer(ERROR), "ERROR: ");
name.put(new Integer(FATAL), "FATAL: ");
}
public boolean isEnabled(int level) {
return true;
}
public void log(int level, String message) {
// System.err.print(name.get(new Integer(level)));
// System.err.println(message);
}
}
}