Removed MsoLogger class
[so.git] / adapters / mso-adapter-utils / src / main / java / org / onap / so / openstack / utils / MsoKeystoneUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Modifications Copyright (c) 2019 Samsung
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.so.openstack.utils;
24
25
26 import com.woorea.openstack.base.client.OpenStackBaseException;
27 import com.woorea.openstack.base.client.OpenStackConnectException;
28 import com.woorea.openstack.base.client.OpenStackRequest;
29 import com.woorea.openstack.base.client.OpenStackResponseException;
30 import com.woorea.openstack.keystone.Keystone;
31 import com.woorea.openstack.keystone.model.Access;
32 import com.woorea.openstack.keystone.model.Authentication;
33 import com.woorea.openstack.keystone.model.Metadata;
34 import com.woorea.openstack.keystone.model.Role;
35 import com.woorea.openstack.keystone.model.Roles;
36 import com.woorea.openstack.keystone.model.Tenant;
37 import com.woorea.openstack.keystone.model.User;
38 import com.woorea.openstack.keystone.utils.KeystoneUtils;
39 import java.util.HashMap;
40 import java.util.Map;
41 import java.util.Optional;
42 import org.onap.so.cloud.authentication.AuthenticationMethodFactory;
43 import org.onap.so.db.catalog.beans.CloudIdentity;
44 import org.onap.so.db.catalog.beans.CloudSite;
45 import org.onap.so.logger.ErrorCode;
46 import org.onap.so.logger.MessageEnum;
47 import org.onap.so.openstack.beans.MsoTenant;
48 import org.onap.so.openstack.exceptions.MsoAdapterException;
49 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
50 import org.onap.so.openstack.exceptions.MsoException;
51 import org.onap.so.openstack.exceptions.MsoOpenstackException;
52 import org.onap.so.openstack.exceptions.MsoTenantAlreadyExists;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.springframework.beans.factory.annotation.Autowired;
56 import org.springframework.stereotype.Component;
57
58 @Component
59 public class MsoKeystoneUtils extends MsoTenantUtils {
60
61     private static Logger logger = LoggerFactory.getLogger(MsoKeystoneUtils.class);
62
63     @Autowired
64     private AuthenticationMethodFactory authenticationMethodFactory;
65         
66         @Autowired
67         private MsoHeatUtils msoHeatUtils;
68         
69         @Autowired
70         private MsoNeutronUtils msoNeutronUtils;
71         
72         @Autowired
73         private MsoTenantUtilsFactory tenantUtilsFactory;
74     /**
75      * Create a tenant with the specified name in the given cloud. If the tenant already exists,
76      * an Exception will be thrown. The MSO User will also be added to the "member" list of
77      * the new tenant to perform subsequent Nova/Heat commands in the tenant. If the MSO User
78      * association fails, the entire transaction will be rolled back.
79      * <p>
80      * For the AIC Cloud (DCP/LCP): it is not clear that cloudId is needed, as all admin
81      * requests go to the centralized identity service in DCP. However, if some artifact
82      * must exist in each local LCP instance as well, then it will be needed to access the
83      * correct region.
84      * <p>
85      *
86      * @param tenantName The tenant name to create
87      * @param cloudSiteId The cloud identifier (may be a region) in which to create the tenant.
88      * @return the tenant ID of the newly created tenant
89      * @throws MsoTenantAlreadyExists Thrown if the requested tenant already exists
90      * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception
91      */
92     public String createTenant (String tenantName,
93                                 String cloudSiteId,
94                                 Map <String, String> metadata,
95                                 boolean backout) throws MsoException {
96         // Obtain the cloud site information where we will create the tenant
97         Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
98         if (!cloudSiteOpt.isPresent()) {
99             logger.error("{} MSOCloudSite {} not found {} ", MessageEnum.RA_CREATE_TENANT_ERR, cloudSiteId,
100                 ErrorCode.DataError.getValue());
101             throw new MsoCloudSiteNotFound (cloudSiteId);
102         }
103         Keystone keystoneAdminClient = getKeystoneAdminClient(cloudSiteOpt.get());
104         Tenant tenant = null;
105         try {
106             // Check if the tenant already exists
107             tenant = findTenantByName (keystoneAdminClient, tenantName);
108
109             if (tenant != null) {
110                 // Tenant already exists. Throw an exception
111                 logger.error("{} Tenant name {} already exists on Cloud site id {}, {}",
112                     MessageEnum.RA_TENANT_ALREADY_EXIST, tenantName, cloudSiteId, ErrorCode.DataError.getValue());
113                 throw new MsoTenantAlreadyExists (tenantName, cloudSiteId);
114             }
115
116             // Does not exist, create a new one
117             tenant = new Tenant ();
118             tenant.setName (tenantName);
119             tenant.setDescription ("SDN Tenant (via MSO)");
120             tenant.setEnabled (true);
121
122             OpenStackRequest <Tenant> request = keystoneAdminClient.tenants ().create (tenant);
123             tenant = executeAndRecordOpenstackRequest (request);
124         } catch (OpenStackBaseException e) {
125             // Convert Keystone OpenStackResponseException to MsoOpenstackException
126             throw keystoneErrorToMsoException (e, "CreateTenant");
127         } catch (RuntimeException e) {
128             // Catch-all
129             throw runtimeExceptionToMsoException (e, "CreateTenant");
130         }
131
132         // Add MSO User to the tenant as a member and
133         // apply tenant metadata if supported by the cloud site
134         try {
135             CloudIdentity cloudIdentity = cloudSiteOpt.get().getIdentityService();
136
137             User msoUser = findUserByNameOrId (keystoneAdminClient, cloudIdentity.getMsoId ());
138             Role memberRole = findRoleByNameOrId (keystoneAdminClient, cloudIdentity.getMemberRole ());
139             
140             if(msoUser != null && memberRole != null) {
141                     OpenStackRequest <Void> request = keystoneAdminClient.tenants ().addUser (tenant.getId (),
142                                                                                               msoUser.getId (),
143                                                                                               memberRole.getId ());
144                     executeAndRecordOpenstackRequest (request);
145             }
146
147             if (cloudIdentity.getTenantMetadata () && metadata != null && !metadata.isEmpty ()) {
148                 Metadata tenantMetadata = new Metadata ();
149                 tenantMetadata.setMetadata (metadata);
150
151                 OpenStackRequest <Metadata> metaRequest = keystoneAdminClient.tenants ()
152                                                                              .createOrUpdateMetadata (tenant.getId (),
153                                                                                                       tenantMetadata);
154                 executeAndRecordOpenstackRequest (metaRequest);
155             }
156         } catch (Exception e) {
157             // Failed to attach MSO User to the new tenant. Can't operate without access,
158             // so roll back the tenant.
159                 if (!backout)
160                 {
161               logger.warn("{} Create Tenant errored, Tenant deletion suppressed {} ", MessageEnum.RA_CREATE_TENANT_ERR,
162                   ErrorCode.DataError.getValue());
163           }
164                 else
165                 {
166                         try {
167                                 OpenStackRequest <Void> request = keystoneAdminClient.tenants ().delete (tenant.getId ());
168                                 executeAndRecordOpenstackRequest (request);
169                         } catch (Exception e2) {
170                                 // Just log this one. We will report the original exception.
171                 logger.error("{} Nested exception rolling back tenant {} ", MessageEnum.RA_CREATE_TENANT_ERR,
172                     ErrorCode.DataError.getValue(), e2);
173             }
174                 }
175                 
176
177             // Propagate the original exception on user/role/tenant mapping
178             if (e instanceof OpenStackBaseException) {
179                 // Convert Keystone Exception to MsoOpenstackException
180                 throw keystoneErrorToMsoException ((OpenStackBaseException) e, "CreateTenantUser");
181             } else {
182                 MsoAdapterException me = new MsoAdapterException (e.getMessage (), e);
183                 me.addContext ("CreateTenantUser");
184                 throw me;
185             }
186         }
187         return tenant.getId ();
188     }
189
190     /**
191      * Query for a tenant by ID in the given cloud. If the tenant exists,
192      * return an MsoTenant object. If not, return null.
193      * <p>
194      * For the AIC Cloud (DCP/LCP): it is not clear that cloudId is needed, as all admin
195      * requests go to the centralized identity service in DCP. However, if some artifact
196      * must exist in each local LCP instance as well, then it will be needed to access the
197      * correct region.
198      * <p>
199      *
200      * @param tenantId The Openstack ID of the tenant to query
201      * @param cloudSiteId The cloud identifier (may be a region) in which to query the tenant.
202      * @return the tenant properties of the queried tenant, or null if not found
203      * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception
204      */
205     public MsoTenant queryTenant (String tenantId, String cloudSiteId) throws MsoException {
206         // Obtain the cloud site information where we will query the tenant
207         CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(
208                 () -> new MsoCloudSiteNotFound(cloudSiteId));
209
210         Keystone keystoneAdminClient = getKeystoneAdminClient (cloudSite);
211
212         // Check if the tenant exists and return its Tenant Id
213         try {
214             Tenant tenant = findTenantById (keystoneAdminClient, tenantId);
215             if (tenant == null) {
216                 return null;
217             }
218
219             Map <String, String> metadata = new HashMap <String, String> ();
220             if (cloudSite.getIdentityService().getTenantMetadata ()) {
221                 OpenStackRequest <Metadata> request = keystoneAdminClient.tenants ().showMetadata (tenant.getId ());
222                 Metadata tenantMetadata = executeAndRecordOpenstackRequest (request);
223                 if (tenantMetadata != null) {
224                     metadata = tenantMetadata.getMetadata ();
225                 }
226             }
227             return new MsoTenant (tenant.getId (), tenant.getName (), metadata);
228         } catch (OpenStackBaseException e) {
229             // Convert Keystone OpenStackResponseException to MsoOpenstackException
230             throw keystoneErrorToMsoException (e, "QueryTenant");
231         } catch (RuntimeException e) {
232             // Catch-all
233             throw runtimeExceptionToMsoException (e, "QueryTenant");
234         }
235     }
236
237     /**
238      * Query for a tenant with the specified name in the given cloud. If the tenant exists,
239      * return an MsoTenant object. If not, return null. This query is useful if the client
240      * knows it has the tenant name, skipping an initial lookup by ID that would always fail.
241      * <p>
242      * For the AIC Cloud (DCP/LCP): it is not clear that cloudId is needed, as all admin
243      * requests go to the centralized identity service in DCP. However, if some artifact
244      * must exist in each local LCP instance as well, then it will be needed to access the
245      * correct region.
246      * <p>
247      *
248      * @param tenantName The name of the tenant to query
249      * @param cloudSiteId The cloud identifier (may be a region) in which to query the tenant.
250      * @return the tenant properties of the queried tenant, or null if not found
251      * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception
252      */
253     public MsoTenant queryTenantByName (String tenantName, String cloudSiteId) throws MsoException {
254         // Obtain the cloud site information where we will query the tenant
255         CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(
256                 () -> new MsoCloudSiteNotFound(cloudSiteId));
257         Keystone keystoneAdminClient = getKeystoneAdminClient (cloudSite);
258
259         try {
260             Tenant tenant = findTenantByName (keystoneAdminClient, tenantName);
261             if (tenant == null) {
262                 return null;
263             }
264
265             Map <String, String> metadata = new HashMap <String, String> ();
266             if (cloudSite.getIdentityService().getTenantMetadata ()) {
267                 OpenStackRequest <Metadata> request = keystoneAdminClient.tenants ().showMetadata (tenant.getId ());
268                 Metadata tenantMetadata = executeAndRecordOpenstackRequest (request);
269                 if (tenantMetadata != null) {
270                     metadata = tenantMetadata.getMetadata ();
271                 }
272             }
273             return new MsoTenant (tenant.getId (), tenant.getName (), metadata);
274         } catch (OpenStackBaseException e) {
275             // Convert Keystone OpenStackResponseException to MsoOpenstackException
276             throw keystoneErrorToMsoException (e, "QueryTenantName");
277         } catch (RuntimeException e) {
278             // Catch-all
279             throw runtimeExceptionToMsoException (e, "QueryTenantName");
280         }
281     }
282
283     /**
284      * Delete the specified Tenant (by ID) in the given cloud. This method returns true or
285      * false, depending on whether the tenant existed and was successfully deleted, or if
286      * the tenant already did not exist. Both cases are treated as success (no Exceptions).
287      * <p>
288      * Note for the AIC Cloud (DCP/LCP): all admin requests go to the centralized identity
289      * service in DCP. So deleting a tenant from one cloudSiteId will remove it from all
290      * sites managed by that identity service.
291      * <p>
292      *
293      * @param tenantId The Openstack ID of the tenant to delete
294      * @param cloudSiteId The cloud identifier from which to delete the tenant.
295      * @return true if the tenant was deleted, false if the tenant did not exist.
296      * @throws MsoOpenstackException If the Openstack API call returns an exception.
297      */
298     public boolean deleteTenant (String tenantId, String cloudSiteId) throws MsoException {
299         // Obtain the cloud site information where we will query the tenant
300         CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(
301                 () -> new MsoCloudSiteNotFound(cloudSiteId));
302         Keystone keystoneAdminClient = getKeystoneAdminClient (cloudSite);
303
304         try {
305             // Check that the tenant exists. Also, need the ID to delete
306             Tenant tenant = findTenantById (keystoneAdminClient, tenantId);
307             if (tenant == null) {
308                 logger.error("{} Tenant id {} not found on cloud site id {}, {}", MessageEnum.RA_TENANT_NOT_FOUND,
309                     tenantId, cloudSiteId, ErrorCode.DataError.getValue());
310                 return false;
311             }
312
313             OpenStackRequest <Void> request = keystoneAdminClient.tenants ().delete (tenant.getId ());
314             executeAndRecordOpenstackRequest (request);
315             logger.debug ("Deleted Tenant {} ({})", tenant.getId(), tenant.getName());
316         } catch (OpenStackBaseException e) {
317             // Convert Keystone OpenStackResponseException to MsoOpenstackException
318             throw keystoneErrorToMsoException (e, "Delete Tenant");
319         } catch (RuntimeException e) {
320             // Catch-all
321             throw runtimeExceptionToMsoException (e, "DeleteTenant");
322         }
323
324         return true;
325     }
326
327     /**
328      * Delete the specified Tenant (by Name) in the given cloud. This method returns true or
329      * false, depending on whether the tenant existed and was successfully deleted, or if
330      * the tenant already did not exist. Both cases are treated as success (no Exceptions).
331      * <p>
332      * Note for the AIC Cloud (DCP/LCP): all admin requests go to the centralized identity
333      * service in DCP. So deleting a tenant from one cloudSiteId will remove it from all
334      * sites managed by that identity service.
335      * <p>
336      *
337      * @param tenantName The name of the tenant to delete
338      * @param cloudSiteId The cloud identifier from which to delete the tenant.
339      * @return true if the tenant was deleted, false if the tenant did not exist.
340      * @throws MsoOpenstackException If the Openstack API call returns an exception.
341      */
342     public boolean deleteTenantByName (String tenantName, String cloudSiteId) throws MsoException {
343         // Obtain the cloud site information where we will query the tenant
344         Optional<CloudSite> cloudSite = cloudConfig.getCloudSite (cloudSiteId);
345         if (!cloudSite.isPresent()) {
346             throw new MsoCloudSiteNotFound (cloudSiteId);
347         }
348         Keystone keystoneAdminClient = getKeystoneAdminClient (cloudSite.get());
349
350         try {
351             // Need the Tenant ID to delete (can't directly delete by name)
352             Tenant tenant = findTenantByName (keystoneAdminClient, tenantName);
353             if (tenant == null) {
354                 // OK if tenant already doesn't exist.
355                 logger.error("{} Tenant {} not found on Cloud site id {}, {}", MessageEnum.RA_TENANT_NOT_FOUND,
356                     tenantName, cloudSiteId, ErrorCode.DataError.getValue());
357                 return false;
358             }
359
360             // Execute the Delete. It has no return value.
361             OpenStackRequest <Void> request = keystoneAdminClient.tenants ().delete (tenant.getId ());
362             executeAndRecordOpenstackRequest (request);
363
364             logger.debug("Deleted Tenant {} ({})", tenant.getId(), tenant.getName());
365
366         } catch (OpenStackBaseException e) {
367             // Note: It doesn't seem to matter if tenant doesn't exist, no exception is thrown.
368             // Convert Keystone OpenStackResponseException to MsoOpenstackException
369             throw keystoneErrorToMsoException (e, "DeleteTenant");
370         } catch (RuntimeException e) {
371             // Catch-all
372             throw runtimeExceptionToMsoException (e, "DeleteTenant");
373         }
374
375         return true;
376     }
377
378     // -------------------------------------------------------------------
379     // PRIVATE UTILITY FUNCTIONS FOR USE WITHIN THIS CLASS
380
381     /*
382      * Get a Keystone Admin client for the Openstack Identity service.
383      * This requires an 'admin'-level userId + password along with an 'admin' tenant
384      * in the target cloud. These values will be retrieved from properties based
385      * on the specified cloud ID.
386      * <p>
387      * On successful authentication, the Keystone object will be cached for the cloudId
388      * so that it can be reused without going back to Openstack every time.
389      *
390      * @param cloudId
391      *
392      * @return an authenticated Keystone object
393      */
394     public Keystone getKeystoneAdminClient (CloudSite cloudSite) throws MsoException {
395         CloudIdentity cloudIdentity = cloudSite.getIdentityService();
396
397         String cloudId = cloudIdentity.getId ();
398         String adminTenantName = cloudIdentity.getAdminTenant ();
399         String region = cloudSite.getRegionId ();
400
401         MsoTenantUtils tenantUtils = tenantUtilsFactory.getTenantUtilsByServerType(cloudIdentity.getIdentityServerType());
402         final String keystoneUrl = tenantUtils.getKeystoneUrl(region, cloudIdentity);
403         Keystone keystone = new Keystone(keystoneUrl);
404
405         // Must authenticate against the 'admin' tenant to get the services endpoints
406         Access access = null;
407         String token = null;
408         try {
409                 Authentication credentials = authenticationMethodFactory.getAuthenticationFor(cloudIdentity);
410             OpenStackRequest <Access> request = keystone.tokens ()
411                                                         .authenticate (credentials)
412                                                         .withTenantName (adminTenantName);
413             access = executeAndRecordOpenstackRequest (request);
414             token = access.getToken ().getId ();
415         } catch (OpenStackResponseException e) {
416             if (e.getStatus () == 401) {
417                 // Authentication error. Can't access admin tenant - something is mis-configured
418                 String error = "MSO Authentication Failed for " + cloudIdentity.getId ();
419
420                 throw new MsoAdapterException (error);
421             } else {
422                 throw keystoneErrorToMsoException (e, "TokenAuth");
423             }
424         } catch (OpenStackConnectException e) {
425             // Connection to Openstack failed
426             throw keystoneErrorToMsoException (e, "TokenAuth");
427         }
428
429         // Get the Identity service URL. Throws runtime exception if not found per region.
430         String adminUrl = null;
431         try {
432                 // TODO:  FOR TESTING!!!!
433                 adminUrl = KeystoneUtils.findEndpointURL (access.getServiceCatalog (), "identity", region, "public");
434                 adminUrl = adminUrl.replaceFirst("5000", "35357");
435         } catch (RuntimeException e) {
436             String error = "Identity service not found: region=" + region + ",cloud=" + cloudIdentity.getId ();
437
438             logger.error("{} Region: {} Cloud identity {} {} Exception in findEndpointURL ",
439                 MessageEnum.IDENTITY_SERVICE_NOT_FOUND, region, cloudIdentity.getId(),
440                 ErrorCode.DataError.getValue(), e);
441             throw new MsoAdapterException (error, e);
442         }
443
444         // A new Keystone object is required for the new URL. Use the auth token from above.
445         // Note: this doesn't go back to Openstack, it's just a local object.
446         keystone = new Keystone (adminUrl);
447         keystone.token (token);
448         return keystone;
449     }
450
451     /*
452      * Find a tenant (or query its existance) by its Name or Id. Check first against the
453      * ID. If that fails, then try by name.
454      *
455      * @param adminClient an authenticated Keystone object
456      *
457      * @param tenantName the tenant name or ID to query
458      *
459      * @return a Tenant object or null if not found
460      */
461     public Tenant findTenantByNameOrId (Keystone adminClient, String tenantNameOrId) {
462         if (tenantNameOrId == null) {
463             return null;
464         }
465
466         Tenant tenant = findTenantById (adminClient, tenantNameOrId);
467         if (tenant == null) {
468             tenant = findTenantByName (adminClient, tenantNameOrId);
469         }
470
471         return tenant;
472     }
473
474     /*
475      * Find a tenant (or query its existance) by its Id.
476      *
477      * @param adminClient an authenticated Keystone object
478      *
479      * @param tenantName the tenant ID to query
480      *
481      * @return a Tenant object or null if not found
482      */
483     private Tenant findTenantById (Keystone adminClient, String tenantId) {
484         if (tenantId == null) {
485             return null;
486         }
487
488         try {
489             OpenStackRequest <Tenant> request = adminClient.tenants ().show (tenantId);
490             return executeAndRecordOpenstackRequest (request);
491         } catch (OpenStackResponseException e) {
492             if (e.getStatus () == 404) {
493                 return null;
494             } else {
495                 logger.error("{} {} Openstack Error, GET Tenant by Id ({}): ", MessageEnum.RA_CONNECTION_EXCEPTION,
496                     ErrorCode.DataError.getValue(), tenantId, e);
497                 throw e;
498             }
499         }
500     }
501
502     /*
503      * Find a tenant (or query its existance) by its Name. This method avoids an
504      * initial lookup by ID when it's known that we have the tenant Name.
505      *
506      * @param adminClient an authenticated Keystone object
507      *
508      * @param tenantName the tenant name to query
509      *
510      * @return a Tenant object or null if not found
511      */
512     public Tenant findTenantByName (Keystone adminClient, String tenantName) {
513         if (tenantName == null) {
514             return null;
515         }
516
517         try {
518             OpenStackRequest <Tenant> request = adminClient.tenants ().show ("").queryParam ("name", tenantName);
519             return executeAndRecordOpenstackRequest (request);
520         } catch (OpenStackResponseException e) {
521             if (e.getStatus () == 404) {
522                 return null;
523             } else {
524                 logger.error("{} {} Openstack Error, GET Tenant By Name ({}) ", MessageEnum.RA_CONNECTION_EXCEPTION,
525                     ErrorCode.DataError.getValue(), tenantName, e);
526                 throw e;
527             }
528         }
529     }
530
531     /*
532      * Look up an Openstack User by Name or Openstack ID. Check the ID first, and if that
533      * fails, try the Name.
534      *
535      * @param adminClient an authenticated Keystone object
536      *
537      * @param userName the user name or ID to query
538      *
539      * @return a User object or null if not found
540      */
541     private User findUserByNameOrId (Keystone adminClient, String userNameOrId) {
542         if (userNameOrId == null) {
543             return null;
544         }
545
546         try {
547             OpenStackRequest <User> request = adminClient.users ().show (userNameOrId);
548             return executeAndRecordOpenstackRequest (request);
549         } catch (OpenStackResponseException e) {
550             if (e.getStatus () == 404) {
551                 // Not found by ID. Search for name
552                 return findUserByName (adminClient, userNameOrId);
553             } else {
554                 logger.error("{} {} Openstack Error, GET User ({}) ", MessageEnum.RA_CONNECTION_EXCEPTION,
555                     ErrorCode.DataError.getValue(), userNameOrId, e);
556                 throw e;
557             }
558         }
559     }
560
561     /*
562      * Look up an Openstack User by Name. This avoids initial Openstack query by ID
563      * if we know we have the User Name.
564      *
565      * @param adminClient an authenticated Keystone object
566      *
567      * @param userName the user name to query
568      *
569      * @return a User object or null if not found
570      */
571     public User findUserByName (Keystone adminClient, String userName) {
572         if (userName == null) {
573             return null;
574         }
575
576         try {
577             OpenStackRequest <User> request = adminClient.users ().show ("").queryParam ("name", userName);
578             return executeAndRecordOpenstackRequest (request);
579         } catch (OpenStackResponseException e) {
580             if (e.getStatus () == 404) {
581                 return null;
582             } else {
583                 logger.error("{} {} Openstack Error, GET User By Name ({}): ", MessageEnum.RA_CONNECTION_EXCEPTION,
584                     ErrorCode.DataError.getValue(), userName, e);
585                 throw e;
586             }
587         }
588     }
589
590     /*
591      * Look up an Openstack Role by Name or Id. There is no direct query for Roles, so
592      * need to retrieve a full list from Openstack and look for a match. By default,
593      * Openstack should have a "_member_" role for normal VM-level privileges and an
594      * "admin" role for expanded privileges (e.g. administer tenants, users, and roles).
595      * <p>
596      *
597      * @param adminClient an authenticated Keystone object
598      *
599      * @param roleNameOrId the Role name or ID to look up
600      *
601      * @return a Role object
602      */
603     private  Role findRoleByNameOrId (Keystone adminClient, String roleNameOrId) {
604         if (roleNameOrId == null) {
605             return null;
606         }
607
608         // Search by name or ID. Must search in list
609         OpenStackRequest <Roles> request = adminClient.roles ().list ();
610         Roles roles = executeAndRecordOpenstackRequest (request);
611
612         for (Role role : roles) {
613             if (roleNameOrId.equals (role.getName ()) || roleNameOrId.equals (role.getId ())) {
614                 return role;
615             }
616         }
617
618         return null;
619     }
620
621         @Override
622         public String getKeystoneUrl(String regionId, CloudIdentity cloudIdentity) throws MsoException {
623                 return cloudIdentity.getIdentityUrl();
624         }
625 }