/******************************************************************************* * Copyright (c) 2011 GigaSpaces Technologies Ltd. All rights reserved * * 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.esc.driver.provisioning.jclouds; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; import org.cloudifysource.dsl.utils.IPUtils; import org.cloudifysource.esc.driver.provisioning.CloudProvisioningException; import org.openspaces.admin.Admin; import org.openspaces.admin.gsa.GridServiceAgent; import org.openspaces.admin.gsm.GridServiceManager; import org.openspaces.admin.pu.ProcessingUnit; import org.openspaces.admin.pu.ProcessingUnitAlreadyDeployedException; 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 com.j_spaces.kernel.Environment; public class ManagementWebServiceInstaller { private static final String TIMEOUT_ERROR_MESSAGE = "operation timed out waiting for the rest service to start"; private final static Logger logger = Logger.getLogger(ConditionLatch.class.getName()); private Admin admin; private boolean verbose; private long progressInSeconds; private int memoryInMB; private int port; private File warFile; private String serviceName; private String zone; private static final int RESERVED_MEMORY_IN_MB = 256; public static final String MANAGEMENT_APPLICATION_NAME = "management"; public void setProgress(final int progress, final TimeUnit timeunit) { this.progressInSeconds = timeunit.toSeconds(progress); } public void setAdmin(final Admin admin) { this.admin = admin; } public void setVerbose(final boolean verbose) { this.verbose = verbose; } public void setMemory(final long memory, final MemoryUnit unit) { this.memoryInMB = (int) unit.toMegaBytes(memory); } public void setPort(final int port) { this.port = port; } public void setWarFile(final File warFile) { this.warFile = warFile; } public void setServiceName(final String serviceName) { this.serviceName = serviceName; } public void setManagementZone(final String zone) { this.zone = zone; } public void install() throws TimeoutException, InterruptedException, CloudProvisioningException, ProcessingUnitAlreadyDeployedException { if (zone == null) { throw new IllegalStateException("Management services must be installed on management zone"); } final ElasticStatelessProcessingUnitDeployment deployment = new ElasticStatelessProcessingUnitDeployment(getGSFile(warFile)) .memoryCapacityPerContainer(memoryInMB, MemoryUnit.MEGABYTES) .name(serviceName) // All PUs on this role share the same machine. Machines // are identified by zone. .sharedMachineProvisioning("public", new DiscoveredMachineProvisioningConfigurer().addGridServiceAgentZone(zone) .reservedMemoryCapacityPerMachine(RESERVED_MEMORY_IN_MB, MemoryUnit.MEGABYTES).create()) // Eager scale (1 container per machine per PU) .scale(new EagerScaleConfigurer().atMostOneContainerPerMachine().create()); for (final Entry<Object, Object> prop : getContextProperties().entrySet()) { deployment.addContextProperty(prop.getKey().toString(), prop.getValue().toString()); } getGridServiceManager().deploy(deployment); } private GridServiceManager getGridServiceManager() throws CloudProvisioningException { final Iterator<GridServiceManager> it = admin.getGridServiceManagers().iterator(); if (it.hasNext()) { return it.next(); } throw new CloudProvisioningException("No Grid Service Manager found to deploy " + serviceName); } public URL waitForProcessingUnitInstance(final GridServiceAgent agent, final long timeout, final TimeUnit timeunit) throws InterruptedException, TimeoutException, CloudProvisioningException { createConditionLatch(timeout, timeunit).waitFor(new ConditionLatch.Predicate() { @Override public boolean isDone() throws CloudProvisioningException, InterruptedException { logger.info("Waiting for " + serviceName + " service."); final ProcessingUnit pu = getProcessingUnit(); boolean isDone = false; if (pu != null) { for (final ProcessingUnitInstance instance : pu) { if (agent.equals(instance.getGridServiceContainer().getGridServiceAgent())) { isDone = true; break; } } } return isDone; } }); final URL url = getWebProcessingUnitURL(agent, getProcessingUnit()); if (logger.isLoggable(Level.INFO)) { final String serviceNameCapital = new StringBuilder(serviceName).replace(0, 1, serviceName.substring(0, 1).toUpperCase()).toString(); logger.info(serviceNameCapital + " service is available at: " + url); } return url; } private Properties getContextProperties() { final Properties props = new Properties(); props.setProperty("com.gs.application", MANAGEMENT_APPLICATION_NAME); props.setProperty("web.port", String.valueOf(port)); props.setProperty("web.context", "/"); props.setProperty("web.context.unique", "true"); return props; } public void waitForManagers(final long timeout, final TimeUnit timeunit) throws InterruptedException, TimeoutException, CloudProvisioningException { createConditionLatch(timeout, timeunit).waitFor(new ConditionLatch.Predicate() { @Override public boolean isDone() throws CloudProvisioningException, InterruptedException { boolean isDone = true; if (0 == admin.getGridServiceManagers().getSize()) { isDone = false; if (verbose) { logger.info("Waiting for Grid Service Manager"); } } if (admin.getElasticServiceManagers().getSize() == 0) { isDone = false; if (verbose) { logger.info("Waiting for Elastic Service Manager"); } } if (!isDone && !verbose) { logger.info("Waiting for Cloudify management processes"); } return isDone; } }); admin.getGridServiceManagers().waitForAtLeastOne(); } private ConditionLatch createConditionLatch(final long timeout, final TimeUnit timeunit) { return new ConditionLatch().timeout(timeout, timeunit).pollingInterval(progressInSeconds, TimeUnit.SECONDS).timeoutErrorMessage(TIMEOUT_ERROR_MESSAGE).verbose(verbose); } private ProcessingUnit getProcessingUnit() { return admin.getProcessingUnits().getProcessingUnit(serviceName); } public static URL getWebProcessingUnitURL(final GridServiceAgent agent, final ProcessingUnit pu) { ProcessingUnitInstance pui = null; for (final ProcessingUnitInstance instance : pu.getInstances()) { if (instance.getGridServiceContainer() != null && instance.getGridServiceContainer().getGridServiceAgent() != null && instance.getGridServiceContainer().getGridServiceAgent().equals(agent)) { pui = instance; } } if (pui == null) { throw new IllegalStateException("Failed finding " + pu.getName() + " on " + agent.getMachine().getHostAddress()); } final Map<String, ServiceDetails> alldetails = pui.getServiceDetailsByServiceId(); String protocol = IPUtils.getRestProtocol(); final ServiceDetails details = alldetails.get("jee-container"); final String host = details.getAttributes().get("host").toString(); final int port = Integer.parseInt(details.getAttributes().get("port").toString()); final String ctx = details.getAttributes().get("context-path").toString(); try { return new URL(protocol, host, port, ctx); } catch (final MalformedURLException e) { // this is a bug since we formed the URL correctly throw new IllegalStateException(e); } } public static File getGSFile(File warFile) { if (!warFile.isAbsolute()) { warFile = new File(Environment.getHomeDirectory(), warFile.getPath()); } return warFile; } }