/*******************************************************************************
* 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.commands;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.gogo.commands.Command;
import org.apache.felix.gogo.commands.Option;
import org.cloudifysource.domain.cloud.Cloud;
import org.cloudifysource.dsl.internal.CloudifyConstants;
import org.cloudifysource.dsl.internal.DSLException;
import org.cloudifysource.dsl.internal.ServiceReader;
import org.cloudifysource.shell.AdminFacade;
import org.cloudifysource.shell.CloudifyLicenseVerifier;
import org.cloudifysource.shell.Constants;
import org.cloudifysource.shell.ShellUtils;
import org.cloudifysource.shell.exceptions.CLIException;
import org.cloudifysource.shell.installer.CLILocalhostBootstrapperListener;
import org.cloudifysource.shell.installer.LocalhostGridAgentBootstrapper;
/**
* @author rafi, barakm
* @since 2.0.0
*
* Starts Cloudify Agent with management zone, and the Cloudify management processes on local machine.
*
* Optional arguments:
* lookup-groups - A unique name that is used to group together Cloudify components. Override
* in order to group together cloudify managements/agents on a network that supports multicast.
* nic-address - The IP address of the local host network card. Specify when local machine has more than one
* network adapter, and a specific network card should be used for network communication.
* user - The username for a secure connection to the rest server
* pwd - The password for a secure connection to the rest server
* timeout - The number of minutes to wait until
* the operation is completed (default: 5 minutes)
* lookup-locators - A list of IP addresses used to identify all management machines. Override when using a
* network without multicast support (Default: null).
* auto-shutdown - determines if undeploying or scaling-in the last service instance on the machine also
* triggers agent shutdown (default: false).
* no-web-services - if set, no attempt to deploy the rest admin and web-ui will be made.
* no-management-space - if set, no attempt to deploy the management space will be made.
* cloud-file - if set, designates the location of the cloud configuration file.
*
* Command syntax: start-management [-lookup-groups lookup-groups] [-nicAddress nicAddress] [-user username]
* [-password password] [-timeout timeout] [-lookup-locators lookup-locators]
* [-no-web-services no-web-services] [-no-management-space no-management-space] [-cloud-file cloud-file]
*/
@Command(
scope = "cloudify",
name = "start-management",
description = "For internal use only! Starts Cloudify Agent with management zone, "
+ "and the Cloudify management processes on local machine. "
+ "The management processes communicate with other"
+ " agent and management machines.")
public class StartManagement extends AbstractGSCommand {
private static final int DEFAULT_PROGRESS_INTERVAL_SECONDS = 10;
private static final int DEFAULT_TIMEOUNT_MINUTES = 5;
private static final String SPRING_SECURITY_CONFIG_FILE =
System.getenv(CloudifyConstants.SPRING_SECURITY_CONFIG_FILE_ENV_VAR);
private static final String KEYSTORE_FILE = System.getenv(CloudifyConstants.KEYSTORE_FILE_ENV_VAR);
private static final String KEYSTORE_PASSWORD = System.getenv(CloudifyConstants.KEYSTORE_PASSWORD_ENV_VAR);
private static String securityProfile = System.getenv(CloudifyConstants.SPRING_ACTIVE_PROFILE_ENV_VAR);
@Option(required = false, name = "-lookup-groups", description = "A unique name that is used to group together "
+ "different Cloudify machines. Default is based on the product version. Override in order to group "
+ "together cloudify managements/agents on a network that supports multicast.")
private final String lookupGroups = null;
@Option(required = false, name = "-lookup-locators", description = "A list of ip addresses used to identify all "
+ "management machines. Default is null. Override when using a network without multicast.")
private final String lookupLocators = null;
@Option(required = false, name = "-nic-address", description = "The ip address of the local host network card. "
+ "Specify when local machine has more than one network adapter, and a specific network card should be"
+ " used for network communication.")
private String nicAddress;
@Option(required = false, description = "The username for a secure connection to the rest server", name = "-user")
private String username;
@Option(required = false, description = "The password for a secure connection to the rest server",
name = "-password")
private String password;
@Option(required = false, name = "-no-web-services",
description = "if set, no attempt to deploy the rest admin and" + " web-ui will be made")
private boolean noWebServices;
@Option(required = false, name = "-timeout", description = "The number of minutes to wait until the operation is"
+ " done. By default waits 5 minutes.")
private int timeoutInMinutes = DEFAULT_TIMEOUNT_MINUTES;
@Option(required = false, name = "-no-management-space", description = "if set, no attempt to deploy the"
+ " management space will be made")
private boolean noManagementSpace;
@Option(required = false, name = "-no-management-space-container", description = "if set, no attempt to start the"
+ " container for the management space will be made")
private boolean noManagementSpaceContainer;
@Option(required = false, name = "-cloud-file", description = "if set, designated the location of the cloud"
+ " configuration file")
private String cloudFileName;
/**
* {@inheritDoc}
*/
@Override
protected Object doExecute()
throws Exception {
new CloudifyLicenseVerifier().verifyLicense();
if (getTimeoutInMinutes() < 0) {
throw new CLIException("-timeout cannot be negative");
}
if (SPRING_SECURITY_CONFIG_FILE == null) {
throw new IllegalStateException("Environment variable "
+ CloudifyConstants.SPRING_SECURITY_CONFIG_FILE_ENV_VAR + " cannot be null");
}
if (securityProfile == null) {
throw new IllegalStateException("Environment variable " + CloudifyConstants.SPRING_ACTIVE_PROFILE_ENV_VAR
+ " cannot be null");
}
if (CloudifyConstants.SPRING_PROFILE_SECURE.equals(securityProfile)) {
if (KEYSTORE_FILE == null) {
throw new IllegalStateException("Environment variable " + CloudifyConstants.KEYSTORE_FILE_ENV_VAR
+ " cannot be null");
}
if (KEYSTORE_PASSWORD == null) {
throw new IllegalStateException("Environment variable " + CloudifyConstants.KEYSTORE_PASSWORD_ENV_VAR
+ " cannot be null");
}
}
setSecurityMode();
final LocalhostGridAgentBootstrapper installer = new LocalhostGridAgentBootstrapper();
installer.setVerbose(verbose);
installer.setLookupGroups(lookupGroups);
installer.setLookupLocators(lookupLocators);
installer.setNicAddress(nicAddress);
installer.setProgressInSeconds(DEFAULT_PROGRESS_INTERVAL_SECONDS);
installer.setAdminFacade((AdminFacade) session.get(Constants.ADMIN_FACADE));
installer.setNoWebServices(noWebServices);
installer.setNoManagementSpace(noManagementSpace);
installer.setNoManagementSpaceContainer(noManagementSpaceContainer);
installer.setNotHighlyAvailableManagementSpace(isNotHAManagementSpace());
installer.setWaitForWebui(true);
installer.setCloudFilePath(cloudFileName);
installer.addListener(new CLILocalhostBootstrapperListener());
installer.startManagementOnLocalhostAndWait(securityProfile, SPRING_SECURITY_CONFIG_FILE, username, password,
KEYSTORE_FILE, KEYSTORE_PASSWORD, getTimeoutInMinutes(), TimeUnit.MINUTES);
return "Management started successfully. Use the shutdown-management command to shutdown"
+ " management processes running on local machine.";
}
private boolean isNotHAManagementSpace() throws IOException, DSLException {
if (cloudFileName != null && !cloudFileName.trim().isEmpty()) {
File cloudFile = new File(cloudFileName);
final Cloud cloud = ServiceReader.readCloud(cloudFile);
if (cloud != null) {
if (cloud.getProvider() != null) {
final int numberOfManagementMachines = cloud.getProvider().getNumberOfManagementMachines();
return numberOfManagementMachines < 2;
}
}
}
return true;
}
public int getTimeoutInMinutes() {
return timeoutInMinutes;
}
public void setTimeoutInMinutes(final int timeoutInMinutes) {
this.timeoutInMinutes = timeoutInMinutes;
}
private void setSecurityMode() throws IOException {
if (StringUtils.isNotBlank(username) && StringUtils.isBlank(password)) {
throw new IllegalArgumentException("Password is missing or empty");
}
if (StringUtils.isBlank(username) && StringUtils.isNotBlank(password)) {
throw new IllegalArgumentException("Username is missing or empty");
}
//no need to copy security config file / keystore file since we're on the mgmt server.
if (StringUtils.isBlank(securityProfile)) {
// TODO [noak] : log this, warning?
securityProfile = CloudifyConstants.SPRING_PROFILE_NON_SECURE;
}
// The security files are expected to be in <cloudify home>\config\security
if (ShellUtils.isSecureConnection(securityProfile)) {
//verify we have the security config file at place
File securityConfigFile = new File(SPRING_SECURITY_CONFIG_FILE);
if (!securityConfigFile.isFile()) {
throw new IllegalArgumentException("Security configuration file not found on management server at the "
+ "expected location: " + securityConfigFile.getCanonicalPath());
}
}
if (ShellUtils.isSecureConnection(securityProfile)) {
//verify we have the keystore file at place
File keystoreFile = new File(KEYSTORE_FILE);
if (!keystoreFile.isFile()) {
throw new IllegalArgumentException("Keystore file not found on management server at the expected "
+ "location: " + keystoreFile.getCanonicalPath());
}
}
}
}