/*******************************************************************************
* Copyright (c) 2013 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.rest;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.cloudifysource.domain.cloud.Cloud;
import org.cloudifysource.domain.cloud.compute.CloudCompute;
import org.cloudifysource.domain.cloud.compute.ComputeTemplate;
import org.cloudifysource.dsl.internal.CloudifyConstants;
import org.cloudifysource.dsl.internal.CloudifyMessageKeys;
import org.cloudifysource.dsl.internal.DSLException;
import org.cloudifysource.dsl.internal.ServiceReader;
import org.cloudifysource.rest.controllers.RestErrorException;
import org.cloudifysource.rest.util.RestUtils;
import org.cloudifysource.security.CustomPermissionEvaluator;
import org.cloudifysource.utilitydomain.data.CloudConfigurationHolder;
import org.cloudifysource.utilitydomain.data.reader.ComputeTemplatesReader;
import org.openspaces.admin.Admin;
import org.openspaces.core.GigaSpace;
import org.openspaces.core.context.GigaSpaceContext;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
*
* @author yael
* @since 2.6.0
*
*/
@Component
public class RestConfigurationFactoryBean implements FactoryBean<RestConfiguration> {
private static final int MAX_FILE_NAME_APPENDER = 99;
private static final Logger logger = Logger.getLogger(RestConfigurationFactoryBean.class.getName());
private RestConfiguration config;
@GigaSpaceContext(name = "gigaSpace")
private GigaSpace gigaSpace;
@Autowired(required = true)
protected Admin admin;
@Autowired(required = false)
private CustomPermissionEvaluator permissionEvaluator;
@Value("${restful.temporaryFolder}")
private String temporaryFolder;
@Override
public RestConfiguration getObject() throws Exception {
config = new RestConfiguration();
initRestConfiguration();
return config;
}
/**
* Initialize all needed fields in RestConfiguration.
* @throws RestErrorException
*/
public void initRestConfiguration() throws RestErrorException {
logger.info("Initializing cloud configuration");
config.setGigaSpace(gigaSpace);
config.setAdmin(admin);
config.setPermissionEvaluator(permissionEvaluator);
config.setRestTempFolder(createRestTempFolder());
Cloud cloud = readCloud();
if (cloud != null) {
config.setCloud(cloud);
setAdditionalTemplatesFolder();
initCloudTemplates();
CloudCompute cloudCompute = cloud.getCloudCompute();
if (cloudCompute.getTemplates().isEmpty()) {
throw new IllegalArgumentException("No templates defined in cloud configuration!");
}
String defaultTemplateName = cloudCompute.getTemplates().keySet().iterator().next();
logger.info("Setting default template name to: " + defaultTemplateName
+ ". This template will be used for services that do not specify an explicit template");
config.setDefaultTemplateName(defaultTemplateName);
String managementTemplateName = cloud.getConfiguration().getManagementMachineTemplate();
config.setManagementTemplateName(managementTemplateName);
config.setManagementTemplate(cloudCompute.getTemplates().get(managementTemplateName));
} else {
logger.info("running in local cloud mode");
}
}
private void setAdditionalTemplatesFolder() {
File additionalTempaltesFolderParent = config.getCloudConfigurationDir();
String persistentStoragePath = config.getCloud().getConfiguration().getPersistentStoragePath();
if (persistentStoragePath != null) {
logger.fine("[setAdditionalTemplatesFolder] - using the persistent storage folder ["
+ persistentStoragePath + "] as the parent of the additional templates folder.");
additionalTempaltesFolderParent = new File(persistentStoragePath);
}
File additionalTemplatesFodler =
new File(additionalTempaltesFolderParent, CloudifyConstants.ADDITIONAL_TEMPLATES_FOLDER_NAME);
if (!additionalTemplatesFodler.exists()) {
additionalTempaltesFolderParent.mkdirs();
}
logger.info("[setAdditionalTemplatesFolder] - setting the additional templates folder to ["
+ additionalTemplatesFodler + "]");
config.setAdditionalTemplatesFolder(additionalTemplatesFodler);
}
private File createRestTempFolder() throws RestErrorException {
String restTempFolderName = "";
if (!StringUtils.isEmpty(temporaryFolder)) {
restTempFolderName = temporaryFolder;
} else {
restTempFolderName = CloudifyConstants.REST_FOLDER;
}
File restTempFolder = new File(restTempFolderName);
// if the temp folder exists (left over of an unexpected shutdown) - delete it
// if deletion fails - create another temp folder next to it (cloudify1, cloudify2...)
if (restTempFolder.exists()) {
try {
FileUtils.deleteDirectory(restTempFolder);
} catch (IOException e) {
logger.warning("failed to delete rest template folder [" + restTempFolder.getAbsolutePath() + "], "
+ "attempting to create a new folder for this purpose");
e.printStackTrace();
try {
String uniqueFolderName = RestUtils.createUniqueFolderName(
restTempFolder.getParentFile(), restTempFolder.getName(), MAX_FILE_NAME_APPENDER);
logger.fine("Rest configuration unique folder is: " + uniqueFolderName);
restTempFolder = new File(restTempFolder.getParentFile(), uniqueFolderName);
} catch (IOException ioe) {
ioe.printStackTrace();
throw new RestErrorException(
CloudifyMessageKeys.UPLOAD_DIRECTORY_CREATION_FAILED.getName(), ioe.getMessage());
}
}
}
restTempFolder.deleteOnExit();
final boolean mkdirs = restTempFolder.mkdirs();
final String absolutePath = restTempFolder.getAbsolutePath();
if (mkdirs) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.INFO, "created rest temp directory - " + absolutePath);
}
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("failed to create rest temp directory at " + absolutePath);
}
throw new RestErrorException(
CloudifyMessageKeys.UPLOAD_DIRECTORY_CREATION_FAILED.getName(), absolutePath);
}
return restTempFolder;
}
private Cloud readCloud() {
logger.info("Loading cloud configuration");
CloudConfigurationHolder cloudConfigurationHolder = getCloudConfigurationFromManagementSpace();
logger.info("Cloud Configuration: " + cloudConfigurationHolder);
final String cloudConfigurationFilePath = cloudConfigurationHolder.getCloudConfigurationFilePath();
if (cloudConfigurationFilePath == null) {
// must be local cloud or azure
return null;
}
Cloud cloud = null;
try {
final File cloudConfigurationFile = new File(cloudConfigurationFilePath);
File cloudConfigurationDir = cloudConfigurationFile.getParentFile();
cloud = ServiceReader.readCloud(cloudConfigurationFile);
config.setCloudConfigurationDir(cloudConfigurationDir);
config.setCloudConfigurationHolder(cloudConfigurationHolder);
} catch (final DSLException e) {
throw new IllegalArgumentException(
"Failed to read cloud configuration file: " + cloudConfigurationHolder
+ ". Error was: " + e.getMessage(), e);
} catch (final IOException e) {
throw new IllegalArgumentException(
"Failed to read cloud configuration file: " + cloudConfigurationHolder
+ ". Error was: " + e.getMessage(), e);
}
logger.info("Successfully loaded cloud configuration file from management space");
return cloud;
}
private void initCloudTemplates() {
final File additionalTemplatesFolder = config.getAdditionalTempaltesFolder();
logger.info("[initCloudTemplates] - Adding templates from folder: "
+ additionalTemplatesFolder.getAbsolutePath());
if (!additionalTemplatesFolder.exists()) {
logger.info("[initCloudTemplates] - no templates to add from folder: "
+ additionalTemplatesFolder.getAbsolutePath());
return;
}
File[] listFiles = additionalTemplatesFolder.listFiles();
ComputeTemplatesReader reader = new ComputeTemplatesReader();
List<ComputeTemplate> addedTemplates = reader.addAdditionalTemplates(config.getCloud(), listFiles);
logger.info("[initCloudTemplates] - Added the following templates: " + addedTemplates);
config.getLastTemplateFileNum().addAndGet(listFiles.length);
}
private CloudConfigurationHolder getCloudConfigurationFromManagementSpace() {
logger.info("Waiting for cloud configuration to become available in management space");
final CloudConfigurationHolder config = gigaSpace.read(
new CloudConfigurationHolder(), 1000 * 60);
if (config == null) {
final String msg = "Could not find the expected Cloud Configuration Holder in Management space!";
logger.severe(msg);
throw new IllegalStateException(msg);
}
return config;
}
@Override
public Class<?> getObjectType() {
return RestConfiguration.class;
}
@Override
public boolean isSingleton() {
return true;
}
}