summaryrefslogtreecommitdiffstats
path: root/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoNeutronUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoNeutronUtils.java')
-rw-r--r--adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoNeutronUtils.java616
1 files changed, 616 insertions, 0 deletions
diff --git a/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoNeutronUtils.java b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoNeutronUtils.java
new file mode 100644
index 0000000000..7e388a5ef8
--- /dev/null
+++ b/adapters/mso-adapter-utils/src/main/java/org/openecomp/mso/openstack/utils/MsoNeutronUtils.java
@@ -0,0 +1,616 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.mso.openstack.utils;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.openecomp.mso.cloud.CloudConfig;
+import org.openecomp.mso.cloud.CloudConfigFactory;
+import org.openecomp.mso.cloud.CloudIdentity;
+import org.openecomp.mso.cloud.CloudSite;
+import org.openecomp.mso.logger.MessageEnum;
+import org.openecomp.mso.logger.MsoAlarmLogger;
+import org.openecomp.mso.logger.MsoLogger;
+import org.openecomp.mso.openstack.beans.NetworkInfo;
+import org.openecomp.mso.openstack.exceptions.MsoAdapterException;
+import org.openecomp.mso.openstack.exceptions.MsoCloudSiteNotFound;
+import org.openecomp.mso.openstack.exceptions.MsoException;
+import org.openecomp.mso.openstack.exceptions.MsoIOException;
+import org.openecomp.mso.openstack.exceptions.MsoNetworkAlreadyExists;
+import org.openecomp.mso.openstack.exceptions.MsoNetworkNotFound;
+import org.openecomp.mso.openstack.exceptions.MsoOpenstackException;
+import org.openecomp.mso.openstack.exceptions.MsoTenantNotFound;
+import com.woorea.openstack.base.client.OpenStackBaseException;
+import com.woorea.openstack.base.client.OpenStackConnectException;
+import com.woorea.openstack.base.client.OpenStackRequest;
+import com.woorea.openstack.base.client.OpenStackResponseException;
+import com.woorea.openstack.keystone.Keystone;
+import com.woorea.openstack.keystone.model.Access;
+import com.woorea.openstack.keystone.utils.KeystoneUtils;
+import com.woorea.openstack.quantum.Quantum;
+import com.woorea.openstack.quantum.model.Network;
+import com.woorea.openstack.quantum.model.Networks;
+import com.woorea.openstack.quantum.model.Segment;
+import com.woorea.openstack.keystone.model.Authentication;
+
+public class MsoNeutronUtils extends MsoCommonUtils
+{
+ // Cache Neutron Clients statically. Since there is just one MSO user, there is no
+ // benefit to re-authentication on every request (or across different flows). The
+ // token will be used until it expires.
+ //
+ // The cache key is "tenantId:cloudId"
+ private static Map<String,NeutronCacheEntry> neutronClientCache = new HashMap<String,NeutronCacheEntry>();
+
+ // Fetch cloud configuration each time (may be cached in CloudConfig class)
+ private CloudConfig cloudConfig;
+
+ private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
+ private String msoPropID;
+
+ public enum NetworkType {
+ BASIC, PROVIDER, MULTI_PROVIDER
+ };
+
+ public MsoNeutronUtils(String msoPropID, CloudConfigFactory cloudConfigFactory) {
+ cloudConfig = cloudConfigFactory.getCloudConfig();
+ this.msoPropID = msoPropID;
+ }
+
+ /**
+ * Create a network with the specified parameters in the given cloud/tenant.
+ *
+ * If a network already exists with the same name, an exception will be thrown. Note that
+ * this is an MSO-imposed restriction. Openstack does not require uniqueness on network names.
+ * <p>
+ * @param cloudSiteId The cloud identifier (may be a region) in which to create the network.
+ * @param tenantId The tenant in which to create the network
+ * @param type The type of network to create (Basic, Provider, Multi-Provider)
+ * @param networkName The network name to create
+ * @param provider The provider network name (for Provider or Multi-Provider networks)
+ * @param vlans A list of VLAN segments for the network (for Provider or Multi-Provider networks)
+ * @return a NetworkInfo object which describes the newly created network
+ * @throws MsoNetworkAlreadyExists Thrown if a network with the same name already exists
+ * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception
+ * @throws MsoCloudSiteNotFound Thrown if the cloudSite is invalid or unknown
+ */
+ public NetworkInfo createNetwork (String cloudSiteId, String tenantId, NetworkType type, String networkName, String provider, List<Integer> vlans)
+ throws MsoException, MsoNetworkAlreadyExists, MsoCloudSiteNotFound
+ {
+ // Obtain the cloud site information where we will create the stack
+ CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId);
+ if (cloudSite == null) {
+ throw new MsoCloudSiteNotFound(cloudSiteId);
+ }
+
+ Quantum neutronClient = getNeutronClient (cloudSite, tenantId);
+
+ // Check if a network already exists with this name
+ // Openstack will allow duplicate name, so require explicit check
+ Network network = findNetworkByName (neutronClient, networkName);
+
+ if (network != null) {
+ // Network already exists. Throw an exception
+ LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Network already exists");
+ throw new MsoNetworkAlreadyExists (networkName, tenantId, cloudSiteId);
+ }
+
+ // Does not exist, create a new one
+ network = new Network();
+ network.setName(networkName);
+ network.setAdminStateUp(true);
+
+ if (type == NetworkType.PROVIDER) {
+ if (provider != null && vlans != null && vlans.size() > 0) {
+ network.setProviderPhysicalNetwork (provider);
+ network.setProviderNetworkType("vlan");
+ network.setProviderSegmentationId (vlans.get(0));
+ }
+ } else if (type == NetworkType.MULTI_PROVIDER) {
+ if (provider != null && vlans != null && vlans.size() > 0) {
+ List<Segment> segments = new ArrayList<Segment>(vlans.size());
+ for (int vlan : vlans) {
+ Segment segment = new Segment();
+ segment.setProviderPhysicalNetwork (provider);
+ segment.setProviderNetworkType("vlan");
+ segment.setProviderSegmentationId (vlan);
+
+ segments.add(segment);
+ }
+ network.setSegments(segments);
+ }
+ }
+
+ try {
+ OpenStackRequest<Network> request = neutronClient.networks().create(network);
+ Network newNetwork = executeAndRecordOpenstackRequest(request);
+ return new NetworkInfo(newNetwork);
+ }
+ catch (OpenStackBaseException e) {
+ // Convert Neutron exception to an MsoOpenstackException
+ MsoException me = neutronExceptionToMsoException (e, "CreateNetwork");
+ throw me;
+ }
+ catch (RuntimeException e) {
+ // Catch-all
+ MsoException me = runtimeExceptionToMsoException(e, "CreateNetwork");
+ throw me;
+ }
+ }
+
+
+ /**
+ * Query for a network with the specified name or ID in the given cloud. If the network exists,
+ * return an NetworkInfo object. If not, return null.
+ * <p>
+ * Whenever possible, the network ID should be used as it is much more efficient. Query by
+ * name requires retrieval of all networks for the tenant and search for matching name.
+ * <p>
+ * @param networkNameOrId The network to query
+ * @param tenantId The Openstack tenant to look in for the network
+ * @param cloudSiteId The cloud identifier (may be a region) in which to query the network.
+ * @return a NetworkInfo object describing the queried network, or null if not found
+ * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception
+ * @throws MsoCloudSiteNotFound
+ */
+ public NetworkInfo queryNetwork (String networkNameOrId, String tenantId, String cloudSiteId)
+ throws MsoException, MsoCloudSiteNotFound
+ {
+ LOGGER.debug("In queryNetwork");
+
+ // Obtain the cloud site information
+ CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId);
+ if (cloudSite == null) {
+ throw new MsoCloudSiteNotFound(cloudSiteId);
+ }
+
+ Quantum neutronClient = getNeutronClient (cloudSite, tenantId);
+
+ // Check if the network exists and return its info
+ try {
+ Network network = findNetworkByNameOrId (neutronClient, networkNameOrId);
+ if (network == null) {
+ LOGGER.debug ("Query Network: " + networkNameOrId + " not found in tenant " + tenantId);
+ return null;
+ }
+ return new NetworkInfo(network);
+ }
+ catch (OpenStackBaseException e) {
+ // Convert Neutron exception to an MsoOpenstackException
+ MsoException me = neutronExceptionToMsoException (e, "QueryNetwork");
+ throw me;
+ }
+ catch (RuntimeException e) {
+ // Catch-all
+ MsoException me = runtimeExceptionToMsoException(e, "QueryNetwork");
+ throw me;
+ }
+ }
+
+ /**
+ * Delete the specified Network (by ID) in the given cloud.
+ * If the network does not exist, success is returned.
+ * <p>
+ * @param networkNameOrId The name or Openstack ID of the network to delete
+ * @param cloudId The cloud identifier (may be a region) from which to delete the network.
+ * @return true if the network was deleted, false if the network did not exist
+ * @throws MsoOpenstackException If the Openstack API call returns an exception, this local
+ * exception will be thrown.
+ * @throws MsoCloudSiteNotFound
+ */
+ public boolean deleteNetwork (String networkId, String tenantId, String cloudSiteId)
+ throws MsoException, MsoCloudSiteNotFound
+ {
+ // Obtain the cloud site information where we will create the stack
+ CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId);
+ if (cloudSite == null) {
+ throw new MsoCloudSiteNotFound(cloudSiteId);
+ }
+
+ Quantum neutronClient = getNeutronClient (cloudSite, tenantId);
+
+ try {
+ // Check that the network exists.
+ Network network = findNetworkById (neutronClient, networkId);
+ if (network == null) {
+ LOGGER.info(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "");
+ return false;
+ }
+
+ OpenStackRequest<Void> request = neutronClient.networks().delete(network.getId());
+ executeAndRecordOpenstackRequest(request);
+
+ LOGGER.debug ("Deleted Network " + network.getId() + " (" + network.getName() + ")");
+ }
+ catch (OpenStackBaseException e) {
+ // Convert Neutron exception to an MsoOpenstackException
+ MsoException me = neutronExceptionToMsoException (e, "Delete Network");
+ throw me;
+ }
+ catch (RuntimeException e) {
+ // Catch-all
+ MsoException me = runtimeExceptionToMsoException(e, "DeleteNetwork");
+ throw me;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Update a network with the specified parameters in the given cloud/tenant.
+ *
+ * Specifically, this call is intended to update the VLAN segments on a
+ * multi-provider network. The provider segments will be replaced with the
+ * supplied list of VLANs.
+ * <p>
+ * Note that updating the 'segments' array is not normally supported by Neutron.
+ * This method relies on a Platform Orchestration extension (using SDN controller
+ * to manage the virtual networking).
+ *
+ * @param cloudSiteId The cloud site ID (may be a region) in which to update the network.
+ * @param the Openstack ID of the tenant in which to update the network
+ * @param networkId The unique Openstack ID of the network to be updated
+ * @param type The network type (Basic, Provider, Multi-Provider)
+ * @param provider The provider network name. This should not change.
+ * @param vlans The list of VLAN segments to replace
+ * @return a NetworkInfo object which describes the updated network
+ * @throws MsoNetworkNotFound Thrown if the requested network does not exist
+ * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception
+ * @throws MsoCloudSiteNotFound
+ */
+ public NetworkInfo updateNetwork (String cloudSiteId, String tenantId, String networkId, NetworkType type, String provider, List<Integer> vlans)
+ throws MsoException, MsoNetworkNotFound, MsoCloudSiteNotFound
+ {
+ // Obtain the cloud site information where we will create the stack
+ CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId);
+ if (cloudSite == null) {
+ throw new MsoCloudSiteNotFound(cloudSiteId);
+ }
+ Quantum neutronClient = getNeutronClient (cloudSite, tenantId);
+
+ // Check that the network exists
+ Network network = findNetworkById (neutronClient, networkId);
+
+ if (network == null) {
+ // Network not found. Throw an exception
+ LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Network not found");
+ throw new MsoNetworkNotFound (networkId, tenantId, cloudSiteId);
+ }
+
+ // Overwrite the properties to be updated
+ if (type == NetworkType.PROVIDER) {
+ if (provider != null && vlans != null && vlans.size() > 0) {
+ network.setProviderPhysicalNetwork (provider);
+ network.setProviderNetworkType("vlan");
+ network.setProviderSegmentationId (vlans.get(0));
+ }
+ } else if (type == NetworkType.MULTI_PROVIDER) {
+ if (provider != null && vlans != null && vlans.size() > 0) {
+ List<Segment> segments = new ArrayList<Segment>(vlans.size());
+ for (int vlan : vlans) {
+ Segment segment = new Segment();
+ segment.setProviderPhysicalNetwork (provider);
+ segment.setProviderNetworkType("vlan");
+ segment.setProviderSegmentationId (vlan);
+
+ segments.add(segment);
+ }
+ network.setSegments(segments);
+ }
+ }
+
+ try {
+ OpenStackRequest<Network> request = neutronClient.networks().update(network);
+ Network newNetwork = executeAndRecordOpenstackRequest(request);
+ return new NetworkInfo(newNetwork);
+ }
+ catch (OpenStackBaseException e) {
+ // Convert Neutron exception to an MsoOpenstackException
+ MsoException me = neutronExceptionToMsoException (e, "UpdateNetwork");
+ throw me;
+ }
+ catch (RuntimeException e) {
+ // Catch-all
+ MsoException me = runtimeExceptionToMsoException(e, "UpdateNetwork");
+ throw me;
+ }
+ }
+
+
+ // -------------------------------------------------------------------
+ // PRIVATE UTILITY FUNCTIONS FOR USE WITHIN THIS CLASS
+
+ /**
+ * Get a Neutron (Quantum) client for the Openstack Network service.
+ * This requires a 'member'-level userId + password, which will be retrieved from
+ * properties based on the specified cloud Id. The tenant in which to operate
+ * must also be provided.
+ * <p>
+ * On successful authentication, the Quantum object will be cached for the
+ * tenantID + cloudId so that it can be reused without reauthenticating with
+ * Openstack every time.
+ *
+ * @param cloudSite - a cloud site definition
+ * @param tenantId - Openstack tenant ID
+ * @return an authenticated Quantum object
+ */
+ private Quantum getNeutronClient (CloudSite cloudSite, String tenantId)
+ throws MsoTenantNotFound, MsoException
+ {
+ String cloudId = cloudSite.getId();
+
+ // Check first in the cache of previously authorized clients
+ String cacheKey = cloudId + ":" + tenantId;
+ if (neutronClientCache.containsKey(cacheKey)) {
+ if (! neutronClientCache.get(cacheKey).isExpired()) {
+ LOGGER.debug ("Using Cached HEAT Client for " + cacheKey);
+ Quantum neutronClient = neutronClientCache.get(cacheKey).getNeutronClient();
+ return neutronClient;
+ }
+ else {
+ // Token is expired. Remove it from cache.
+ neutronClientCache.remove(cacheKey);
+ LOGGER.debug ("Expired Cached Neutron Client for " + cacheKey);
+ }
+ }
+
+ // Obtain an MSO token for the tenant from the identity service
+ CloudIdentity cloudIdentity = cloudSite.getIdentityService();
+ Keystone keystoneTenantClient = new Keystone (cloudIdentity.getKeystoneUrl(cloudId, msoPropID));
+ Access access = null;
+ try {
+ Authentication credentials = cloudIdentity.getAuthentication ();
+ OpenStackRequest<Access> request = keystoneTenantClient.tokens().authenticate(credentials).withTenantId(tenantId);
+ access = executeAndRecordOpenstackRequest(request);
+ }
+ catch (OpenStackResponseException e) {
+ if (e.getStatus() == 401) {
+ // Authentication error.
+ String error = "Authentication Failure: tenant=" + tenantId + ",cloud=" + cloudIdentity.getId();
+ alarmLogger .sendAlarm("MsoAuthenticationError", MsoAlarmLogger.CRITICAL, error);
+ throw new MsoAdapterException(error);
+ }
+ else {
+ MsoException me = keystoneErrorToMsoException(e, "TokenAuth");
+ throw me;
+ }
+ }
+ catch (OpenStackConnectException e) {
+ // Connection to Openstack failed
+ MsoIOException me = new MsoIOException (e.getMessage(), e);
+ me.addContext("TokenAuth");
+ throw me;
+ }
+ catch (RuntimeException e) {
+ // Catch-all
+ MsoException me = runtimeExceptionToMsoException(e, "TokenAuth");
+ throw me;
+ }
+
+ String region = cloudSite.getRegionId();
+ String neutronUrl = null;
+ try {
+ neutronUrl = KeystoneUtils.findEndpointURL(access.getServiceCatalog(), "network", region, "public");
+ if (! neutronUrl.endsWith("/")) {
+ neutronUrl += "/v2.0/";
+ }
+ } catch (RuntimeException e) {
+ // This comes back for not found (probably an incorrect region ID)
+ String error = "Network service not found: region=" + region + ",cloud=" + cloudIdentity.getId();
+ alarmLogger.sendAlarm("MsoConfigurationError", MsoAlarmLogger.CRITICAL, error);
+ throw new MsoAdapterException (error, e);
+ }
+ // This is needed for testing in the MT cloud
+ if (cloudId.equals("MT")) {
+ neutronUrl = neutronUrl.replace("controller", "mtdnj02bh01wt.bvoip.labs.att.com");
+ }
+
+ Quantum neutronClient = new Quantum(neutronUrl);
+ neutronClient.token(access.getToken().getId());
+
+ neutronClientCache.put(cacheKey, new NeutronCacheEntry(neutronUrl, access.getToken().getId(), access.getToken().getExpires()));
+ LOGGER.debug ("Caching Neutron Client for " + cacheKey);
+
+ return neutronClient;
+ }
+
+ /**
+ * Forcibly expire a Neutron client from the cache. This call is for use by
+ * the KeystoneClient in case where a tenant is deleted. In that case,
+ * all cached credentials must be purged so that fresh authentication is
+ * done on subsequent calls.
+ * <p>
+ * @param tenantName
+ * @param cloudId
+ */
+ public static void expireNeutronClient (String tenantId, String cloudId) {
+ String cacheKey = cloudId + ":" + tenantId;
+ if (neutronClientCache.containsKey(cacheKey)) {
+ neutronClientCache.remove(cacheKey);
+ LOGGER.debug ("Deleted Cached Neutron Client for " + cacheKey);
+ }
+ }
+
+
+ /*
+ * Find a tenant (or query its existence) by its Name or Id. Check first against the
+ * ID. If that fails, then try by name.
+ *
+ * @param adminClient an authenticated Keystone object
+ * @param tenantName the tenant name or ID to query
+ * @return a Tenant object or null if not found
+ */
+ public Network findNetworkByNameOrId (Quantum neutronClient, String networkNameOrId)
+ {
+ if (networkNameOrId == null) {
+ return null;
+ }
+
+ Network network = findNetworkById(neutronClient, networkNameOrId);
+
+ if (network == null) {
+ network = findNetworkByName(neutronClient, networkNameOrId);
+ }
+
+ return network;
+ }
+
+ /*
+ * Find a network (or query its existence) by its Id.
+ *
+ * @param neutronClient an authenticated Quantum object
+ * @param networkId the network ID to query
+ * @return a Network object or null if not found
+ */
+ private static Network findNetworkById (Quantum neutronClient, String networkId)
+ {
+ if (networkId == null) {
+ return null;
+ }
+
+ try {
+ OpenStackRequest<Network> request = neutronClient.networks().show(networkId);
+ Network network = executeAndRecordOpenstackRequest(request);
+ return network;
+ }
+ catch (OpenStackResponseException e) {
+ if (e.getStatus() == 404) {
+ return null;
+ } else {
+ LOGGER.error (MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Error, GET Network By ID (" + networkId + "): " + e, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception in Openstack");
+ throw e;
+ }
+ }
+ }
+
+ /*
+ * Find a network (or query its existence) by its Name. This method avoids an
+ * initial lookup by ID when it's known that we have the network Name.
+ *
+ * Neutron does not support 'name=*' query parameter for Network query (show).
+ * The only way to query by name is to retrieve all networks and look for the
+ * match. While inefficient, this capability will be provided as it is needed
+ * by MSO, but should be avoided in favor of ID whenever possible.
+ *
+ * TODO:
+ * Network names are not required to be unique, though MSO will attempt to enforce
+ * uniqueness. This call probably needs to return an error (instead of returning
+ * the first match).
+ *
+ * @param neutronClient an authenticated Quantum object
+ * @param networkName the network name to query
+ * @return a Network object or null if not found
+ */
+ public Network findNetworkByName (Quantum neutronClient, String networkName)
+ {
+ if (networkName == null) {
+ return null;
+ }
+
+ try {
+ OpenStackRequest<Networks> request = neutronClient.networks().list();
+ Networks networks = executeAndRecordOpenstackRequest(request);
+ for (Network network : networks.getList()) {
+ if (network.getName().equals(networkName)) {
+ LOGGER.debug ("Found match on network name: " + networkName);
+ return network;
+ }
+ }
+ LOGGER.debug ("findNetworkByName - no match found for " + networkName);
+ return null;
+ }
+ catch (OpenStackResponseException e) {
+ if (e.getStatus() == 404) {
+ return null;
+ } else {
+ LOGGER.error (MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Error, GET Network By Name (" + networkName + "): " + e, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception in OpenStack");
+ throw e;
+ }
+ }
+ }
+
+
+ /*
+ * An entry in the Neutron Client Cache. It saves the Neutron client object
+ * along with the token expiration. After this interval, this cache
+ * item will no longer be used.
+ */
+ private static class NeutronCacheEntry implements Serializable
+ {
+ private static final long serialVersionUID = 1L;
+
+ private String neutronUrl;
+ private String token;
+ private Calendar expires;
+
+ public NeutronCacheEntry (String neutronUrl, String token, Calendar expires) {
+ this.neutronUrl = neutronUrl;
+ this.token = token;
+ this.expires = expires;
+ }
+
+ public Quantum getNeutronClient () {
+ Quantum neutronClient = new Quantum(neutronUrl);
+ neutronClient.token(token);
+ return neutronClient;
+ }
+
+ public boolean isExpired() {
+ if (expires == null) {
+ return true;
+ }
+
+ Calendar now = Calendar.getInstance();
+ if (now.after(expires)) {
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ /**
+ * Clean up the Neutron client cache to remove expired entries.
+ */
+ public static void neutronCacheCleanup () {
+ for (String cacheKey : neutronClientCache.keySet()) {
+ if (neutronClientCache.get(cacheKey).isExpired()) {
+ neutronClientCache.remove(cacheKey);
+ LOGGER.debug ("Cleaned Up Cached Neutron Client for " + cacheKey);
+ }
+ }
+ }
+
+ /**
+ * Reset the Neutron client cache.
+ * This may be useful if cached credentials get out of sync.
+ */
+ public static void neutronCacheReset () {
+ neutronClientCache = new HashMap<String,NeutronCacheEntry>();
+ }
+}