package com.sixsq.slipstream.factory; /* * +=================================================================+ * SlipStream Server (WAR) * ===== * Copyright (C) 2013 SixSq Sarl (sixsq.com) * ===== * 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. * -=================================================================- */ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.sixsq.slipstream.configuration.Configuration; import com.sixsq.slipstream.connector.ConnectorBase; import com.sixsq.slipstream.connector.ExecutionControlUserParametersFactory; import com.sixsq.slipstream.connector.UserParametersFactoryBase; import com.sixsq.slipstream.exceptions.ConfigurationException; import com.sixsq.slipstream.exceptions.NotFoundException; import com.sixsq.slipstream.exceptions.SlipStreamClientException; import com.sixsq.slipstream.exceptions.ValidationException; import com.sixsq.slipstream.persistence.*; import com.sixsq.slipstream.util.FileUtil; public abstract class RunFactory { public final Run createRun(Module module, User user) throws SlipStreamClientException { return createRun(module, user, null); } public final Run createRun(Module module, User user, Map<String, List<Parameter<?>>> userChoices) throws SlipStreamClientException { validateModuleForRun(module); Map<String, String> cloudServicePerNode = resolveCloudServiceNames(module, user, userChoices); Set<String> cloudServiceNames = new HashSet<String>(cloudServicePerNode.values()); validateModule(module, cloudServicePerNode); Run run = new Run(module, getRunType(), cloudServiceNames, user); initCloudServices(run, cloudServicePerNode); initDefaultRunParameters(run, user); initExtraRunParameters(module, run); if (userChoices != null && !userChoices.isEmpty()) { addUserFormParametersAsRunParameters(module, run, userChoices); updateExtraRunParameters(module, run, userChoices); } validateRun(run, user); initialize(module, run, user); return run; } protected void validateModuleForRun(Module module) throws ValidationException { try { castToRequiredModuleType(module); } catch (ClassCastException e) { throw new ValidationException("Module validation failed: " + e.getMessage()); } } private void initDefaultRunParameters(Run run, User user) throws ValidationException { run = addDefaultKeepRunningToParameters(run, user); run.setParameter(new RunParameter(Run.GARBAGE_COLLECTED_PARAMETER_NAME, "false", Run.GARBAGE_COLLECTED_PARAMETER_DESCRIPTION)); } private void initialize(Module module, Run run, User user) throws ValidationException, NotFoundException { initializeGlobalParameters(run); init(module, run, user); initializeOrchestratorRuntimeParameters(run); initOrchestratorsNodeNames(run); } protected abstract RunType getRunType(); protected abstract void init(Module module, Run run, User user) throws ValidationException, NotFoundException; protected abstract Map<String, String> resolveCloudServiceNames(Module module, User user, Map<String, List<Parameter<?>>> userChoices); protected abstract void addUserFormParametersAsRunParameters(Module module, Run run, Map<String, List<Parameter<?>>> userChoices) throws ValidationException; protected abstract Module castToRequiredModuleType(Module module); private void initCloudServices(Run run, Map<String, String> cloudServicePerNode) throws ValidationException { for (Map.Entry<String, String> entry : cloudServicePerNode.entrySet()) { String key = constructParamName(entry.getKey(), RuntimeParameter.CLOUD_SERVICE_NAME); RunParameter rp = new RunParameter(key, entry.getValue(), RuntimeParameter.CLOUD_SERVICE_DESCRIPTION); run.setParameter(rp); } } protected abstract void initExtraRunParameters(Module module, Run run) throws ValidationException; protected abstract void updateExtraRunParameters(Module module, Run run, Map<String, List<Parameter<?>>> userChoices) throws ValidationException; protected void validateModule(Module module, Map<String, String> cloudServicePerNode) throws SlipStreamClientException { return; } protected void validateRun(Run run, User user) throws SlipStreamClientException { validateCloudServicesSet(run); validatePublicSshKey(run, user); } private void validateCloudServicesSet(Run run) throws ValidationException { if (run.getCloudServiceNamesList().length == 0) { throw new ValidationException("No cloud service names set on the run."); } } private void validatePublicSshKey(Run run, User user) throws ValidationException { if (run.getType() != RunType.Run) { String publicSshKeyFile = Configuration.getInstance().getProperty( ServiceConfiguration.CLOUD_CONNECTOR_ORCHESTRATOR_PUBLICSSHKEY, null); if (publicSshKeyFile == null || "".equals(publicSshKeyFile)) { throw new ValidationException("The path to the SSH public key to put in the orchestrator is empty. " + "Please contact your SlipStream administrator."); } if (!FileUtil.exist(publicSshKeyFile)) { throw new ValidationException( "The path to the SSH public key to put in the orchestrator points to a nonexistent file. " + "Please contact your SlipStream administrator."); } } } public static void validateUserPublicSshKeys(User user) throws ValidationException { String publicSshKey = user.getParameterValue(ExecutionControlUserParametersFactory.CATEGORY + "." + UserParametersFactoryBase.SSHKEY_PARAMETER_NAME, null); if (publicSshKey == null || publicSshKey.trim().isEmpty()) { throw new ValidationException("Missing public key in your user profile."); } } public static Run getRun(Module module, RunType type, User user) throws SlipStreamClientException { return getRun(module, type, user, null); } public static Run getRun(Module module, RunType type, User user, Map<String, List<Parameter<?>>> userChoices) throws SlipStreamClientException { if (userChoices == null) { userChoices = new HashMap<String, List<Parameter<?>>>(); } return selectFactory(type).createRun(module, user, userChoices); } public static RunFactory selectFactory(RunType type) throws SlipStreamClientException { RunFactory factory = null; switch (type) { case Orchestration: factory = new DeploymentFactory(); break; case Machine: factory = new BuildImageFactory(); break; case Run: factory = new SimpleRunFactory(); break; default: throw (new SlipStreamClientException("Unknown module type: " + type)); } return factory; } private Run addDefaultKeepRunningToParameters(Run run, User user) throws ValidationException { String key = Parameter.constructKey(ExecutionControlUserParametersFactory.CATEGORY, UserParameter.KEY_KEEP_RUNNING); UserParameter up = user.getParameter(key); if (up != null) { run.setParameter(new RunParameter(up.getName(), up.getValue(), up.getDescription())); } else { throw new ValidationException("Parameter 'Keep running after deployment' not found in the user profile."); } return run; } public static void terminate(Run run) { } public static Module loadModule(Run run) throws ValidationException { Module module = Module.load(run.getModuleResourceUrl()); if (module == null) { throw new ValidationException("Unknown module: " + run.getModuleResourceUrl()); } return module; } protected void initializeOrchestratorRuntimeParameters(Run run) throws ValidationException { if (withOrchestrator(run)) { for (String cloudServiceName : getCloudServiceNames(run)) { initializeOrchestratorParameters(run, cloudServiceName); } } } private static boolean withOrchestrator(Run run) { return ConnectorBase.isInOrchestrationContext(run); } protected static void initializeGlobalParameters(Run run) throws ValidationException { run.assignRuntimeParameter(RuntimeParameter.GLOBAL_CATEGORY_KEY, run.getCategory().toString(), "Module category"); run.assignRuntimeParameter(RuntimeParameter.GLOBAL_COMPLETE_KEY, "", RuntimeParameter.GLOBAL_COMPLETE_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.GLOBAL_ABORT_KEY, "", RuntimeParameter.GLOBAL_ABORT_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.GLOBAL_STATE_KEY, Run.INITIAL_NODE_STATE, RuntimeParameter.GLOBAL_STATE_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.GLOBAL_NODE_GROUPS_KEY, "", RuntimeParameter.GLOBAL_NODE_GROUPS_DESCRIPTION).setIsSet(true); run.assignRuntimeParameter(RuntimeParameter.GLOBAL_URL_SERVICE_KEY, "", RuntimeParameter.GLOBAL_URL_SERVICE_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.GLOBAL_TAGS_KEY, "", RuntimeParameter.GLOBAL_TAGS_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.GLOBAL_RECOVERY_MODE_KEY, "false", RuntimeParameter.GLOBAL_RECOVERY_MDDE_DESCRIPTION); } private static void initializeOrchestratorParameters(Run run, String cloudService) throws ValidationException { if (cloudService.isEmpty()) { throw new ValidationException("Failed to intialise orchestrator parameters: empty cloud service name."); } String prefix = Run.constructOrchestratorName(cloudService); assignCommonRuntimeParameters(run, prefix); run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.HOSTNAME_KEY), RuntimeParameter.HOSTNAME_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.INSTANCE_ID_KEY), RuntimeParameter.INSTANCE_ID_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.IS_ORCHESTRATOR_KEY), "true", RuntimeParameter.IS_ORCHESTRATOR_DESCRIPTION); Configuration conf = Configuration.getInstance(); String maxJaasWorkers = conf.getProperty( ServiceConfigurationParameter.constructKey(cloudService, RuntimeParameter.MAX_JAAS_WORKERS_KEY), RuntimeParameter.MAX_JAAS_WORKERS_DEFAULT); run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.MAX_JAAS_WORKERS_KEY), maxJaasWorkers, RuntimeParameter.MAX_JAAS_WORKERS_DESCRIPTION); } /** * @param nodename * Example (< nodename>.< index>) * @throws ValidationException */ public static void assignCommonRuntimeParameters(Run run, String nodename) throws ValidationException { String prefix = nodename; run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.STATE_CUSTOM_KEY), "", RuntimeParameter.STATE_CUSTOM_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.STATE_VM_KEY), "", RuntimeParameter.STATE_VM_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.ABORT_KEY), "", RuntimeParameter.ABORT_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.COMPLETE_KEY), "false", RuntimeParameter.COMPLETE_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.URL_SSH_KEY), "", RuntimeParameter.URL_SSH_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(prefix, RuntimeParameter.URL_SERVICE_KEY), "", RuntimeParameter.URL_SERVICE_DESCRIPTION); } protected static void assignCommonNodeInstanceRuntimeParameters(Run run, String nodename) throws ValidationException { assignCommonRuntimeParameters(run, nodename); run.assignRuntimeParameter(RuntimeParameter.constructParamName(nodename, RuntimeParameter.IS_ORCHESTRATOR_KEY), "false", RuntimeParameter.IS_ORCHESTRATOR_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(nodename, RuntimeParameter.SCALE_STATE_KEY), RuntimeParameter.SCALE_STATE_DEFAULT_VALUE, RuntimeParameter.SCALE_STATE_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(nodename, RuntimeParameter.PRE_SCALE_DONE_KEY), RuntimeParameter.PRE_SCALE_DONE_DEFAULT_VALUE, RuntimeParameter.PRE_SCALE_DONE_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(nodename, RuntimeParameter.SCALE_IAAS_DONE_KEY), RuntimeParameter.SCALE_IAAS_DONE_DEFAULT_VALUE, RuntimeParameter.SCALE_IAAS_DONE_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(nodename, RuntimeParameter.SCALE_DISK_ATTACH_SIZE_KEY), RuntimeParameter.SCALE_DISK_ATTACH_SIZE_DEFAULT_VALUE, RuntimeParameter.SCALE_DISK_ATTACH_SIZE_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(nodename, RuntimeParameter.SCALE_DISK_ATTACHED_DEVICE_KEY), RuntimeParameter.SCALE_DISK_ATTACHED_DEVICE_DEFAULT_VALUE, RuntimeParameter.SCALE_DISK_ATTACHED_DEVICE_DESCRIPTION); run.assignRuntimeParameter(RuntimeParameter.constructParamName(nodename, RuntimeParameter.SCALE_DISK_DETACH_DEVICE_KEY), RuntimeParameter.SCALE_DISK_DETACH_DEVICE_DEFAULT_VALUE, RuntimeParameter.SCALE_DISK_DETACH_DEVICE_DESCRIPTION); } protected void initOrchestratorsNodeNames(Run run) throws ConfigurationException, ValidationException { if (withOrchestrator(run)) { for (String cloudServiceName : getCloudServiceNames(run)) { String nodename = Run.constructOrchestratorName(cloudServiceName); run.addNodeInstanceName(nodename, cloudServiceName); run.assignRuntimeParameter(nodename + RuntimeParameter.NODE_PROPERTY_SEPARATOR + RuntimeParameter.CLOUD_SERVICE_NAME, cloudServiceName, RuntimeParameter.CLOUD_SERVICE_DESCRIPTION); } } } public static String[] getCloudServiceNames(Run run) throws ValidationException { return run.getCloudServiceNamesList(); } public static String constructParamName(String nodename, String paramname) { return RuntimeParameter.constructParamName(nodename, paramname); } protected static void findAndAddImagesApplicationParameters(Map<String, ModuleParameter> parameters, ImageModule image) { for (Map.Entry<String, ModuleParameter> entry : image.getParameters().entrySet()) { ModuleParameter parameter = entry.getValue(); if (ParameterCategory.applicationParameters().contains(parameter.getCategory())) { parameters.putIfAbsent(entry.getKey(), parameter); } } ImageModule parent = image.getParentModule(); if (parent != null) { findAndAddImagesApplicationParameters(parameters, parent); } } }