2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.so.openstack.utils;
24 import java.io.Serializable;
25 import java.util.Calendar;
26 import java.util.HashMap;
28 import java.util.Optional;
30 import org.onap.so.db.catalog.beans.CloudIdentity;
31 import org.onap.so.db.catalog.beans.CloudSite;
32 import org.onap.so.cloud.authentication.AuthenticationMethodFactory;
33 import org.onap.so.logger.MessageEnum;
34 import org.onap.so.logger.MsoAlarmLogger;
35 import org.onap.so.logger.MsoLogger;
36 import org.onap.so.openstack.beans.MsoTenant;
37 import org.onap.so.openstack.exceptions.MsoAdapterException;
38 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
39 import org.onap.so.openstack.exceptions.MsoException;
40 import org.onap.so.openstack.exceptions.MsoOpenstackException;
41 import org.onap.so.openstack.exceptions.MsoTenantAlreadyExists;
42 import org.springframework.beans.factory.annotation.Autowired;
43 import org.springframework.stereotype.Component;
45 import com.woorea.openstack.base.client.OpenStackBaseException;
46 import com.woorea.openstack.base.client.OpenStackConnectException;
47 import com.woorea.openstack.base.client.OpenStackRequest;
48 import com.woorea.openstack.base.client.OpenStackResponseException;
49 import com.woorea.openstack.keystone.Keystone;
50 import com.woorea.openstack.keystone.model.Access;
51 import com.woorea.openstack.keystone.model.Authentication;
52 import com.woorea.openstack.keystone.model.Metadata;
53 import com.woorea.openstack.keystone.model.Role;
54 import com.woorea.openstack.keystone.model.Roles;
55 import com.woorea.openstack.keystone.model.Tenant;
56 import com.woorea.openstack.keystone.model.User;
57 import com.woorea.openstack.keystone.utils.KeystoneUtils;
60 public class MsoKeystoneUtils extends MsoTenantUtils {
62 // Cache the Keystone Clients statically. Since there is just one MSO user, there is no
63 // benefit to re-authentication on every request (or across different flows). The
64 // token will be used until it expires.
66 // The cache key is "cloudId"
67 private static Map <String, KeystoneCacheEntry> adminClientCache = new HashMap<>();
69 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoKeystoneUtils.class);
72 private AuthenticationMethodFactory authenticationMethodFactory;
75 private MsoHeatUtils msoHeatUtils;
78 private MsoNeutronUtils msoNeutronUtils;
81 private MsoTenantUtilsFactory tenantUtilsFactory;
83 * Create a tenant with the specified name in the given cloud. If the tenant already exists,
84 * an Exception will be thrown. The MSO User will also be added to the "member" list of
85 * the new tenant to perform subsequent Nova/Heat commands in the tenant. If the MSO User
86 * association fails, the entire transaction will be rolled back.
88 * For the AIC Cloud (DCP/LCP): it is not clear that cloudId is needed, as all admin
89 * requests go to the centralized identity service in DCP. However, if some artifact
90 * must exist in each local LCP instance as well, then it will be needed to access the
94 * @param tenantName The tenant name to create
95 * @param cloudSiteId The cloud identifier (may be a region) in which to create the tenant.
96 * @return the tenant ID of the newly created tenant
97 * @throws MsoTenantAlreadyExists Thrown if the requested tenant already exists
98 * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception
100 public String createTenant (String tenantName,
102 Map <String, String> metadata,
103 boolean backout) throws MsoException {
104 // Obtain the cloud site information where we will create the tenant
105 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
106 if (!cloudSiteOpt.isPresent()) {
107 LOGGER.error(MessageEnum.RA_CREATE_TENANT_ERR, "MSOCloudSite not found", "", "", MsoLogger.ErrorCode.DataError, "MSOCloudSite not found");
108 throw new MsoCloudSiteNotFound (cloudSiteId);
110 Keystone keystoneAdminClient = getKeystoneAdminClient(cloudSiteOpt.get());
111 Tenant tenant = null;
113 // Check if the tenant already exists
114 tenant = findTenantByName (keystoneAdminClient, tenantName);
116 if (tenant != null) {
117 // Tenant already exists. Throw an exception
118 LOGGER.error(MessageEnum.RA_TENANT_ALREADY_EXIST, tenantName, cloudSiteId, "", "", MsoLogger.ErrorCode.DataError, "Tenant already exists");
119 throw new MsoTenantAlreadyExists (tenantName, cloudSiteId);
122 // Does not exist, create a new one
123 tenant = new Tenant ();
124 tenant.setName (tenantName);
125 tenant.setDescription ("SDN Tenant (via MSO)");
126 tenant.setEnabled (true);
128 OpenStackRequest <Tenant> request = keystoneAdminClient.tenants ().create (tenant);
129 tenant = executeAndRecordOpenstackRequest (request);
130 } catch (OpenStackBaseException e) {
131 // Convert Keystone OpenStackResponseException to MsoOpenstackException
132 throw keystoneErrorToMsoException (e, "CreateTenant");
133 } catch (RuntimeException e) {
135 throw runtimeExceptionToMsoException (e, "CreateTenant");
138 // Add MSO User to the tenant as a member and
139 // apply tenant metadata if supported by the cloud site
141 CloudIdentity cloudIdentity = cloudSiteOpt.get().getIdentityService();
143 User msoUser = findUserByNameOrId (keystoneAdminClient, cloudIdentity.getMsoId ());
144 Role memberRole = findRoleByNameOrId (keystoneAdminClient, cloudIdentity.getMemberRole ());
146 if(msoUser != null && memberRole != null) {
147 OpenStackRequest <Void> request = keystoneAdminClient.tenants ().addUser (tenant.getId (),
149 memberRole.getId ());
150 executeAndRecordOpenstackRequest (request);
153 if (cloudIdentity.getTenantMetadata () && metadata != null && !metadata.isEmpty ()) {
154 Metadata tenantMetadata = new Metadata ();
155 tenantMetadata.setMetadata (metadata);
157 OpenStackRequest <Metadata> metaRequest = keystoneAdminClient.tenants ()
158 .createOrUpdateMetadata (tenant.getId (),
160 executeAndRecordOpenstackRequest (metaRequest);
162 } catch (Exception e) {
163 // Failed to attach MSO User to the new tenant. Can't operate without access,
164 // so roll back the tenant.
167 LOGGER.warn(MessageEnum.RA_CREATE_TENANT_ERR, "Create Tenant errored, Tenant deletion suppressed", "Openstack", "", MsoLogger.ErrorCode.DataError, "Create Tenant error, Tenant deletion suppressed");
172 OpenStackRequest <Void> request = keystoneAdminClient.tenants ().delete (tenant.getId ());
173 executeAndRecordOpenstackRequest (request);
174 } catch (Exception e2) {
175 // Just log this one. We will report the original exception.
176 LOGGER.error (MessageEnum.RA_CREATE_TENANT_ERR, "Nested exception rolling back tenant", "Openstack", "", MsoLogger.ErrorCode.DataError, "Create Tenant error, Nested exception rolling back tenant", e2);
181 // Propagate the original exception on user/role/tenant mapping
182 if (e instanceof OpenStackBaseException) {
183 // Convert Keystone Exception to MsoOpenstackException
184 throw keystoneErrorToMsoException ((OpenStackBaseException) e, "CreateTenantUser");
186 MsoAdapterException me = new MsoAdapterException (e.getMessage (), e);
187 me.addContext ("CreateTenantUser");
191 return tenant.getId ();
195 * Query for a tenant by ID in the given cloud. If the tenant exists,
196 * return an MsoTenant object. If not, return null.
198 * For the AIC Cloud (DCP/LCP): it is not clear that cloudId is needed, as all admin
199 * requests go to the centralized identity service in DCP. However, if some artifact
200 * must exist in each local LCP instance as well, then it will be needed to access the
204 * @param tenantId The Openstack ID of the tenant to query
205 * @param cloudSiteId The cloud identifier (may be a region) in which to query the tenant.
206 * @return the tenant properties of the queried tenant, or null if not found
207 * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception
209 public MsoTenant queryTenant (String tenantId, String cloudSiteId) throws MsoException {
210 // Obtain the cloud site information where we will query the tenant
211 CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(
212 () -> new MsoCloudSiteNotFound(cloudSiteId));
214 Keystone keystoneAdminClient = getKeystoneAdminClient (cloudSite);
216 // Check if the tenant exists and return its Tenant Id
218 Tenant tenant = findTenantById (keystoneAdminClient, tenantId);
219 if (tenant == null) {
223 Map <String, String> metadata = new HashMap <String, String> ();
224 if (cloudSite.getIdentityService().getTenantMetadata ()) {
225 OpenStackRequest <Metadata> request = keystoneAdminClient.tenants ().showMetadata (tenant.getId ());
226 Metadata tenantMetadata = executeAndRecordOpenstackRequest (request);
227 if (tenantMetadata != null) {
228 metadata = tenantMetadata.getMetadata ();
231 return new MsoTenant (tenant.getId (), tenant.getName (), metadata);
232 } catch (OpenStackBaseException e) {
233 // Convert Keystone OpenStackResponseException to MsoOpenstackException
234 throw keystoneErrorToMsoException (e, "QueryTenant");
235 } catch (RuntimeException e) {
237 throw runtimeExceptionToMsoException (e, "QueryTenant");
242 * Query for a tenant with the specified name in the given cloud. If the tenant exists,
243 * return an MsoTenant object. If not, return null. This query is useful if the client
244 * knows it has the tenant name, skipping an initial lookup by ID that would always fail.
246 * For the AIC Cloud (DCP/LCP): it is not clear that cloudId is needed, as all admin
247 * requests go to the centralized identity service in DCP. However, if some artifact
248 * must exist in each local LCP instance as well, then it will be needed to access the
252 * @param tenantName The name of the tenant to query
253 * @param cloudSiteId The cloud identifier (may be a region) in which to query the tenant.
254 * @return the tenant properties of the queried tenant, or null if not found
255 * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception
257 public MsoTenant queryTenantByName (String tenantName, String cloudSiteId) throws MsoException {
258 // Obtain the cloud site information where we will query the tenant
259 CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(
260 () -> new MsoCloudSiteNotFound(cloudSiteId));
261 Keystone keystoneAdminClient = getKeystoneAdminClient (cloudSite);
264 Tenant tenant = findTenantByName (keystoneAdminClient, tenantName);
265 if (tenant == null) {
269 Map <String, String> metadata = new HashMap <String, String> ();
270 if (cloudSite.getIdentityService().getTenantMetadata ()) {
271 OpenStackRequest <Metadata> request = keystoneAdminClient.tenants ().showMetadata (tenant.getId ());
272 Metadata tenantMetadata = executeAndRecordOpenstackRequest (request);
273 if (tenantMetadata != null) {
274 metadata = tenantMetadata.getMetadata ();
277 return new MsoTenant (tenant.getId (), tenant.getName (), metadata);
278 } catch (OpenStackBaseException e) {
279 // Convert Keystone OpenStackResponseException to MsoOpenstackException
280 throw keystoneErrorToMsoException (e, "QueryTenantName");
281 } catch (RuntimeException e) {
283 throw runtimeExceptionToMsoException (e, "QueryTenantName");
288 * Delete the specified Tenant (by ID) in the given cloud. This method returns true or
289 * false, depending on whether the tenant existed and was successfully deleted, or if
290 * the tenant already did not exist. Both cases are treated as success (no Exceptions).
292 * Note for the AIC Cloud (DCP/LCP): all admin requests go to the centralized identity
293 * service in DCP. So deleting a tenant from one cloudSiteId will remove it from all
294 * sites managed by that identity service.
297 * @param tenantId The Openstack ID of the tenant to delete
298 * @param cloudSiteId The cloud identifier from which to delete the tenant.
299 * @return true if the tenant was deleted, false if the tenant did not exist.
300 * @throws MsoOpenstackException If the Openstack API call returns an exception.
302 public boolean deleteTenant (String tenantId, String cloudSiteId) throws MsoException {
303 // Obtain the cloud site information where we will query the tenant
304 CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(
305 () -> new MsoCloudSiteNotFound(cloudSiteId));
306 Keystone keystoneAdminClient = getKeystoneAdminClient (cloudSite);
309 // Check that the tenant exists. Also, need the ID to delete
310 Tenant tenant = findTenantById (keystoneAdminClient, tenantId);
311 if (tenant == null) {
312 LOGGER.error(MessageEnum.RA_TENANT_NOT_FOUND, tenantId, cloudSiteId, "", "", MsoLogger.ErrorCode.DataError, "Tenant not found");
316 OpenStackRequest <Void> request = keystoneAdminClient.tenants ().delete (tenant.getId ());
317 executeAndRecordOpenstackRequest (request);
318 LOGGER.debug ("Deleted Tenant " + tenant.getId () + " (" + tenant.getName () + ")");
320 // Clear any cached clients. Not really needed, ID will not be reused.
321 msoHeatUtils.expireHeatClient (tenant.getId (), cloudSiteId);
322 msoNeutronUtils.expireNeutronClient (tenant.getId (), cloudSiteId);
323 } catch (OpenStackBaseException e) {
324 // Convert Keystone OpenStackResponseException to MsoOpenstackException
325 throw keystoneErrorToMsoException (e, "Delete Tenant");
326 } catch (RuntimeException e) {
328 throw runtimeExceptionToMsoException (e, "DeleteTenant");
335 * Delete the specified Tenant (by Name) in the given cloud. This method returns true or
336 * false, depending on whether the tenant existed and was successfully deleted, or if
337 * the tenant already did not exist. Both cases are treated as success (no Exceptions).
339 * Note for the AIC Cloud (DCP/LCP): all admin requests go to the centralized identity
340 * service in DCP. So deleting a tenant from one cloudSiteId will remove it from all
341 * sites managed by that identity service.
344 * @param tenantName The name of the tenant to delete
345 * @param cloudSiteId The cloud identifier from which to delete the tenant.
346 * @return true if the tenant was deleted, false if the tenant did not exist.
347 * @throws MsoOpenstackException If the Openstack API call returns an exception.
349 public boolean deleteTenantByName (String tenantName, String cloudSiteId) throws MsoException {
350 // Obtain the cloud site information where we will query the tenant
351 Optional<CloudSite> cloudSite = cloudConfig.getCloudSite (cloudSiteId);
352 if (!cloudSite.isPresent()) {
353 throw new MsoCloudSiteNotFound (cloudSiteId);
355 Keystone keystoneAdminClient = getKeystoneAdminClient (cloudSite.get());
358 // Need the Tenant ID to delete (can't directly delete by name)
359 Tenant tenant = findTenantByName (keystoneAdminClient, tenantName);
360 if (tenant == null) {
361 // OK if tenant already doesn't exist.
362 LOGGER.error(MessageEnum.RA_TENANT_NOT_FOUND, tenantName, cloudSiteId, "", "", MsoLogger.ErrorCode.DataError, "Tenant not found");
366 // Execute the Delete. It has no return value.
367 OpenStackRequest <Void> request = keystoneAdminClient.tenants ().delete (tenant.getId ());
368 executeAndRecordOpenstackRequest (request);
370 LOGGER.debug ("Deleted Tenant " + tenant.getId () + " (" + tenant.getName () + ")");
372 // Clear any cached clients. Not really needed, ID will not be reused.
373 msoHeatUtils.expireHeatClient (tenant.getId (), cloudSiteId);
374 msoNeutronUtils.expireNeutronClient (tenant.getId (), cloudSiteId);
375 } catch (OpenStackBaseException e) {
376 // Note: It doesn't seem to matter if tenant doesn't exist, no exception is thrown.
377 // Convert Keystone OpenStackResponseException to MsoOpenstackException
378 throw keystoneErrorToMsoException (e, "DeleteTenant");
379 } catch (RuntimeException e) {
381 throw runtimeExceptionToMsoException (e, "DeleteTenant");
387 // -------------------------------------------------------------------
388 // PRIVATE UTILITY FUNCTIONS FOR USE WITHIN THIS CLASS
391 * Get a Keystone Admin client for the Openstack Identity service.
392 * This requires an 'admin'-level userId + password along with an 'admin' tenant
393 * in the target cloud. These values will be retrieved from properties based
394 * on the specified cloud ID.
396 * On successful authentication, the Keystone object will be cached for the cloudId
397 * so that it can be reused without going back to Openstack every time.
401 * @return an authenticated Keystone object
403 public Keystone getKeystoneAdminClient (CloudSite cloudSite) throws MsoException {
404 CloudIdentity cloudIdentity = cloudSite.getIdentityService();
406 String cloudId = cloudIdentity.getId ();
407 String adminTenantName = cloudIdentity.getAdminTenant ();
408 String region = cloudSite.getRegionId ();
410 // Check first in the cache of previously authorized clients
411 KeystoneCacheEntry entry = adminClientCache.get (cloudId);
413 if (!entry.isExpired ()) {
414 return entry.getKeystoneClient ();
416 // Token is expired. Remove it from cache.
417 adminClientCache.remove (cloudId);
420 MsoTenantUtils tenantUtils = tenantUtilsFactory.getTenantUtilsByServerType(cloudIdentity.getIdentityServerType());
421 final String keystoneUrl = tenantUtils.getKeystoneUrl(region, cloudIdentity);
422 Keystone keystone = new Keystone(keystoneUrl);
424 // Must authenticate against the 'admin' tenant to get the services endpoints
425 Access access = null;
428 Authentication credentials = authenticationMethodFactory.getAuthenticationFor(cloudIdentity);
429 OpenStackRequest <Access> request = keystone.tokens ()
430 .authenticate (credentials)
431 .withTenantName (adminTenantName);
432 access = executeAndRecordOpenstackRequest (request);
433 token = access.getToken ().getId ();
434 } catch (OpenStackResponseException e) {
435 if (e.getStatus () == 401) {
436 // Authentication error. Can't access admin tenant - something is mis-configured
437 String error = "MSO Authentication Failed for " + cloudIdentity.getId ();
438 alarmLogger.sendAlarm ("MsoAuthenticationError", MsoAlarmLogger.CRITICAL, error);
439 throw new MsoAdapterException (error);
441 throw keystoneErrorToMsoException (e, "TokenAuth");
443 } catch (OpenStackConnectException e) {
444 // Connection to Openstack failed
445 throw keystoneErrorToMsoException (e, "TokenAuth");
448 // Get the Identity service URL. Throws runtime exception if not found per region.
449 String adminUrl = null;
451 // TODO: FOR TESTING!!!!
452 adminUrl = KeystoneUtils.findEndpointURL (access.getServiceCatalog (), "identity", region, "public");
453 adminUrl = adminUrl.replaceFirst("5000", "35357");
454 } catch (RuntimeException e) {
455 String error = "Identity service not found: region=" + region + ",cloud=" + cloudIdentity.getId ();
456 alarmLogger.sendAlarm ("MsoConfigurationError", MsoAlarmLogger.CRITICAL, error);
457 LOGGER.error(MessageEnum.IDENTITY_SERVICE_NOT_FOUND, region, cloudIdentity.getId(), "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception in findEndpointURL");
458 throw new MsoAdapterException (error, e);
461 // A new Keystone object is required for the new URL. Use the auth token from above.
462 // Note: this doesn't go back to Openstack, it's just a local object.
463 keystone = new Keystone (adminUrl);
464 keystone.token (token);
466 // Cache to avoid re-authentication for every call.
467 KeystoneCacheEntry cacheEntry = new KeystoneCacheEntry (adminUrl, token, access.getToken ().getExpires ());
468 adminClientCache.put (cloudId, cacheEntry);
474 * Find a tenant (or query its existance) by its Name or Id. Check first against the
475 * ID. If that fails, then try by name.
477 * @param adminClient an authenticated Keystone object
479 * @param tenantName the tenant name or ID to query
481 * @return a Tenant object or null if not found
483 public Tenant findTenantByNameOrId (Keystone adminClient, String tenantNameOrId) {
484 if (tenantNameOrId == null) {
488 Tenant tenant = findTenantById (adminClient, tenantNameOrId);
489 if (tenant == null) {
490 tenant = findTenantByName (adminClient, tenantNameOrId);
497 * Find a tenant (or query its existance) by its Id.
499 * @param adminClient an authenticated Keystone object
501 * @param tenantName the tenant ID to query
503 * @return a Tenant object or null if not found
505 private Tenant findTenantById (Keystone adminClient, String tenantId) {
506 if (tenantId == null) {
511 OpenStackRequest <Tenant> request = adminClient.tenants ().show (tenantId);
512 return executeAndRecordOpenstackRequest (request);
513 } catch (OpenStackResponseException e) {
514 if (e.getStatus () == 404) {
517 LOGGER.error(MessageEnum.RA_CONNECTION_EXCEPTION, "Openstack Error, GET Tenant by Id (" + tenantId + "): " + e, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception in Openstack GET tenant by Id");
524 * Find a tenant (or query its existance) by its Name. This method avoids an
525 * initial lookup by ID when it's known that we have the tenant Name.
527 * @param adminClient an authenticated Keystone object
529 * @param tenantName the tenant name to query
531 * @return a Tenant object or null if not found
533 public Tenant findTenantByName (Keystone adminClient, String tenantName) {
534 if (tenantName == null) {
539 OpenStackRequest <Tenant> request = adminClient.tenants ().show ("").queryParam ("name", tenantName);
540 return executeAndRecordOpenstackRequest (request);
541 } catch (OpenStackResponseException e) {
542 if (e.getStatus () == 404) {
545 LOGGER.error (MessageEnum.RA_CONNECTION_EXCEPTION, "Openstack Error, GET Tenant By Name (" + tenantName + "): " + e, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception in Openstack GET Tenant By Name");
552 * Look up an Openstack User by Name or Openstack ID. Check the ID first, and if that
553 * fails, try the Name.
555 * @param adminClient an authenticated Keystone object
557 * @param userName the user name or ID to query
559 * @return a User object or null if not found
561 private User findUserByNameOrId (Keystone adminClient, String userNameOrId) {
562 if (userNameOrId == null) {
567 OpenStackRequest <User> request = adminClient.users ().show (userNameOrId);
568 return executeAndRecordOpenstackRequest (request);
569 } catch (OpenStackResponseException e) {
570 if (e.getStatus () == 404) {
571 // Not found by ID. Search for name
572 return findUserByName (adminClient, userNameOrId);
574 LOGGER.error (MessageEnum.RA_CONNECTION_EXCEPTION, "Openstack Error, GET User (" + userNameOrId + "): " + e, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception in Openstack GET User");
581 * Look up an Openstack User by Name. This avoids initial Openstack query by ID
582 * if we know we have the User Name.
584 * @param adminClient an authenticated Keystone object
586 * @param userName the user name to query
588 * @return a User object or null if not found
590 public User findUserByName (Keystone adminClient, String userName) {
591 if (userName == null) {
596 OpenStackRequest <User> request = adminClient.users ().show ("").queryParam ("name", userName);
597 return executeAndRecordOpenstackRequest (request);
598 } catch (OpenStackResponseException e) {
599 if (e.getStatus () == 404) {
602 LOGGER.error (MessageEnum.RA_CONNECTION_EXCEPTION, "Openstack Error, GET User By Name (" + userName + "): " + e, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception in Openstack GET User By Name");
609 * Look up an Openstack Role by Name or Id. There is no direct query for Roles, so
610 * need to retrieve a full list from Openstack and look for a match. By default,
611 * Openstack should have a "_member_" role for normal VM-level privileges and an
612 * "admin" role for expanded privileges (e.g. administer tenants, users, and roles).
615 * @param adminClient an authenticated Keystone object
617 * @param roleNameOrId the Role name or ID to look up
619 * @return a Role object
621 private Role findRoleByNameOrId (Keystone adminClient, String roleNameOrId) {
622 if (roleNameOrId == null) {
626 // Search by name or ID. Must search in list
627 OpenStackRequest <Roles> request = adminClient.roles ().list ();
628 Roles roles = executeAndRecordOpenstackRequest (request);
630 for (Role role : roles) {
631 if (roleNameOrId.equals (role.getName ()) || roleNameOrId.equals (role.getId ())) {
639 private static class KeystoneCacheEntry implements Serializable {
641 private static final long serialVersionUID = 1L;
643 private String keystoneUrl;
644 private String token;
645 private Calendar expires;
647 public KeystoneCacheEntry (String url, String token, Calendar expires) {
648 this.keystoneUrl = url;
650 this.expires = expires;
653 public Keystone getKeystoneClient () {
654 Keystone keystone = new Keystone (keystoneUrl);
655 keystone.token (token);
659 public boolean isExpired () {
660 // adding arbitrary guard timer of 5 minutes
661 return expires == null || System.currentTimeMillis() > (expires.getTimeInMillis() - 300000);
666 public String getKeystoneUrl(String regionId, CloudIdentity cloudIdentity) throws MsoException {
667 return cloudIdentity.getIdentityUrl();