Drop ping/list discovery, WinRM scripts, and heavy Java probing so only KnownContainers + MBean restart remain. Co-authored-by: Cursor <cursoragent@cursor.com>
296 lines
9.2 KiB
Java
296 lines
9.2 KiB
Java
import java.lang.reflect.Method;
|
|
import java.util.Hashtable;
|
|
|
|
import javax.management.ObjectName;
|
|
|
|
/**
|
|
* Minimaler Sonic-Restart (wie SMC): JMSConnectorClient + MBean stop/restart.
|
|
* Compile: javac --release 8 SonicMfContainerTool.java
|
|
*/
|
|
public final class SonicMfContainerTool
|
|
{
|
|
public static final String TOOL_VERSION = "2026-07-24d-restart-only";
|
|
|
|
public static void main(String[] args)
|
|
{
|
|
info("ToolVersion=" + TOOL_VERSION);
|
|
try
|
|
{
|
|
Args a = Args.parse(args);
|
|
if (!"restart".equals(a.command))
|
|
{
|
|
fail("Usage: SonicMfContainerTool restart --domain D --url U --user U --container C [--timeout SEC]");
|
|
return;
|
|
}
|
|
if (isBlank(a.domain) || isBlank(a.url) || isBlank(a.user) || isBlank(a.container))
|
|
{
|
|
fail("domain, url, user und container sind Pflicht.");
|
|
return;
|
|
}
|
|
|
|
long timeoutMs = Math.max(5_000L, a.timeoutSec * 1000L);
|
|
Object connector = connect(a.url, a.user, a.password, timeoutMs);
|
|
try
|
|
{
|
|
restart(connector, a.domain, a.container);
|
|
}
|
|
finally
|
|
{
|
|
try
|
|
{
|
|
connector.getClass().getMethod("disconnect").invoke(connector);
|
|
}
|
|
catch (Exception ignore)
|
|
{
|
|
/* ignore */
|
|
}
|
|
}
|
|
}
|
|
catch (Throwable t)
|
|
{
|
|
fail(rootOf(t).getClass().getName() + ": " + rootOf(t).getMessage());
|
|
}
|
|
}
|
|
|
|
private static Object connect(String url, String user, String password, long timeoutMs) throws Exception
|
|
{
|
|
Hashtable env = new Hashtable();
|
|
env.put("ConnectionURLs", url);
|
|
env.put("DefaultUser", user);
|
|
env.put("DefaultPassword", password == null ? "" : password);
|
|
|
|
Class addressCl = Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorAddress");
|
|
Object address = addressCl.getConstructor(new Class[] { Hashtable.class }).newInstance(new Object[] { env });
|
|
|
|
Class clientCl = Class.forName("com.sonicsw.mf.jmx.client.JMSConnectorClient");
|
|
Object connector = clientCl.getConstructor(new Class[] {}).newInstance(new Object[] {});
|
|
trySetTimeout(connector, timeoutMs);
|
|
|
|
Method connect = findConnect(clientCl);
|
|
if (connect == null)
|
|
{
|
|
fail("JMSConnectorClient.connect(...) nicht gefunden.");
|
|
return null;
|
|
}
|
|
|
|
Class[] pts = connect.getParameterTypes();
|
|
if (pts.length == 2)
|
|
{
|
|
connect.invoke(connector, new Object[] { address, boxTimeout(pts[1], timeoutMs) });
|
|
}
|
|
else
|
|
{
|
|
connect.invoke(connector, new Object[] { address });
|
|
}
|
|
return connector;
|
|
}
|
|
|
|
private static void restart(Object connector, String domain, String container) throws Exception
|
|
{
|
|
String shortName = shortContainer(container);
|
|
ObjectName on = new ObjectName(domain + "." + shortName + ":ID=AGENT");
|
|
info("ObjectName=" + on);
|
|
|
|
StringBuffer attempts = new StringBuffer();
|
|
String[] ops = new String[] { "stop", "restart" };
|
|
for (int i = 0; i < ops.length; i++)
|
|
{
|
|
String op = ops[i];
|
|
try
|
|
{
|
|
info("Trying MBean.invoke(" + op + ")");
|
|
invokeNoArgs(connector, on, op);
|
|
okRestart("MBean." + op, shortName, domain);
|
|
return;
|
|
}
|
|
catch (Throwable t)
|
|
{
|
|
Throwable root = rootOf(t);
|
|
String line = "MBean." + op + " => " + root.getClass().getName() + ": " + root.getMessage();
|
|
warn(line);
|
|
attempts.append(line).append('\n');
|
|
if ("stop".equals(op) && looksLikeStopSideEffect(root))
|
|
{
|
|
okRestart("MBean.stop(side-effect)", shortName, domain);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
fail("Neustart fehlgeschlagen. ToolVersion=" + TOOL_VERSION + "\nAttempts:\n" + attempts.toString());
|
|
}
|
|
|
|
private static void invokeNoArgs(Object connector, ObjectName on, String op) throws Exception
|
|
{
|
|
Method invoke = connector.getClass().getMethod("invoke", new Class[] {
|
|
ObjectName.class, String.class, Object[].class, String[].class
|
|
});
|
|
invoke.invoke(connector, new Object[] { on, op, new Object[0], new String[0] });
|
|
}
|
|
|
|
private static boolean looksLikeStopSideEffect(Throwable root)
|
|
{
|
|
if (root == null || root.getMessage() == null)
|
|
{
|
|
return false;
|
|
}
|
|
String m = root.getMessage().toLowerCase();
|
|
return m.indexOf("disconnect") >= 0
|
|
|| m.indexOf("closed") >= 0
|
|
|| m.indexOf("not connected") >= 0
|
|
|| m.indexOf("connection lost") >= 0;
|
|
}
|
|
|
|
private static void okRestart(String method, String shortName, String domain)
|
|
{
|
|
System.out.println("OK:RestartInvoked method=" + method
|
|
+ " container=" + shortName + " domain=" + domain
|
|
+ " tool=" + TOOL_VERSION);
|
|
System.out.flush();
|
|
}
|
|
|
|
private static Method findConnect(Class clientCl)
|
|
{
|
|
Method[] methods = clientCl.getMethods();
|
|
Method best = null;
|
|
for (int i = 0; i < methods.length; i++)
|
|
{
|
|
Method m = methods[i];
|
|
if (!"connect".equals(m.getName()))
|
|
{
|
|
continue;
|
|
}
|
|
Class[] pts = m.getParameterTypes();
|
|
if (pts.length == 1 || pts.length == 2)
|
|
{
|
|
best = m;
|
|
if (pts.length == 2)
|
|
{
|
|
return m;
|
|
}
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
|
|
private static void trySetTimeout(Object connector, long timeoutMs)
|
|
{
|
|
try
|
|
{
|
|
connector.getClass().getMethod("setTimeout", new Class[] { Long.TYPE })
|
|
.invoke(connector, new Object[] { Long.valueOf(timeoutMs) });
|
|
}
|
|
catch (Exception ignore)
|
|
{
|
|
try
|
|
{
|
|
connector.getClass().getMethod("setRequestTimeout", new Class[] { Long.TYPE })
|
|
.invoke(connector, new Object[] { Long.valueOf(timeoutMs) });
|
|
}
|
|
catch (Exception ignore2)
|
|
{
|
|
/* optional */
|
|
}
|
|
}
|
|
}
|
|
|
|
private static Object boxTimeout(Class type, long timeoutMs)
|
|
{
|
|
if (type == Integer.TYPE || type == Integer.class)
|
|
{
|
|
return Integer.valueOf((int) Math.min(Integer.MAX_VALUE, timeoutMs));
|
|
}
|
|
return Long.valueOf(timeoutMs);
|
|
}
|
|
|
|
private static String shortContainer(String container)
|
|
{
|
|
String c = container.trim();
|
|
int dot = c.lastIndexOf('.');
|
|
return dot >= 0 ? c.substring(dot + 1) : c;
|
|
}
|
|
|
|
private static Throwable rootOf(Throwable t)
|
|
{
|
|
Throwable cur = t;
|
|
while (cur.getCause() != null && cur.getCause() != cur)
|
|
{
|
|
cur = cur.getCause();
|
|
}
|
|
return cur;
|
|
}
|
|
|
|
private static boolean isBlank(String s)
|
|
{
|
|
return s == null || s.trim().length() == 0;
|
|
}
|
|
|
|
private static void info(String msg)
|
|
{
|
|
System.out.println("INFO:" + msg);
|
|
System.out.flush();
|
|
}
|
|
|
|
private static void warn(String msg)
|
|
{
|
|
System.out.println("WARN:" + msg);
|
|
System.out.flush();
|
|
}
|
|
|
|
private static void fail(String msg)
|
|
{
|
|
System.err.println("ERROR:" + msg);
|
|
System.err.flush();
|
|
System.exit(1);
|
|
}
|
|
|
|
private static final class Args
|
|
{
|
|
String command;
|
|
String domain;
|
|
String url;
|
|
String user;
|
|
String password;
|
|
String container;
|
|
int timeoutSec = 120;
|
|
|
|
static Args parse(String[] args)
|
|
{
|
|
Args a = new Args();
|
|
if (args == null || args.length == 0)
|
|
{
|
|
return a;
|
|
}
|
|
a.command = args[0];
|
|
for (int i = 1; i < args.length; i++)
|
|
{
|
|
String k = args[i];
|
|
String v = (i + 1 < args.length) ? args[i + 1] : null;
|
|
if ("--domain".equals(k) && v != null) { a.domain = v; i++; }
|
|
else if ("--url".equals(k) && v != null) { a.url = v; i++; }
|
|
else if ("--user".equals(k) && v != null) { a.user = v; i++; }
|
|
else if ("--password".equals(k) && v != null) { a.password = v; i++; }
|
|
else if ("--container".equals(k) && v != null) { a.container = v; i++; }
|
|
else if ("--timeout".equals(k) && v != null)
|
|
{
|
|
try { a.timeoutSec = Integer.parseInt(v); } catch (Exception ignore) { /* keep default */ }
|
|
i++;
|
|
}
|
|
}
|
|
if (isBlank(a.password))
|
|
{
|
|
String env = System.getenv("ESB_SONIC_PASSWORD");
|
|
if (!isBlank(env))
|
|
{
|
|
a.password = env;
|
|
}
|
|
}
|
|
return a;
|
|
}
|
|
}
|
|
|
|
private SonicMfContainerTool()
|
|
{
|
|
}
|
|
}
|