blob: 1cdf5cf169c3b7c6ded492618879ed1ce8bed141 [file] [log] [blame]
/*
* Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
/**
* AdminBaseDevTest is a base class for administration CLI dev tests.
*
* @author Byron Nevins
* @author tmueller
*/
package admin;
import com.sun.appserv.test.BaseDevTest;
import java.io.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.SortedSet;
import java.util.TreeSet;
import static admin.Constants.*;
import javax.xml.namespace.QName;
public abstract class AdminBaseDevTest extends BaseDevTest implements Runnable {
static enum PasswordType {
SSH_PASS, KEY_PASS, ALIAS_PASS
};
@Override
protected final void writeFailure() {
// writes to stdout
super.writeFailure();
AsadminReturn ret = getLastAsadminReturn();
// put the information right into the CLI log. Makes it much easier
// to figure out failures.
if (ret != null) {
TestUtils.writeErrorToDebugLog(ret);
}
// byron nevins, June 2013. We need an easy way to see if there were
// ANY errors at all
TestUtils.setErrorFile();
}
protected AdminBaseDevTest() {
boolean verbose = false;
try {
verbose = Boolean.parseBoolean(System.getProperty("verbose"));
}
catch (Exception e) {
}
setVerbose(verbose);
if (!verbose) {
System.out.println("##### Non-Verbose: Only Failures Are Printed #####");
}
}
// Byron Says:
// let's make this an abstract method someday when we have time to change
// all the test classes
public void subrun() {
// all subclasses someday should have this method which is called by run()
// the subclass should call run() which will help with housekeeping.
// I'm not enforcing yet because I don't have time to change all the
// classes! 10/12/11
// do nothing.
}
@Override
public File getGlassFishHome() {
return TestEnv.getGlassFishHome();
}
// Allow old-style and new-style simultaneously. But prefer the latter.
@Override
public File getDASDomainDir() {
return getDASDomainDir("domain1");
}
File getDASDomainDir(String domainName) {
File f = null;
if (isHadas())
f = new File(DOMAINS_DIR, domainName + "/server");
else
f = new File(DOMAINS_DIR, domainName);
if (!f.exists())
report(false, "Domain Directory does not exist: " + f);
return f;
}
@Override
public File getDASDomainXML() {
return TestEnv.getDomainXml();
}
File getDASDomainXML(String domainName) {
return TestEnv.getDomainXml(domainName);
}
@Override
public Object evalXPath(String expr, QName ret) {
return evalXPath(expr, getDASDomainXML(), ret);
}
@Override
public final void run() {
System.out.println(getTestDescription());
System.out.println(getTestName());
subrun();
stat.printSummary();
}
@Override
public String getTestName() {
return this.getClass().getName();
}
// convenience method
static boolean isHadas() {
return TestEnv.isHadas();
}
public static File getLogFile(File installDir, String domainName) {
if (isHadas()) {
return new File(installDir, "domains/" + domainName + "/server/logs/server.log");
}
else {
return new File(installDir, "domains/" + domainName + "/logs/server.log");
}
}
public void report(boolean success, String name) {
// WBN ==> sometimes I like it in this order!
report(name, success);
}
@Override
public void report(String name, boolean success) {
// bnevins june 6 2010
// crazy base class uses a Map to store these reports. If you use
// the same name > 1 time they are ignored and thrown away!!!
// I went with this outrageous kludge because (1) it is just tests
// and (2) there are tens of thousands of other files in this harness!!!
// another issue is hacking off strings after a space. Makes no sense to me!!
if (!success) {
int x = 5; // a place to hang a breakpoint when debugging!!
}
writeTimestamp(name, success);
if (name.length() > MAX_LENGTH - 3) {
name = name.substring(0, MAX_LENGTH - 3);
}
String name2 = name.replace(' ', '_');
if (!name2.equals(name)) {
name = name2; // don't foul logic below!
}
int i = 0;
while (reportNames.add(name2) == false) {
name2 = name + i++;
}
if (!name2.equals(name)) {
write("Duplicate name found (" + name
+ ") and replaced with: " + name2);
}
int numpads = 60 - name2.length();
if (numpads > 0) {
name2 += DASHES.substring(0, numpads);
}
super.report(name2, success);
if (!success) {
writeFailure();
}
}
@Override
public void report(String step, AsadminReturn ret) {
report(step, ret.returnValue);
}
protected void startDomain(String domainname) {
report(getTestName() + "-start-domain" + startstops++,
asadmin("start-domain", domainname));
}
protected void startDomain() {
report(getTestName() + "-start-def-domain" + startstops++,
asadmin("start-domain"));
}
protected void startDomainDebug() {
report(getTestName() + "-start-def-domain" + startstops++,
asadmin("start-domain", "--debug"));
}
protected void stopDomain(String domainname) {
report(getTestName() + "-stop-domain" + startstops++,
asadmin("stop-domain", domainname));
}
protected void stopDomain() {
report(getTestName() + "-stop-def-domain" + startstops++,
asadmin("stop-domain"));
}
protected final boolean verifyNoClusters() {
AsadminReturn ret = asadminWithOutput("list-clusters");
String s = (ret.out == null) ? "" : ret.out.trim();
s = s.toLowerCase();
return s.endsWith("list-clusters") || s.indexOf("nothing to list") >= 0;
}
protected final boolean verifyNoInstances() {
AsadminReturn ret = asadminWithOutput("list-instances");
String s = (ret.out == null) ? "" : ret.out.trim();
return s.toLowerCase().indexOf("nothing to list") >= 0;
}
/*
* Returns true if String b contains String a.
*/
protected static boolean matchString(String a, String b) {
return b.indexOf(a) != -1;
}
static String getURL(String urlstr) {
try {
URL u = new URL(urlstr);
URLConnection urlc = u.openConnection();
BufferedReader ir = new BufferedReader(new InputStreamReader(urlc.getInputStream(),
"ISO-8859-1"));
StringWriter ow = new StringWriter();
String line;
while ((line = ir.readLine()) != null) {
ow.write(line);
ow.write("\n");
}
ir.close();
ow.close();
return ow.getBuffer().toString();
}
catch (IOException ex) {
printf("unable to fetch URL:" + urlstr + ", reason: " + ex.getMessage());
return "";
}
}
static void printf(String fmt, Object... args) {
if (DEBUG) {
System.out.printf("**** DEBUG MESSAGE **** " + fmt + "\n", args);
}
}
private final SortedSet<String> reportNames = new TreeSet<String>();
private int startstops = 0;
protected final static boolean DEBUG;
protected final static boolean isHudson = Boolean.parseBoolean(System.getenv("HUDSON"));
static {
String name = System.getProperty("user.name");
if (name != null && name.equals("bnevins")) {
DEBUG = true;
}
else if (isHudson) {
DEBUG = true;
}
else if (Boolean.parseBoolean(System.getenv("AS_DEBUG"))) {
DEBUG = true;
}
else {
DEBUG = false;
}
}
String generateInstanceName() {
String s = "" + System.currentTimeMillis();
s = s.substring(4, 10);
return "in_" + s;
}
String generateClusterName() {
String s = "" + System.currentTimeMillis();
s = s.substring(4, 10);
return "cl_" + s;
}
String get(String what) {
// note that the returned string is full of junk -- namely the HUGE asadmin
// command is prepended to the output.
// the "get" key will appear TWICE!!!!!! Once for the echo of the command itself
// and once for the output of the command.
AsadminReturn ret = asadminWithOutput("get", what);
if (!ret.returnValue) {
return null;
}
int index = ret.outAndErr.lastIndexOf(what);
int len = ret.outAndErr.length();
if (index < 0 || len - index <= 2) {
return null;
}
// e.g. "asadmin blah foo=xyz len==20, index==13, start at index=17
// which is index+lenofget-string+1
int valueIndex = index + what.length() + 1;
return ret.outAndErr.substring(index + what.length() + 1).trim();
}
public final boolean doesGetMatch(String what, String match) {
String ret = get(what);
if (!ok(match) && !ok(ret)) {
return true;
}
if (!ok(match) || !ok(ret)) {
return false;
}
return (match.equals(ret));
}
/**
* returns true if there is anything in the config that matches. returns
* false if there is no such thing
*
* @param what
* @return
*/
public final boolean doesGetMatch(String what) {
AsadminReturn ret = asadminWithOutput("get", what);
if (!ret.returnValue) {
return false;
}
if (ret.err != null && ret.err.length() > 1) {
return false;
}
return ret.out != null && ret.out.indexOf("=") >= 0;
}
public static void runFakeServerDaemon(int port) {
Thread t = new Thread(new FakeServer(port), "FakeServerListeningOn: " + port);
t.setDaemon(true);
t.start();
}
/**
*
* typical output as og 6/6/10
* C:\glassfishv3\glassfish\nodeagents\vaio>asadmin list-instances in_879669
* not running i20 running
*/
public boolean isInstanceRunning(String iname) {
AsadminReturn ret = asadminWithOutput("list-instances");
String[] lines = ret.out.split("[\r\n]");
// beware! The echo'd command can have a pathwith the instance name embedded,
// innocently in it. THis happened on a Hudson build which had a directory named
// makati1 in it!!
// So now we throw away the echo'd command line if we see it (just in case we turn
// echoing off later)
for (String line : lines) {
if (line.indexOf("list-instances") >= 0) {
continue;
}
if (line.indexOf(iname) >= 0) {
printf("Line from list-instances = " + line);
return line.indexOf(" running") >= 0;
}
}
return false;
}
public boolean isClusterRunning(String cname) {
AsadminReturn ret = asadminWithOutput("list-clusters");
String[] lines = ret.out.split("[\r\n]");
for (String line : lines) {
if (line.indexOf(cname) >= 0) {
printf("Line from list-clusters = " + line);
return line.indexOf(cname + " running") >= 0;
}
}
return false;
}
public boolean isClusterPartiallyRunning(String cname) {
AsadminReturn ret = asadminWithOutput("list-clusters");
String[] lines = ret.out.split("[\r\n]");
for (String line : lines) {
if (line.indexOf(cname) >= 0) {
printf("Line from list-clusters = " + line);
return line.indexOf(cname + " partially running") >= 0;
}
}
return false;
}
/*
* Delete the directories for a local node (since delete-node-* doesn't do
* this
*/
public boolean deleteNodeDirectory(String node) {
return deleteDirectory(new File(new File(getGlassFishHome(), "nodes"), node));
}
public boolean deleteDirectory(File path) {
if (path.exists()) {
File[] files = path.listFiles();
for (File f : files) {
if (f.isDirectory()) {
deleteDirectory(f);
}
else {
f.delete();
}
}
}
return (path.delete());
}
/**
* Add a password to the asadmin password file used by the test.
*
* @param value Password to use
* @param passType SSH_PASS if you are setting ssh password. KEY_PASS if you
* are setting encryption key
*/
void addPassword(String value, PasswordType passType) {
BufferedWriter out = null;
if (value == null) {
value = "";
}
try {
final File f = new File(pFile);
out = new BufferedWriter(new FileWriter(f, true));
out.newLine();
switch (passType) {
case SSH_PASS:
out.write("AS_ADMIN_SSHPASSWORD=" + value);
break;
case KEY_PASS:
out.write("AS_ADMIN_SSHKEYPASSPHRASE=" + value);
break;
case ALIAS_PASS:
out.write("AS_ADMIN_ALIASPASSWORD=" + value);
break;
default:
//do nothing
}
}
catch (IOException ioe) {
//ignore
}
finally {
try {
if (out != null) {
out.flush();
out.close();
}
}
catch (final Exception ignore) {
}
}
return;
}
/**
* Remove SSH related passwords from the asadmin password file id == "SSH"
* or "DCOM"
*/
void removePasswords(String id) {
final File f = new File(pFile);
final File tempFile = new File(tmpFile);
BufferedReader reader = null;
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(tempFile));
reader = new BufferedReader(new FileReader(f));
String currentLine;
while ((currentLine = reader.readLine()) != null && !currentLine.trim().isEmpty()) {
if (currentLine.trim().startsWith("AS_ADMIN_" + id)) {
continue;
}
writer.write(currentLine);
writer.newLine();
}
reader.close();
writer.close();
//On Windows, rename will fail if destination file already exists
if (!f.delete()) {
System.out.println("Failed to delete original file");
}
if (!tempFile.renameTo(f)) {
System.out.println("Failed to restore password file.");
}
}
catch (IOException ioe) {
//ignore
}
finally {
try {
if (reader != null) {
reader.close();
}
if (writer != null) {
writer.close();
}
}
catch (final Exception ignore) {
}
}
return;
}
final boolean ok(String s) {
return s != null && s.length() > 0;
}
// bnevins - horribly inefficient but we are guaranteeing to see contents when exited abruptly.
// It can't possibly take all that long for a few thousand calss - right?
// If a problem it can be tuned easily.
// this will give a rough idea of the time spent for every report call
private static void writeTimestamp(String s, boolean b) {
BufferedWriter out = null;
long prevTime = lastReportTime;
lastReportTime = System.currentTimeMillis();
long elapsed = prevTime == 0 ? 0 : lastReportTime - prevTime;
try {
out = new BufferedWriter(new FileWriter(TIMESTAMP_FILE, true));
out.write("" + elapsed + "ms " + b + " [" + s + "]");
}
catch (IOException e) {
// It is just a debug file.
}
finally {
if (out != null) {
try {
out.write("\n");
out.close();
}
catch (Exception e) {
// ignore
}
}
}
}
private static final File TIMESTAMP_FILE = new File("timestamps.out").getAbsoluteFile();
private final File GF_HOME = getGlassFishHome();
private final File DOMAINS_DIR = new File(GF_HOME, "domains");
private static long lastReportTime = 0;
private static final int MAX_LENGTH = 101;
private static final String DASHES =
"------------------------------------------------------------------------------------------------------------------------------";
}