| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you 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.apache.cloudstack.storage.datastore.provider; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.apache.cloudstack.storage.datastore.adapter.ProviderAdapter; |
| import org.apache.cloudstack.storage.datastore.adapter.ProviderAdapterFactory; |
| import org.apache.log4j.Logger; |
| |
| import com.cloud.utils.crypt.DBEncryptionUtil; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| |
| public class AdaptivePrimaryDatastoreAdapterFactoryMap { |
| private final Logger logger = Logger.getLogger(ProviderAdapter.class); |
| private Map<String,ProviderAdapterFactory> factoryMap = new HashMap<String,ProviderAdapterFactory>(); |
| private Map<String,ProviderAdapter> apiMap = new HashMap<String,ProviderAdapter>(); |
| |
| public AdaptivePrimaryDatastoreAdapterFactoryMap() { |
| |
| } |
| |
| /** |
| * Given a storage pool return current client. Reconfigure if changes are |
| * discovered |
| */ |
| public final ProviderAdapter getAPI(String uuid, String providerName, Map<String, String> details) { |
| ProviderAdapter api = apiMap.get(uuid); |
| if (api == null) { |
| synchronized (this) { |
| api = apiMap.get(uuid); |
| if (api == null) { |
| api = createNewAdapter(uuid, providerName, details); |
| apiMap.put(uuid, api); |
| logger.debug("Cached the new ProviderAdapter for storage pool " + uuid); |
| } |
| } |
| } |
| return api; |
| } |
| |
| /** |
| * Update the API with the given UUID. allows for URL changes and authentication updates |
| * @param uuid |
| * @param providerName |
| * @param details |
| */ |
| public final void updateAPI(String uuid, String providerName, Map<String, String> details) { |
| // attempt to create (which validates) the new info before updating the cache |
| ProviderAdapter adapter = createNewAdapter(uuid, providerName, details); |
| |
| // if its null its likely because no action has occured yet to trigger the API object to be loaded |
| if (adapter == null) { |
| throw new CloudRuntimeException("Adapter configruation failed for an unknown reason"); |
| } |
| |
| ProviderAdapter oldAdapter = apiMap.get(uuid); |
| apiMap.put(uuid, adapter); |
| try { |
| if (oldAdapter != null) oldAdapter.disconnect(); |
| } catch (Throwable e) { |
| logger.debug("Failure closing the old ProviderAdapter during an update of the cached data after validation of the new adapter configuration, likely the configuration is no longer valid", e); |
| } |
| } |
| |
| public void register(ProviderAdapterFactory factory) { |
| factoryMap.put(factory.getProviderName(), factory); |
| } |
| |
| protected ProviderAdapter createNewAdapter(String uuid, String providerName, Map<String, String> details) { |
| String authnType = details.get(ProviderAdapter.API_AUTHENTICATION_TYPE_KEY); |
| if (authnType == null) authnType = "basicauth"; |
| String lookupKey = null; |
| if (authnType.equals("basicauth")) { |
| lookupKey = details.get(ProviderAdapter.API_USERNAME_KEY); |
| if (lookupKey == null) { |
| throw new RuntimeException("Storage provider configuration property [" + ProviderAdapter.API_USERNAME_KEY + "] is required when using authentication type [" + authnType + "]"); |
| } |
| } else if (authnType.equals("apitoken")) { |
| lookupKey = details.get(ProviderAdapter.API_TOKEN_KEY); |
| if (lookupKey == null) { |
| throw new RuntimeException("Storage provider configuration property [" + ProviderAdapter.API_TOKEN_KEY + "] is required when using authentication type [" + authnType + "]"); |
| } |
| } else { |
| throw new RuntimeException("Storage provider configuration property [" + ProviderAdapter.API_AUTHENTICATION_TYPE_KEY + "] not set to valid value"); |
| } |
| |
| String url = details.get(ProviderAdapter.API_URL_KEY); |
| if (url == null) { |
| throw new RuntimeException("URL required when configuring a Managed Block API storage provider"); |
| } |
| |
| logger.debug("Looking for Provider [" + providerName + "] at [" + url + "]"); |
| ProviderAdapterFactory factory = factoryMap.get(providerName); |
| if (factory == null) { |
| throw new RuntimeException("Unable to find a storage provider API factory for provider: " + providerName); |
| } |
| |
| // decrypt password or token before sending to provider |
| if (authnType.equals("basicauth")) { |
| try { |
| details.put(ProviderAdapter.API_PASSWORD_KEY, DBEncryptionUtil.decrypt(details.get(ProviderAdapter.API_PASSWORD_KEY))); |
| } catch (Exception e) { |
| logger.warn("Failed to decrypt managed block API property: [" + ProviderAdapter.API_PASSWORD_KEY + "], trying to use as-is"); |
| } |
| } else if (authnType.equals("apitoken")) { |
| try { |
| details.put(ProviderAdapter.API_TOKEN_KEY, DBEncryptionUtil.decrypt(details.get(ProviderAdapter.API_TOKEN_KEY))); |
| } catch (Exception e) { |
| logger.warn("Failed to decrypt managed block API property: [" + ProviderAdapter.API_TOKEN_KEY + "], trying to use as-is"); |
| } |
| } |
| |
| ProviderAdapter api = factory.create(url, details); |
| api.validate(); |
| logger.debug("Creating new ProviderAdapter object for endpoint: " + providerName + "@" + url); |
| return api; |
| } |
| } |