/** * 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 siebog.starter; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.util.Map; import java.util.logging.Logger; import org.jboss.as.controller.client.helpers.domain.DomainClient; import org.jboss.as.controller.client.helpers.domain.ServerIdentity; import org.jboss.as.controller.client.helpers.domain.ServerStatus; import org.wildfly.plugin.deployment.DeploymentExecutionException; import org.wildfly.plugin.deployment.DeploymentFailureException; import siebog.starter.Deployment; import siebog.starter.FileUtils; import siebog.starter.Global; import siebog.starter.NodeStarter; import siebog.starter.config.NodeConfig; /** * A helper class for starting Siebog / JBoss nodes. * * @author <a href="mailto:mitrovic.dejan@gmail.com">Dejan Mitrovic</a> */ public class NodeStarter { private static final Logger LOG = Logger.getLogger(NodeStarter.class.getName()); private NodeConfig config; // @formatter:off private final static String INTF_DEF = "" + "<interface name=\"management\"><inet-address value=\"${jboss.bind.address.management:ADDR}\" /></interface>" + "<interface name=\"public\"><inet-address value=\"${jboss.bind.address:ADDR}\" /></interface>" + "<interface name=\"unsecure\"><inet-address value=\"${jboss.bind.address.unsecure:ADDR}\" /></interface>"; private final static String SLAVE_SERVER_DEF = "" + "<server name=\"NAME\" group=\"xjaf2x-group\" auto-start=\"true\">" + " <socket-bindings port-offset=\"POFFSET\" />" + "</server>"; // @formatter:on public NodeStarter(NodeConfig config) { this.config = config; } public void start() { try { setupDomain(); setupLogging(); if (config.isSlave()) { startSlave(); } else { startMaster(); // TODO: check if already deployed deploy(config.getRootFolder(), Global.SIEBOG_MODULE); } } catch (DeploymentExecutionException | DeploymentFailureException | IOException ex) { throw new IllegalStateException("Error while starting node.", ex); } } public void setupDomain() throws IOException { String resDomain = FileUtils.read(NodeStarter.class.getResourceAsStream("profile.xml")); resDomain = resDomain.replace("${loglevel}", config.getLogLevel()); File domainFile = new File(config.getJBossHome(), "domain/configuration/domain.xml"); String domain = FileUtils.read(domainFile); int start = domain.indexOf("<profile name=\"full-ha\">"); int end = domain.indexOf("</profile>", start + 1) + "</profile>".length(); StringBuilder str = new StringBuilder(domain); str.replace(start, end, resDomain); // removeDeployments(str); FileUtils.write(domainFile, str.toString()); } @SuppressWarnings("unused") private void removeDeployments(StringBuilder str) { int a = str.lastIndexOf("<deployments>"); if (a > 0) { String end = "</deployments>"; int b = str.lastIndexOf(end); str.delete(a, b + end.length()); } File dataDir = new File(config.getJBossHome(), "domain/data/content"); if (dataDir.exists()) { dataDir.delete(); } } private void setupLogging() throws IOException { String logProps = FileUtils.read(NodeStarter.class .getResourceAsStream("logging.properties")); logProps = logProps.replace("${loglevel}", config.getLogLevel()); File logFile = new File(config.getJBossHome(), "domain/configuration/logging.properties"); FileUtils.write(logFile, logProps); } private void startMaster() throws IOException { LOG.info("Starting master node " + Global.MASTER_NAME + "@" + config.getAddress()); prepareHostMaster(); // @formatter:off String[] jbossArgs = { "-jboss-home", config.getJBossHome().getAbsolutePath(), "-mp", new File(config.getJBossHome(), "modules").getAbsolutePath(), "-jar", new File(config.getJBossHome(), "jboss-modules.jar").getAbsolutePath(), "--", "-server", "--", "--host-config=host-master.xml", "-Djboss.bind.address.management=" + config.getAddress() }; // @formatter:on org.jboss.as.process.Main.start(jbossArgs); waitForServer(config.getAddress(), Global.MASTER_NAME, "master"); } private void prepareHostMaster() throws IOException { String intfDef = INTF_DEF.replace("ADDR", config.getAddress()); String host = FileUtils.read("host-master.txt", 0); host = host.replace("<!-- interface-def -->", intfDef); File outFile = new File(config.getJBossHome(), "domain/configuration/host-master.xml"); FileUtils.write(outFile, host); } private void startSlave() throws IOException { final String ADDR = config.getAddress(); final String MASTER = config.getMasterAddr(); final String NAME = config.getSlaveName(); // + "@" + ADDR; final int portOffset = config.getPortOffset(); LOG.info(String.format("Starting slave node %s@%s, with %s@%s", NAME, ADDR, Global.MASTER_NAME, MASTER)); String hostSlave = FileUtils.read(NodeStarter.class.getResourceAsStream("host-slave.txt")); String intfDef = INTF_DEF.replace("ADDR", ADDR); hostSlave = hostSlave.replace("<!-- interface-def -->", intfDef); String serverDef = SLAVE_SERVER_DEF.replace("NAME", ADDR).replace("POFFSET", portOffset + ""); hostSlave = hostSlave.replace("<!-- server-def -->", serverDef); int nativePort = 9999; if (portOffset > 0) nativePort += portOffset; hostSlave = hostSlave.replace("NAT_PORT", nativePort + ""); hostSlave = hostSlave.replace("SL_NAME", "name=\"" + NAME + "\""); File hostConfig = new File(config.getJBossHome(), "domain/configuration/host-slave.xml"); FileUtils.write(hostConfig, hostSlave); // @formatter:off String[] jbossArgs = { "-jboss-home", config.getJBossHome().getAbsolutePath(), "-mp", new File(config.getJBossHome(), "modules").getAbsolutePath(), "-jar", new File(config.getJBossHome(), "jboss-modules.jar").getAbsolutePath(), "--", //"-Dorg.jboss.boot.log.file=" + jbossHome + "domain/log/host-controller.log", //"-Dlogging.configuration=file:" + jbossHome + "domain/configuration/logging.properties", "-server", "--", // "--host-config=host-slave.xml", "-Djboss.domain.master.address=" + MASTER, "-Djboss.bind.address=" + ADDR, "-Djboss.bind.address.management=" + ADDR }; // @formatter:on org.jboss.as.process.Main.start(jbossArgs); } private void waitForServer(String address, String serverName, String hostName) { try { InetAddress addr = InetAddress.getByName(address); ServerStatus status; int maxTries = 10; do { Thread.sleep(500); try (DomainClient client = DomainClient.Factory.create(addr, 9990)) { ServerIdentity id = new ServerIdentity(hostName, Global.GROUP, serverName); try { Map<ServerIdentity, ServerStatus> statuses = client.getServerStatuses(); status = statuses.get(id); } catch (RuntimeException e) { final Throwable cause = e.getCause(); if (cause != null && (cause instanceof IOException)) { if (--maxTries < 0) throw e; status = ServerStatus.STARTING; } else throw e; } } } while (status == ServerStatus.STARTING || status == ServerStatus.UNKNOWN); } catch (Throwable ex) { throw new IllegalStateException("Error while waiting for the server to start: " + ex.getMessage()); } } private void deploy(File root, String name) throws DeploymentExecutionException, DeploymentFailureException, IOException { final String appName = name + ".war"; File file = new File(root, appName); LOG.info("Deploying " + file.getCanonicalPath()); InetAddress addr = InetAddress.getByName(config.getAddress()); Deployment.deploy(addr, file, appName); } }