/******************************************************************************* * 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.shell.installer; import com.j_spaces.kernel.Environment; import org.cloudifysource.shell.AdminFacade; import org.cloudifysource.shell.ConditionLatch; import org.cloudifysource.shell.exceptions.CLIException; import org.openspaces.admin.Admin; import org.openspaces.admin.gsa.GridServiceAgent; import org.openspaces.admin.pu.ProcessingUnitAlreadyDeployedException; import org.openspaces.admin.pu.ProcessingUnitDeployment; import org.openspaces.admin.pu.dependency.ProcessingUnitDeploymentDependenciesConfigurer; import org.openspaces.admin.space.Space; import org.openspaces.admin.space.SpaceInstance; import org.openspaces.core.GigaSpace; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; import java.util.Properties; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * @author rafi, barakm * @since 2.0.0 * * Handles the installation of a management space * */ public class ManagementSpaceServiceInstaller extends AbstractManagementServiceInstaller { private boolean highlyAvailable; private GigaSpace gigaspace = null; private final List<LocalhostBootstrapperListener> eventsListenersList = new ArrayList<LocalhostBootstrapperListener>(); private boolean isLocalcloud; private String persistentStoragePath; /** * Sets the management space availability behavior. A highly-available space is a space that must always have a * backup instance, running on a separate machine. * * @param highlyAvailable * High-availability behavior (true - on, false - off) */ public void setHighlyAvailable(final boolean highlyAvailable) { this.highlyAvailable = highlyAvailable; } @Override protected Properties getContextProperties() { final Properties props = super.getContextProperties(); if (this.persistentStoragePath != null) { props.setProperty("space.storage.path", this.persistentStoragePath); } props.setProperty("space.name", this.serviceName); return props; } /** * Installs the management space with the configured settings. If a dependency on another PU is * set, the deployment will wait until at least 1 instance of that PU is available. * * @throws CLIException * Reporting a failure to get the Grid Service Manager (GSM) to install the service */ @Override public void install() throws ProcessingUnitAlreadyDeployedException, CLIException { try { if (agentZone == null) { throw new IllegalStateException("Management services must be installed on management zone"); } final File puFile = getManagementSpacePUFile(); final int numberOfBackups = highlyAvailable ? 1 : 0; final ProcessingUnitDeployment deployment = new ProcessingUnitDeployment(puFile) .name(serviceName) .addZone(serviceName) .maxInstancesPerMachine(1) .partitioned(1, numberOfBackups); for (final Entry<Object, Object> prop : getContextProperties().entrySet()) { deployment.setContextProperty(prop.getKey().toString(), prop.getValue().toString()); } for (final String requiredPUName : dependencies) { deployment.addDependencies(new ProcessingUnitDeploymentDependenciesConfigurer() .dependsOnMinimumNumberOfDeployedInstancesPerPartition(requiredPUName, 1).create()); } getGridServiceManager().deploy(deployment); } catch (final ProcessingUnitAlreadyDeployedException e) { if (isLocalcloud) { throw e; } // this is possible in a re-bootstrap scenario logger.warning("Deployment of management space failed because a Processing unit with the " + "same name already exists. If this error occured during recovery of management machines, " + "this error is normal and can be ignored."); } } private File getManagementSpacePUFile() { final File puFile = new File(Environment.getHomeDirectory() + "/tools/management-space/management-space.jar"); if (!puFile.exists() || !puFile.isFile()) { throw new IllegalStateException("Expected to find management space jar file at: " + puFile.getAbsolutePath()); } return puFile; } /** * Waits for the management space installation to completes. * * @param adminFacade * Admin facade to use for deployment * @param agent * The grid service agent to use * @param timeout * number of {@link TimeUnit}s to wait * @param timeunit * The {@link TimeUnit} to use * @throws InterruptedException * Reporting the thread was interrupted while waiting * @throws TimeoutException * Reporting the timeout was reached * @throws CLIException * Reporting a failure to check the installation progress */ @Override public void waitForInstallation(final AdminFacade adminFacade, final GridServiceAgent agent, final long timeout, final TimeUnit timeunit) throws InterruptedException, TimeoutException, CLIException { createConditionLatch(timeout, timeunit).waitFor(new ConditionLatch.Predicate() { /** * {@inheritDoc} */ @Override public boolean isDone() throws CLIException, InterruptedException { final Space space = admin.getSpaces().getSpaceByName(serviceName); logger.fine("Looking for a space instance that belongs to agent " + agent.getUid()); if (space != null) { final SpaceInstance[] spaceInstances = space.getInstances(); if (spaceInstances == null || spaceInstances.length == 0) { logger.fine("Did not find any " + serviceName + " instances"); return false; } for (SpaceInstance instance : spaceInstances) { GridServiceAgent instanceAgent = instance.getMachine().getGridServiceAgent(); if (instanceAgent != null && agent.getUid().equals(instanceAgent.getUid())) { // we found a space instance on this agent gigaspace = space.getGigaSpace(); return true; } else if (instanceAgent != null ) { logger.fine("Found space instance " + instance.getSpaceInstanceName() + " on agent " + instanceAgent.getUid()); } } } logger.fine("Connecting to management space."); if (verbose) { publishEvent("Connecting to management space."); } return false; } }); logger.fine("Management space is available."); if (verbose) { logger.fine("Management space is available."); } } @Override public void validateManagementService(final Admin admin, final GridServiceAgent agent, final long timeout, final TimeUnit timeunit) throws InterruptedException, TimeoutException, CLIException { waitForInstallation(null /*adminFacade*/, agent, timeout, timeunit); } /** * Returns the {@link GigaSpace} member used. * * @return the GigaSpace member */ public GigaSpace getGigaSpace() { return this.gigaspace; } /******* * Add an event listener. * * @param listener * . */ public void addListener(final LocalhostBootstrapperListener listener) { this.eventsListenersList.add(listener); } /******* * Add multiple event listeners. * * @param listeners * . */ public void addListeners(final List<LocalhostBootstrapperListener> listeners) { for (final LocalhostBootstrapperListener listener : listeners) { this.eventsListenersList.add(listener); } } private void publishEvent(final String event) { for (final LocalhostBootstrapperListener listener : this.eventsListenersList) { listener.onLocalhostBootstrapEvent(event); } } public void setIsLocalCloud(final boolean isLocalCloud) { this.isLocalcloud = isLocalCloud; } public String getPersistentStoragePath() { return persistentStoragePath; } public void setPersistentStoragePath(final String persistentStoragePath) { this.persistentStoragePath = persistentStoragePath; } }