diff --git a/plugins/integrations/cloudian/docs/connector.txt b/plugins/integrations/cloudian/docs/connector.txt index 48593cb065e..33bed321ec2 100644 --- a/plugins/integrations/cloudian/docs/connector.txt +++ b/plugins/integrations/cloudian/docs/connector.txt @@ -351,16 +351,6 @@ is therefore integrated with the Management Server's log files. Logging is only output when the connector is enabled and appropriate logging configuration has been setup, for example: ----- -# cat /etc/cloudstack/management/log4j-cloud.xml - -[...snipped...] - - - -[...snipped...] ----- - .Connector Log File ---- view /var/log/cloudstack/management/management-server.log @@ -379,7 +369,7 @@ INFO [o.a.c.s.m.m.i.DefaultModuleDefinitionSet] (localhost-startStop-1:null) (l DEBUG [c.c.a.ApiServer] (localhost-startStop-1:null) (logid:) Discovered plugin CloudianConnectorImpl INFO [o.a.c.s.m.m.i.DefaultModuleDefinitionSet] (localhost-startStop-1:null) (logid:) Starting module [cloudian] ... -DEBUG [c.c.c.CloudianConnectorImpl] (localhost-startStop-1:null) (logid:) Cloudian connector is enabled, completed configuration, integration is ready. Cloudian admin host:admin.hs.yadav.xyz, port:19443 +DEBUG [c.c.c.CloudianConnectorImpl] (localhost-startStop-1:null) (logid:) Cloudian connector is enabled, completed configuration, integration is ready. Cloudian admin host:admin.abc.xyz, port:19443 ---- ==== SSO Failures @@ -391,25 +381,34 @@ but there was a typo and it was mapped to 'admn'. .Example of an SSO Failure ---- -[c.c.c.CloudianIntegrationServlet] (catalina-exec-23:null) EndUser: *admin|b3ebfd90-d73d-11e3-9a7c-002170530220|4069e3d2-d73d-11e3-9a7c-002170530220 -[c.c.c.CloudianIntegrationServlet] (catalina-exec-23:null) Mapping admin to 'admn' -[c.c.c.CloudianIntegrationServlet] (catalina-exec-23:null) SSO login failed for admn user. Check config. -[c.c.c.CloudianIntegrationServlet] (catalina-exec-23:null) SSO login failed. Removing any existing SSO Cookie. +DEBUG [o.a.c.c.CloudianConnectorImpl] (qtp1809303591-31:ctx-6e8e8621 ctx-40a6e707) (logid:cd96b235) Attempting Cloudian SSO with user id=admn, group id=0 +DEBUG [o.a.c.c.c.CloudianClient] (qtp1809303591-31:ctx-6e8e8621 ctx-40a6e707) (logid:cd96b235) Trying to find Cloudian user with id=admn and group id=0 +INFO [c.c.a.ApiServer] (qtp1809303591-31:ctx-6e8e8621 ctx-40a6e707) (logid:cd96b235) Failed to find the requested resource and get valid response from Cloudian admin API call, please ask your administrator to diagnose and fix issues. ---- ==== Other Failures -Connectivity problems with the Cloudian Admin server will probably be the -source of other problems logged. Below, we have incorrectly configured -Basic Auth and the connector is unable to connect to the Cloudian Admin server. +Connectivity problems with the Cloudian Admin server will probably be the +source of other problems logged. Below, we have logs from a timeout/connectivity +issue and incorrectly configured Basic Auth which causes authorization failures +and the connector fails to connect to the Cloudian Admin server. + +.Admin Server connection problem due to time out +---- +DEBUG [o.a.c.c.CloudianConnectorImpl] (qtp1809303591-372:ctx-a707eecc ctx-0e85865f) (logid:3efb32f0) Attempting Cloudian SSO with user id=753a62a8-978c-4bab-bfc4-b55ea2fda505, group id=16711de6-a806-11e7-b0a6-a434d91cd37e +DEBUG [o.a.c.c.c.CloudianClient] (qtp1809303591-372:ctx-a707eecc ctx-0e85865f) (logid:3efb32f0) Trying to find Cloudian user with id=753a62a8-978c-4bab-bfc4-b55ea2fda505 and group id=16711de6-a806-11e7-b0a6-a434d91cd37e +ERROR [o.a.c.c.c.CloudianClient] (qtp1809303591-372:ctx-a707eecc ctx-0e85865f) (logid:3efb32f0) Failed to list Cloudian user due to: +org.apache.http.conn.ConnectTimeoutException: Connect to admin.hs.yadav.xyz:19443 [admin.abc.xyz/10.5.1.6] failed: connect timed out +[...snipped...] +INFO [c.c.a.ApiServer] (qtp1638771699-28:ctx-e8b5b507 ctx-0632d279) (logid:94e8345e) Operation timed out, please try again. +---- .Admin Server Connection problem logging in as admin ---- -[c.c.c.CloudianIntegrationServlet] (catalina-exec-17:null) EndUser: *admin|b3ebfd90-d73d-11e3-9a7c-002170530220|4069e3d2-d73d-11e3-9a7c-002170530220 -[c.c.c.CloudianIntegrationServlet] (catalina-exec-17:null) Mapping admin to 'admin' -[o.a.c.h.a.AuthChallengeProcessor] (catalina-exec-17:null) basic authentication scheme selected -[o.a.c.h.HttpMethodDirector] (catalina-exec-17:null) Failure authenticating with BASIC 'CloudianAdmin'@admin.cloudian.com:18081 -[c.c.c.CloudianIntegrationServlet] (catalina-exec-17:null) SSO login request failed for '*admin|b3ebfd90-d73d-11e3-9a7c-002170530220|4069e3d2-d73d-11e3-9a7c-002170530220' +DEBUG [o.a.c.c.CloudianConnectorImpl] (qtp1809303591-23:ctx-e9d61989 ctx-78760902) (logid:d3ea9e30) Attempting Cloudian SSO with user id=753a62a8-978c-4bab-bfc4-b55ea2fda505, group id=16711de6-a806-11e7-b0a6-a434d91cd37e +DEBUG [o.a.c.c.c.CloudianClient] (qtp1809303591-23:ctx-e9d61989 ctx-78760902) (logid:d3ea9e30) Trying to find Cloudian user with id=753a62a8-978c-4bab-bfc4-b55ea2fda505 and group id=16711de6-a806-11e7-b0a6-a434d91cd37e +ERROR [o.a.c.c.c.CloudianClient] (qtp1809303591-23:ctx-e9d61989 ctx-78760902) (logid:d3ea9e30) Cloudian admin API authentication failed, please check Cloudian configuration. Admin auth principal=[principal: admin], password=incorrect-password, API url=https://admin.abc.xyz:19443 +INFO [c.c.a.ApiServer] (qtp1809303591-23:ctx-e9d61989 ctx-78760902) (logid:d3ea9e30) Cloudian admin API call unauthorized, please ask your administrator to fix integration issues. ---- == Trouble Shooting @@ -422,20 +421,18 @@ There are a few things which can go wrong for SSO. Here are the most common problems and things to check. + .SSO Check List -* Does the mapping of adminUserId point to the correct Cloudian user - in the <>? +* Does the global settings 'cloudian.cmc.admin.user' point to the correct + Cloudian (admin) user? * Is SSO configured and enabled on Cloudian HyperStore CMC? * Check for errors in the CMC log file. -* Are both CloudStack and HyperStore CMC configured with the same - ssoSharedKey? -* Try running 'cloudian-cloudstack.sh configure' which runs through - the connectivity settings. +* Are both CloudStack and HyperStore CMC configured with the same + 'cloudian.sso.key'? * Check the /var/log/cloudstack/management/management-server.log file and search for errors relating to SSO. -* Try access the CMC host directly from the problem users host using - the configured cmcHost, cmcPort and cmcProtocol configured in the - <>. -* If you log out of the management server and log in again, does +* Try access the CMC host directly from the problem users host using + the configured 'cloudian.cmc.host', 'cloudian.cmc.port' and 'cloudian.cmc.protocol' + configured in the CloudStack global settings. +* If you log out of the management server and log in again, does the 'Cloudian Storage' button work? . Adding/Deleting Domains or Accounts fails @@ -445,73 +442,15 @@ has changed with the connection or the admin server is down? + .Admin Check List * Is the admin server alive and listening? -* Run the 'cloudian-cloudstack.sh configure' script as it tests the connection - using the configured properties. This will usually identify the problem. +* Try access the admin server host directly from the problem users host using + the configured 'cloudian.admin.host', 'cloudian.admin.port' and + 'cloudian.admin.protocol' configured in the CloudStack global settings. Check + the configured auth settings 'cloudian.admin.user' and + 'cloudian.admin.password'. +* If you're experiencing timeout issues, trying changing the API timeout value + defined in 'cloudian.api.request.timeout' global setting. * Look for errors in the admin log file /var/log/cloudian/cloudian-admin.log. -. CloudStack Patching -+ -The enable and disable options of the 'cloudian-cloudstack.sh' script -usually manages all the patching for you. The following shows you -the normal clean state of the cloudstack-management installation. Note -though that the output will vary slightly depending on your installation -and what you have changed. -+ -.With Connector not installed ----- -# rpm -qV cloudstack-management -S.5....T. c /etc/cloudstack/management/db.properties -.......T. /var/run/cloudstack-management.pid ----- -+ -.With Connector installed ----- -# rpm -qV cloudstack-management - -# rpm -qV cloudstack-management -S.5....T. c /etc/cloudstack/management/db.properties -S.5....T. /usr/share/cloudstack-management/webapps/client/plugins/plugins.js -S.5....T. /usr/share/cloudstack-management/webapps/client/plugins/plugins.js.gz -.......T. /var/run/cloudstack-management.pid ----- - -. Fail-safe botched scripts recovery -+ -This procedure is probably not required but is noted here as a -fail-safe recovery method if things fail when you for update -packages or otherwise and unexpected things happen. -+ -RPM is luckily a great way to manage application files on a machine -as the original RPM contains everything you need to recover and -re-install the original state of the CloudStack Application. If -things don't work for some reason and you want to back things out -, but disable doesn't work for some reason, you can do the following: -+ -.First, try uninstall the connector ----- -# rpm -e cloudian-cloudplatform ----- -+ -If that fails to uninstall for some reason you can try to uninstall -it using the '--noscripts' option as below: -+ -.Optionally, force uninstall the connector (if uninstall fails) ----- -# rpm -e --noscripts cloudian-cloudplatform ----- -+ -Next re-install (without uninstalling) CloudStack. Re-install -will keep any configuration files belonging to CloudStack intact -and just gets the application files back to its initial installation -state. -+ -[subs="attributes"] ----- -# yum reinstall ./CloudStack-{cpver}.0.0-rhel/cloudstack-management-{cpver}.0.0-1.el6.x86_64.rpm ----- -+ -At this point you can install, configure and enable the connector again. - '''' _Confidentiality Notice_ diff --git a/plugins/integrations/cloudian/src/org/apache/cloudstack/cloudian/CloudianConnectorImpl.java b/plugins/integrations/cloudian/src/org/apache/cloudstack/cloudian/CloudianConnectorImpl.java index bf7ff629661..c62ca8361be 100644 --- a/plugins/integrations/cloudian/src/org/apache/cloudstack/cloudian/CloudianConnectorImpl.java +++ b/plugins/integrations/cloudian/src/org/apache/cloudstack/cloudian/CloudianConnectorImpl.java @@ -30,8 +30,8 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.cloudian.api.CloudianSsoLoginCmd; import org.apache.cloudstack.cloudian.api.CloudianIsEnabledCmd; +import org.apache.cloudstack.cloudian.api.CloudianSsoLoginCmd; import org.apache.cloudstack.cloudian.client.CloudianClient; import org.apache.cloudstack.cloudian.client.CloudianGroup; import org.apache.cloudstack.cloudian.client.CloudianUser; @@ -85,20 +85,11 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo throw new CloudRuntimeException("Failed to create and return Cloudian API client instance"); } - private boolean addOrUpdateGroup(final Domain domain) { + private boolean addGroup(final Domain domain) { if (domain == null || !isEnabled()) { return false; } final CloudianClient client = getClient(); - final CloudianGroup existingGroup = client.listGroup(domain.getUuid()); - if (existingGroup != null) { - if (!existingGroup.getActive() || !existingGroup.getGroupName().equals(domain.getPath())) { - existingGroup.setActive(true); - existingGroup.setGroupName(domain.getPath()); - return client.updateGroup(existingGroup); - } - return true; - } final CloudianGroup group = new CloudianGroup(); group.setGroupId(domain.getUuid()); group.setGroupName(domain.getPath()); @@ -127,23 +118,13 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo return false; } - private boolean addOrUpdateUserAccount(final Account account, final Domain domain) { + private boolean addUserAccount(final Account account, final Domain domain) { if (account == null || domain == null || !isEnabled()) { return false; } final User accountUser = userDao.listByAccount(account.getId()).get(0); - final String fullName = String.format("%s %s (%s)", accountUser.getFirstname(), accountUser.getLastname(), account.getAccountName()); final CloudianClient client = getClient(); - final CloudianUser existingUser = client.listUser(account.getUuid(), domain.getUuid()); - if (existingUser != null) { - if (!existingUser.getActive() || !existingUser.getFullName().equals(fullName)) { - existingUser.setActive(true); - existingUser.setEmailAddr(accountUser.getEmail()); - existingUser.setFullName(fullName); - return client.updateUser(existingUser); - } - return true; - } + final String fullName = String.format("%s %s (%s)", accountUser.getFirstname(), accountUser.getLastname(), account.getAccountName()); final CloudianUser user = new CloudianUser(); user.setUserId(account.getUuid()); user.setGroupId(domain.getUuid()); @@ -154,6 +135,25 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo return client.addUser(user); } + private boolean updateUserAccount(final Account account, final Domain domain, final CloudianUser existingUser) { + if (account == null || domain == null || !isEnabled()) { + return false; + } + final CloudianClient client = getClient(); + if (existingUser != null) { + final User accountUser = userDao.listByAccount(account.getId()).get(0); + final String fullName = String.format("%s %s (%s)", accountUser.getFirstname(), accountUser.getLastname(), account.getAccountName()); + if (!existingUser.getActive() || !existingUser.getFullName().equals(fullName) || !existingUser.getEmailAddr().equals(accountUser.getEmail())) { + existingUser.setActive(true); + existingUser.setFullName(fullName); + existingUser.setEmailAddr(accountUser.getEmail()); + return client.updateUser(existingUser); + } + return true; + } + return false; + } + private boolean removeUserAccount(final Account account) { if (account == null || !isEnabled()) { return false; @@ -197,13 +197,31 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo if (caller.getAccountName().equals("admin") && caller.getRoleId() == RoleType.Admin.getId()) { user = CloudianCmcAdminUser.value(); group = "0"; - final CloudianUser adminUser = getClient().listUser(user, group); - if (adminUser == null) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to find mapped Cloudian admin user, please fix integration issues."); + } + + LOG.debug(String.format("Attempting Cloudian SSO with user id=%s, group id=%s", user, group)); + + final CloudianUser ssoUser = getClient().listUser(user, group); + if (ssoUser == null || !ssoUser.getActive()) { + LOG.debug(String.format("Failed to find existing Cloudian user id=%s in group id=%s", user, group)); + final CloudianGroup ssoGroup = getClient().listGroup(group); + if (ssoGroup == null) { + LOG.debug(String.format("Failed to find existing Cloudian group id=%s, trying to add it", group)); + if (!addGroup(domain)) { + LOG.error("Failed to add missing Cloudian group id=" + group); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Aborting Cloudian SSO, failed to add group to Cloudian."); + } + } + if (!addUserAccount(caller, domain)) { + LOG.error("Failed to add missing Cloudian group id=" + group); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Aborting Cloudian SSO, failed to add user to Cloudian."); + } + final CloudianUser addedSsoUser = getClient().listUser(user, group); + if (addedSsoUser == null || !addedSsoUser.getActive()) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Aborting Cloudian SSO, failed to find mapped Cloudian user, please fix integration issues."); } } else { - addOrUpdateGroup(domain); - addOrUpdateUserAccount(caller, domain); + updateUserAccount(caller, domain, ssoUser); } return CloudianUtils.generateSSOUrl(getCmcUrl(), user, group, CloudianSsoKey.value()); @@ -235,7 +253,7 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo final Account account = accountDao.findById(accountId); final Domain domain = domainDao.findById(account.getDomainId()); - if (!addOrUpdateUserAccount(account, domain)) { + if (!addUserAccount(account, domain)) { LOG.warn(String.format("Failed to add account in Cloudian while adding CloudStack account=%s in domain=%s", account.getAccountName(), domain.getPath())); } } catch (final Exception e) { @@ -263,7 +281,7 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo public void onPublishMessage(String senderAddress, String subject, Object args) { try { final Domain domain = domainDao.findById((Long) args); - if (!addOrUpdateGroup(domain)) { + if (!addGroup(domain)) { LOG.warn(String.format("Failed to add group in Cloudian while adding CloudStack domain=%s id=%s", domain.getPath(), domain.getId())); } } catch (final Exception e) { diff --git a/plugins/integrations/cloudian/src/org/apache/cloudstack/cloudian/client/CloudianClient.java b/plugins/integrations/cloudian/src/org/apache/cloudstack/cloudian/client/CloudianClient.java index 9e05dd6d698..ed45c5c4c72 100644 --- a/plugins/integrations/cloudian/src/org/apache/cloudstack/cloudian/client/CloudianClient.java +++ b/plugins/integrations/cloudian/src/org/apache/cloudstack/cloudian/client/CloudianClient.java @@ -114,7 +114,7 @@ public class CloudianClient { private void checkResponseOK(final HttpResponse response) { if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to get valid response from Cloudian admin API call, please ask your administrator to fix diagnose and fix issues."); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to find the requested resource and get valid response from Cloudian admin API call, please ask your administrator to diagnose and fix issues."); } }