/******************************************************************************* * Copyright 2011 GigaSpaces Technologies Ltd * * 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. ******************************************************************************/ package org.cloudifysource.shell.commands; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteException; import org.apache.commons.exec.ExecuteResultHandler; import org.apache.commons.exec.ExecuteStreamHandler; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; import org.apache.felix.gogo.commands.CompleterValues; import org.openspaces.admin.Admin; import org.openspaces.admin.AdminFactory; import org.openspaces.admin.gsm.GridServiceManager; import org.openspaces.admin.pu.ProcessingUnit; import org.openspaces.admin.pu.ProcessingUnitInstance; import org.openspaces.admin.pu.elastic.ElasticStatelessProcessingUnitDeployment; import org.openspaces.admin.pu.elastic.config.DiscoveredMachineProvisioningConfigurer; import org.openspaces.admin.pu.elastic.config.EagerScaleConfigurer; import org.openspaces.core.util.MemoryUnit; import org.openspaces.pu.service.ServiceDetails; import org.cloudifysource.shell.AbstractAdminFacade; import org.cloudifysource.shell.AdminFacade; import org.cloudifysource.shell.Constants; import org.cloudifysource.shell.rest.ErrorStatusException; import org.cloudifysource.shell.rest.RestAdminFacade; import com.j_spaces.kernel.Environment; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import javax.jms.IllegalStateException; /** * @author rafi * @since 2.0.0 */ @Command(scope = "cloudify", name = "start-local-cloud", description = "starts a local cloud") public class StartLocalCloud extends AbstractGSCommand { private static final String LINUX_EXECUTABLE = "gs-agent.sh"; private static final String WINDOWS_EXECUTABLE = "cmd.exe";// /c // gs-agent.bat"; private static final String[] WINDOWS_PREFIX = { "/c", "gs-agent.bat" }; private static final String[] AGENT_PARAMETERS = { "gsa.global.esm", "1", "gsa.gsc", "0", "gsa.global.gsm", "1", "gsa.global.lus", "1" }; private static final String[] LINUX_SUFFIX = { ">", "/dev/null", "2>", "/dev/null" }; private static final String[] WINDOWS_SUFFIX = { ">", "NUL", "2>", "NUL" }; @Argument(index = 0, required = false, name = "groups", description = "The Lookup Group be used by the local cloud. Will default to the LOOKUPGROUPS environment variable if not specified") private String groups; @Override protected Object doExecute() throws ErrorStatusException { // TODO - scan for open ports - 8080, 8099 Admin admin = createAdmin(); boolean lusFound = admin.getLookupServices().waitFor(1, 2, TimeUnit.SECONDS); if (lusFound) { return getFormattedMessage("lus_already_running", Arrays.toString(admin.getGroups())); } // "gs-agent.bat gsa.global.esm 1 gsa.gsc 0 gsa.global.gsm 1 gsa.global.lus 1" try { startLocalAgent(admin); } catch (ExecuteException e) { logger.log(Level.SEVERE, "Failed to start local cloud agent", e); } catch (IOException e) { logger.log(Level.SEVERE, "Failed to start local cloud agent", e); } try { deployRestAdminServer(admin); } catch (IOException e) { logger.log(Level.SEVERE, "Failed to start REST Admin Server", e); } // connect to local rest server if (session != null) { this.adminFacade = (AbstractAdminFacade) session .get(Constants.ADMIN_FACADE); } else { this.adminFacade = new RestAdminFacade(); } adminFacade.connect(null, null, "http://localhost:8080/restful"); try { deployWebUI(admin); } catch (Exception e) { logger.log(Level.SEVERE, "Failed to start Web UI for local cloud", e); } return getFormattedMessage("local_cloud_started"); // TODO - add local // cloud messages } private void deployRestAdminServer(Admin admin) throws IOException { final String restFileName = "tools" + File.separator + "rest" + File.separator + "rest.war"; final File restFile = getGSFile(restFileName); final ElasticStatelessProcessingUnitDeployment deployment = new ElasticStatelessProcessingUnitDeployment( restFile) // .memoryCapacityPerContainer(externalProcessMemoryInMB, // MemoryUnit.MEGABYTES) .addCommandLineArgument("-Xmx" + 64 + "m") // .addCommandLineArgument("-Xms" + containerMemoryInMB + "m") .addContextProperty("com.gs.application", "management") .name("restful") // All PUs on this role share the same machine. Machines // are identified by zone. .sharedMachineProvisioning( "public", new DiscoveredMachineProvisioningConfigurer() .addGridServiceAgentZone("management") // .reservedMemoryCapacityPerMachine(reservedMemoryCapacityPerMachineInMB, // MemoryUnit.MEGABYTES) .create()) // Eager scale (1 container per machine per PU) .scale(new EagerScaleConfigurer() .atMostOneContainerPerMachine().create()); GridServiceManager gsm = admin.getGridServiceManagers() .waitForAtLeastOne(5, TimeUnit.SECONDS); if (gsm == null) { throw new java.lang.IllegalStateException( "Could not find a GSM in the local cloud"); } ProcessingUnit pu = gsm.deploy(deployment); boolean res = pu.waitFor(1, 30, TimeUnit.SECONDS); if (!res) { throw new java.lang.IllegalStateException( "REST Admin server did not deploy successfully"); } String url = getWebProcessingUnitURL(pu); System.out.println("REST Admin server is available at: " + url); } private String getWebProcessingUnitURL(ProcessingUnit pu) { ProcessingUnitInstance pui = pu.getInstances()[0]; Map<String, ServiceDetails> alldetails = pui .getServiceDetailsByServiceId(); ServiceDetails details = alldetails.get("jee-container"); String host = details.getAttributes().get("host").toString(); String port = details.getAttributes().get("port").toString(); String ctx = details.getAttributes().get("context-path").toString(); String url = "http://" + host + ":" + port + ctx; return url; } private void startLocalAgent(Admin admin) throws ExecuteException, IOException { File binDir = new File(Environment.getHomeDirectory(), "bin"); DefaultExecutor executor = new DefaultExecutor(); executor.setWorkingDirectory(binDir); CommandLine cmdLine = createCommandLine(); executor.setExitValue(0); executor.execute(cmdLine, new ExecuteResultHandler() { @Override public void onProcessFailed(ExecuteException e) { logger.log(Level.SEVERE, "Local Cloud Agent terminated unexpectedly", e); } @Override public void onProcessComplete(int arg0) { logger.fine("Local Cloud Agent terminated"); } }); boolean foundLus = admin.getLookupServices().waitFor(1, 1, TimeUnit.MINUTES); if (!foundLus) { throw new java.lang.IllegalStateException( "Local Cloud Lookup Service did not start!"); } } private CommandLine createCommandLine() { String os = System.getProperty("os.name"); logger.fine("os.name = " + os); if (os == null) { throw new java.lang.IllegalStateException( "The System Property variable 'os.name' was not set"); } os = os.toLowerCase(); CommandLine cmdLine = null; boolean isWindows = os.startsWith("win"); if (isWindows) { cmdLine = new CommandLine(WINDOWS_EXECUTABLE); for (String param : WINDOWS_PREFIX) { cmdLine.addArgument(param); } } else { cmdLine = new CommandLine(LINUX_EXECUTABLE); } for (String param : AGENT_PARAMETERS) { cmdLine.addArgument(param); } if (isWindows) { for (String param : WINDOWS_SUFFIX) { cmdLine.addArgument(param); } } else { for (String param : LINUX_SUFFIX) { cmdLine.addArgument(param); } } return cmdLine; } private void deployWebUI(Admin admin) throws Exception { final String webUIFileName = "tools" + File.separator + "gs-webui" + File.separator + "gs-webui-9.5.0-SNAPSHOT.war"; File webUIFile = getGSFile(webUIFileName); this.adminFacade.installElastic(webUIFile, "management", "web-ui", "web-ui", null); ProcessingUnit pu = admin.getProcessingUnits().waitFor("web-ui", 10, TimeUnit.SECONDS); if (pu == null) { throw new IllegalStateException( "Could not find 'web-ui' processing unit"); } boolean res = pu.waitFor(1, 30, TimeUnit.SECONDS); if (!res) { throw new java.lang.IllegalStateException( "Could not find instance of 'web-ui' processing unit"); } String url = getWebProcessingUnitURL(pu); System.out.println("Web UI is available at: " + url); } private File getGSFile(final String relativeFileName) throws FileNotFoundException, IOException { final String absoluteFileName = Environment.getHomeDirectory() + File.separator + relativeFileName; File file = new File(absoluteFileName); if (!file.exists()) { throw new FileNotFoundException("File: " + file + " was not found"); } if (!file.isFile()) { throw new IOException(file + " is not a file"); } return file; } private Admin createAdmin() { AdminFactory adminFactory = new AdminFactory(); adminFactory.useDaemonThreads(true); if (this.groups != null) { adminFactory.addGroups(groups); } Admin admin = adminFactory.createAdmin(); return admin; } public static void main(String[] args) throws ErrorStatusException { StartLocalCloud cmd = new StartLocalCloud(); cmd.doExecute(); } }