package alien4cloud.orchestrators.services; import java.io.IOException; import java.util.Map; import javax.annotation.Resource; import javax.inject.Inject; import org.springframework.stereotype.Service; import com.google.common.collect.Sets; import alien4cloud.dao.IGenericSearchDAO; import alien4cloud.exception.NotFoundException; import alien4cloud.model.orchestrators.Orchestrator; import alien4cloud.model.orchestrators.OrchestratorConfiguration; import alien4cloud.orchestrators.plugin.IOrchestratorPlugin; import alien4cloud.orchestrators.plugin.IOrchestratorPluginFactory; import alien4cloud.paas.OrchestratorPluginService; import alien4cloud.paas.exception.PluginConfigurationException; import alien4cloud.rest.utils.JsonUtil; import alien4cloud.utils.ReflectionUtil; /** * Manages orchestrator configuration */ @Service public class OrchestratorConfigurationService { @Inject private OrchestratorService orchestratorService; @Resource(name = "alien-es-dao") private IGenericSearchDAO alienDAO; @Inject private OrchestratorPluginService orchestratorPluginService; /** * Return the type of configuration for a given orchestrator. * * @param id Id of the orchestrator for which to get configuration. * @return The type of the orchestrator. */ public Class<?> getConfigurationType(String id) { Orchestrator orchestrator = orchestratorService.getOrFail(id); return getConfigurationType(orchestrator); } /** * Return the type of configuration for a given orchestrator. * * @param orchestrator Orchestrator for which to get configuration. * @return The type of the orchestrator. */ private Class<?> getConfigurationType(Orchestrator orchestrator) { IOrchestratorPluginFactory orchestratorFactory = orchestratorService.getPluginFactory(orchestrator); return orchestratorFactory.getConfigurationType(); } /** * Ensure that the configuration object parsed from json without typing is valid based on the orchestrator configuration type and return a valid typed * object. * * @param id if of the orchestrator. * @param configurationAsMap Configuration object (that may be a map parsed from json). * @return A typed configuration object. */ public Object configurationAsValidObject(String id, Object configurationAsMap) throws IOException, PluginConfigurationException { Orchestrator orchestrator = orchestratorService.getOrFail(id); return configurationAsValidObject(orchestrator, configurationAsMap); } /** * Get the configuration for a given orchestrator. * * @param id Id of the orchestrator for which to get the configuration. * @return the instance of configuration for the given orchestrator */ public OrchestratorConfiguration getConfigurationOrFail(String id) { OrchestratorConfiguration configuration = alienDAO.findById(OrchestratorConfiguration.class, id); if (configuration == null) { throw new NotFoundException("Orchestrator Configuration for id [" + id + "] doesn't exists."); } return configuration; } /** * Ensure that the configuration object parsed from json without typing is valid based on the orchestrator configuration type and return a valid typed * object. * * @param orchestrator Orchestrator for which to validated and compute a type configuration object. * @param configurationAsMap Configuration object (that may be a map parsed from json). * @return A typed configuration object. */ private Object configurationAsValidObject(Orchestrator orchestrator, Object configurationAsMap) throws PluginConfigurationException, IOException { Class<?> configurationType = getConfigurationType(orchestrator); if (configurationType == null) { String message = "Orchestrator <" + orchestrator.getId() + "> using plugin <" + orchestrator.getPluginId() + "> <" + orchestrator.getPluginBean() + "> cannot have configuration set (plugin has no configuration type)."; throw new PluginConfigurationException(message); } return JsonUtil.readObject(JsonUtil.toString(configurationAsMap), configurationType); } /** * Update the configuration for the given cloud. * * @param id Id of the orchestrator for which to update the configuration. * @param newConfiguration The new configuration. */ public synchronized void updateConfiguration(String id, Object newConfiguration) throws PluginConfigurationException, IOException { OrchestratorConfiguration configuration = alienDAO.findById(OrchestratorConfiguration.class, id); if (configuration == null) { throw new NotFoundException("No configuration exists for cloud [" + id + "]."); } Object newConfigurationObj = configurationAsValidObject(id, newConfiguration); Object oldConfiguration = configuration.getConfiguration(); Object oldConfigurationObj = configurationAsValidObject(id, oldConfiguration); Map<String, Object> oldConfAsMap = JsonUtil.toMap(JsonUtil.toString(oldConfigurationObj)); Map<String, Object> newConfAsMap = (Map<String, Object>) newConfiguration; // merge the config so that old values are preserved ReflectionUtil.mergeObject(newConfigurationObj, oldConfigurationObj, false, Sets.difference(oldConfAsMap.keySet(), newConfAsMap.keySet())); configuration.setConfiguration(oldConfigurationObj); // Trigger update of the orchestrator's configuration if enabled. IOrchestratorPlugin orchestratorInstance = (IOrchestratorPlugin) orchestratorPluginService.get(id); if (orchestratorInstance != null) { orchestratorInstance.setConfiguration(oldConfigurationObj); } alienDAO.save(configuration); } }