/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.ignite.testframework.junits.multijvm;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import com.thoughtworks.xstream.XStream;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.Ignition;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.processors.cache.GridCacheAbstractFullApiSelfTest;
import org.apache.ignite.internal.util.GridJavaProcess;
import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.marshaller.Marshaller;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.testframework.junits.IgniteTestResources;
import sun.jvmstat.monitor.HostIdentifier;
import sun.jvmstat.monitor.MonitoredHost;
import sun.jvmstat.monitor.MonitoredVm;
import sun.jvmstat.monitor.MonitoredVmUtil;
import sun.jvmstat.monitor.VmIdentifier;
/**
* Run ignite node.
*/
public class IgniteNodeRunner {
/** */
private static final String IGNITE_CONFIGURATION_FILE = System.getProperty("java.io.tmpdir") +
File.separator + "igniteConfiguration.tmp_";
/** */
private static volatile Ignite ignite;
/**
* Starts {@link Ignite} instance accorging to given arguments.
*
* @param args Arguments.
* @throws Exception If failed.
*/
public static void main(String[] args) throws Exception {
X.println(GridJavaProcess.PID_MSG_PREFIX + U.jvmPid());
X.println("Starting Ignite Node... Args=" + Arrays.toString(args));
IgniteConfiguration cfg = readCfgFromFileAndDeleteFile(args[0]);
ignite = Ignition.start(cfg);
}
/**
* @return Ignite instance started at main.
*/
public static IgniteEx startedInstance(){
return (IgniteEx)ignite;
}
/**
* @return <code>True</code> if there is ignite node started via {@link IgniteNodeRunner} at this JVM.
*/
public static boolean hasStartedInstance() {
return ignite != null;
}
/**
* Stores {@link IgniteConfiguration} to file as xml.
*
* @param cfg Ignite Configuration.
* @return A name of file where the configuration was stored.
* @throws IOException If failed.
* @see #readCfgFromFileAndDeleteFile(String)
*/
public static String storeToFile(IgniteConfiguration cfg, boolean resetDiscovery) throws IOException, IgniteCheckedException {
String fileName = IGNITE_CONFIGURATION_FILE + cfg.getNodeId();
storeToFile(cfg, fileName, true, resetDiscovery);
return fileName;
}
/**
* Stores {@link IgniteConfiguration} to file as xml.
*
* @param cfg Ignite Configuration.
* @param fileName A name of file where the configuration was stored.
* @param resetMarshaller Reset marshaller configuration to default.
* @param resetDiscovery Reset discovery configuration to default.
* @throws IOException If failed.
* @see #readCfgFromFileAndDeleteFile(String)
*/
public static void storeToFile(IgniteConfiguration cfg, String fileName,
boolean resetMarshaller,
boolean resetDiscovery) throws IOException, IgniteCheckedException {
try(OutputStream out = new BufferedOutputStream(new FileOutputStream(fileName))) {
IgniteConfiguration cfg0 = new IgniteConfiguration(cfg);
if (resetMarshaller)
cfg0.setMarshaller(null);
if (resetDiscovery)
cfg0.setDiscoverySpi(null);
cfg0.setWorkDirectory(U.defaultWorkDirectory());
cfg0.setMBeanServer(null);
cfg0.setGridLogger(null);
new XStream().toXML(cfg0, out);
}
}
/**
* Reads configuration from given file and delete the file after.
*
* @param fileName File name.
* @return Readed configuration.
* @throws IOException If failed.
* @see #storeToFile(IgniteConfiguration, boolean)
* @throws IgniteCheckedException On error.
*/
private static IgniteConfiguration readCfgFromFileAndDeleteFile(String fileName)
throws IOException, IgniteCheckedException {
try(BufferedReader cfgReader = new BufferedReader(new FileReader(fileName))) {
IgniteConfiguration cfg = (IgniteConfiguration)new XStream().fromXML(cfgReader);
if (cfg.getMarshaller() == null) {
Marshaller marsh = IgniteTestResources.getMarshaller();
cfg.setMarshaller(marsh);
}
X.println("Configured marshaller class: " + cfg.getMarshaller().getClass().getName());
if (cfg.getDiscoverySpi() == null) {
TcpDiscoverySpi disco = new TcpDiscoverySpi();
disco.setIpFinder(GridCacheAbstractFullApiSelfTest.LOCAL_IP_FINDER);
cfg.setDiscoverySpi(disco);
}
return cfg;
}
finally {
new File(fileName).delete();
}
}
/**
* Kill all Jvm runned by {#link IgniteNodeRunner}. Works based on jps command.
*
* @return List of killed process ids.
* @throws Exception If exception.
*/
public static List<Integer> killAll() throws Exception{
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(new HostIdentifier("localhost"));
Set<Integer> jvms = monitoredHost.activeVms();
List<Integer> res = new ArrayList<>();
for (Integer jvmId : jvms) {
try {
MonitoredVm vm = monitoredHost.getMonitoredVm(new VmIdentifier("//" + jvmId + "?mode=r"), 0);
if (IgniteNodeRunner.class.getName().equals(MonitoredVmUtil.mainClass(vm, true))) {
Process killProc = Runtime.getRuntime().exec(U.isWindows() ?
new String[] {"taskkill", "/pid", jvmId.toString(), "/f", "/t"} :
new String[] {"kill", "-9", jvmId.toString()});
killProc.waitFor();
res.add(jvmId);
}
}
catch (Exception e) {
// Print stack trace just for information.
X.printerrln("Could not kill IgniteNodeRunner java processes. Jvm pid = " + jvmId, e);
}
}
return res;
}
}