Return-Path: X-Original-To: apmail-incubator-cloudstack-commits-archive@minotaur.apache.org Delivered-To: apmail-incubator-cloudstack-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 61B56E251 for ; Thu, 31 Jan 2013 12:57:33 +0000 (UTC) Received: (qmail 79050 invoked by uid 500); 31 Jan 2013 12:57:33 -0000 Delivered-To: apmail-incubator-cloudstack-commits-archive@incubator.apache.org Received: (qmail 78545 invoked by uid 500); 31 Jan 2013 12:57:32 -0000 Mailing-List: contact cloudstack-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: cloudstack-dev@incubator.apache.org Delivered-To: mailing list cloudstack-commits@incubator.apache.org Received: (qmail 78483 invoked by uid 99); 31 Jan 2013 12:57:32 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 31 Jan 2013 12:57:32 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 477EE827EF1; Thu, 31 Jan 2013 12:57:32 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: kishan@apache.org To: cloudstack-commits@incubator.apache.org X-Mailer: ASF-Git Admin Mailer Subject: [1/4] - Separated RegionServiceImpl and RegionManagerImpl - Added comments - Changed package name to org.apache.cloudstack.region Message-Id: <20130131125732.477EE827EF1@tyr.zones.apache.org> Date: Thu, 31 Jan 2013 12:57:32 +0000 (UTC) http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/RegionManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/RegionManagerImpl.java b/server/src/org/apache/cloudstack/region/RegionManagerImpl.java new file mode 100755 index 0000000..d93ab10 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionManagerImpl.java @@ -0,0 +1,861 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import org.apache.cloudstack.region.dao.RegionDao; +import org.apache.cloudstack.region.dao.RegionSyncDao; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.log4j.Logger; + +import com.cloud.domain.Domain; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.DomainManager; +import com.cloud.user.UserAccount; +import com.cloud.user.UserVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserAccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.component.Inject; +import com.cloud.utils.component.Manager; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.uuididentity.dao.IdentityDao; + +@Local(value = { RegionManager.class }) +public class RegionManagerImpl implements RegionManager, Manager{ + public static final Logger s_logger = Logger.getLogger(RegionManagerImpl.class); + + @Inject + private RegionDao _regionDao; + @Inject + private AccountDao _accountDao; + @Inject + private AccountManager _accountMgr; + @Inject + private UserDao _userDao; + @Inject + private DomainDao _domainDao; + @Inject + private DomainManager _domainMgr; + @Inject + private UserAccountDao _userAccountDao; + @Inject + private IdentityDao _identityDao; + @Inject + private RegionSyncDao _regionSyncDao; + + private String _name; + private int _id; + + @Override + public boolean configure(final String name, final Map params) throws ConfigurationException { + _name = name; + _id = _regionDao.getRegionId(); + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + public int getId() { + return _id; + } + + /* + * Propagates Account creation to peer Regions + * Adds an entry in region_sync table on failure + */ + @Override + public boolean propagateAddAccount(String userName, String password, String firstName, String lastName, String email, String timezone, + String accountName, short accountType, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID) { + String command = "createAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.USERNAME, userName)); + params.add(new NameValuePair(ApiConstants.PASSWORD, password)); + params.add(new NameValuePair(ApiConstants.FIRSTNAME, firstName)); + params.add(new NameValuePair(ApiConstants.LASTNAME, lastName)); + params.add(new NameValuePair(ApiConstants.EMAIL, email)); + params.add(new NameValuePair(ApiConstants.TIMEZONE, timezone)); + params.add(new NameValuePair(ApiConstants.ACCOUNT, accountName)); + params.add(new NameValuePair(ApiConstants.ACCOUNT_TYPE, ""+accountType)); + //ToDo: use domain UUID + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, ((domainId != null) ? domainId.toString() : ""))); + params.add(new NameValuePair(ApiConstants.NETWORK_DOMAIN, networkDomain)); + params.add(new NameValuePair(ApiConstants.ACCOUNT_DETAILS, (details != null) ? details.toString() : "")); + params.add(new NameValuePair(ApiConstants.ACCOUNT_ID, accountUUID)); + params.add(new NameValuePair(ApiConstants.USER_ID, userUUID)); + params.add(new NameValuePair(ApiConstants.REGION_ID, ""+getId())); + + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + s_logger.debug("Adding account :"+accountName+" to Region: "+region.getId()); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully added account :"+accountName+" to Region: "+region.getId()); + } else { + // api call failed. Add entry in region_sync table + addRegionSyncItem(region.getId(), command, params); + s_logger.error("Error while Adding account :"+accountName+" to Region: "+region.getId()); + } + } + return true; + } + + /* + * Propagates User creation to peer Regions + * Adds an entry in region_sync table on failure + */ + @Override + public void propagateAddUser(String userName, String password, + String firstName, String lastName, String email, String timezone, + String accountName, String domainUUId, String userUUID) { + + String command = "createUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.USERNAME, userName)); + params.add(new NameValuePair(ApiConstants.PASSWORD, password)); + params.add(new NameValuePair(ApiConstants.FIRSTNAME, firstName)); + params.add(new NameValuePair(ApiConstants.LASTNAME, lastName)); + params.add(new NameValuePair(ApiConstants.EMAIL, email)); + params.add(new NameValuePair(ApiConstants.TIMEZONE, timezone)); + params.add(new NameValuePair(ApiConstants.ACCOUNT, accountName)); + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, domainUUId)); + params.add(new NameValuePair(ApiConstants.USER_ID, userUUID)); + params.add(new NameValuePair(ApiConstants.REGION_ID, ""+getId())); + + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + s_logger.debug("Adding account :"+accountName+" to Region: "+region.getId()); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully added user :"+userName+" to Region: "+region.getId()); + } else { + // api call failed. Add entry in region_sync table + addRegionSyncItem(region.getId(), command, params); + s_logger.error("Error while Adding user :"+userName+" to Region: "+region.getId()); + } + } + return; + } + + /* + * Propagates Domain creation details to peer Regions + * Adds an entry in region_sync table on failure + */ + @Override + public void propagateAddDomain(String name, Long parentId, String networkDomain, String uuid) { + + String command = "createDomain"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.NAME, name)); + if(parentId != null){ + DomainVO domain = _domainDao.findById(parentId); + if(domain != null){ + params.add(new NameValuePair(ApiConstants.PARENT_DOMAIN_ID, domain.getUuid())); + } + } + params.add(new NameValuePair(ApiConstants.NETWORK_DOMAIN, networkDomain)); + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, uuid)); + params.add(new NameValuePair(ApiConstants.REGION_ID, ""+getId())); + + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + s_logger.debug("Adding domain :"+name+" to Region: "+region.getId()); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully added domain :"+name+" to Region: "+region.getId()); + } else { + // api call failed. Add entry in region_sync table + addRegionSyncItem(region.getId(), command, params); + s_logger.error("Error while Adding domain :"+name+" to Region: "+region.getId()); + } + } + return; + } + + /** + * Adds an entry to region_sync table + * Entry contains region Id along with failed api + * @param regionId + * @param command + * @param params + */ + private void addRegionSyncItem(int regionId, String command, List params){ + String api = RegionsApiUtil.buildParams(command, params); + RegionSyncVO sync = new RegionSyncVO(regionId, api); + if(_regionSyncDao.persist(sync) == null){ + s_logger.error("Failed to add Region Sync Item. RegionId: "+regionId + "API command: "+api); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Region addRegion(int id, String name, String endPoint, String apiKey, String secretKey) { + //Region Id should be unique + if( _regionDao.findById(id) != null ){ + throw new InvalidParameterValueException("Region with id: "+id+" already exists"); + } + //Region Name should be unique + if( _regionDao.findByName(name) != null ){ + throw new InvalidParameterValueException("Region with name: "+name+" already exists"); + } + RegionVO region = new RegionVO(id, name, endPoint, apiKey, secretKey); + return _regionDao.persist(region); + } + + /** + * {@inheritDoc} + */ + @Override + public Region updateRegion(int id, String name, String endPoint, String apiKey, String secretKey) { + RegionVO region = _regionDao.findById(id); + + if(region == null){ + throw new InvalidParameterValueException("Region with id: "+id+" does not exist"); + } + + //Ensure region name is unique + if(name != null){ + RegionVO region1 = _regionDao.findByName(name); + if(region1 != null && id != region1.getId()){ + throw new InvalidParameterValueException("Region with name: "+name+" already exists"); + } + } + + if(name != null){ + region.setName(name); + } + + if(endPoint != null){ + region.setEndPoint(endPoint); + } + + if(apiKey != null){ + region.setApiKey(apiKey); + } + + if(secretKey != null){ + region.setSecretKey(secretKey); + } + + _regionDao.update(id, region); + return _regionDao.findById(id); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean removeRegion(int id) { + RegionVO region = _regionDao.findById(id); + if(region == null){ + throw new InvalidParameterValueException("Failed to delete Region: " + id + ", Region not found"); + } + return _regionDao.remove(id); + } + + /** + * {@inheritDoc} + */ + @Override + public List listRegions(Integer id, String name) { + return _regionDao.listByNameAndId(id, name); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteUserAccount(long accountId) { + AccountVO account = _accountDao.findById(accountId); + if(account == null){ + throw new InvalidParameterValueException("The specified account does not exist in the system"); + } + String accountUUID = account.getUuid(); + int regionId = account.getRegionId(); + + String command = "deleteAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, accountUUID)); + + if(getId() == regionId){ + if(_accountMgr.deleteUserAccount(accountId)){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted account :"+accountUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while deleting account :"+accountUUID+" in Region: "+region.getId()); + } + } + return true; + } else { + return false; + } + } else { + //First delete in the Region where account is created + Region region = _regionDao.findById(regionId); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted account :"+accountUUID+" in Region: "+region.getId()); + return true; + } else { + s_logger.error("Error while deleting account :"+accountUUID+" in Region: "+region.getId()); + return false; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Account updateAccount(UpdateAccountCmd cmd) { + Long accountId = cmd.getId(); + Long domainId = cmd.getDomainId(); + DomainVO domain = _domainDao.findById(domainId); + String accountName = cmd.getAccountName(); + String newAccountName = cmd.getNewName(); + String networkDomain = cmd.getNetworkDomain(); + //ToDo send details + Map details = cmd.getDetails(); + + Account account = null; + if (accountId != null) { + account = _accountDao.findById(accountId); + } else { + account = _accountDao.findEnabledAccount(accountName, domainId); + } + + // Check if account exists + if (account == null || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + s_logger.error("Unable to find account by accountId: " + accountId + " OR by name: " + accountName + " in domain " + domainId); + throw new InvalidParameterValueException("Unable to find account by accountId: " + accountId + " OR by name: " + accountName + " in domain " + domainId); + } + + String command = "updateAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.NEW_NAME, newAccountName)); + params.add(new NameValuePair(ApiConstants.ID, account.getUuid())); + params.add(new NameValuePair(ApiConstants.ACCOUNT, accountName)); + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, domain.getUuid())); + params.add(new NameValuePair(ApiConstants.NETWORK_DOMAIN, networkDomain)); + params.add(new NameValuePair(ApiConstants.NEW_NAME, newAccountName)); + if(details != null){ + params.add(new NameValuePair(ApiConstants.ACCOUNT_DETAILS, details.toString())); + } + int regionId = account.getRegionId(); + if(getId() == regionId){ + Account updatedAccount = _accountMgr.updateAccount(cmd); + if(updatedAccount != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully updated account :"+account.getUuid()+" in Region: "+region.getId()); + } else { + s_logger.error("Error while updating account :"+account.getUuid()+" in Region: "+region.getId()); + } + } + } + return updatedAccount; + } else { + //First update in the Region where account is created + Region region = _regionDao.findById(regionId); + RegionAccount updatedAccount = RegionsApiUtil.makeAccountAPICall(region, command, params); + if (updatedAccount != null) { + Long id = _identityDao.getIdentityId("account", updatedAccount.getUuid()); + updatedAccount.setId(id); + Long domainID = _identityDao.getIdentityId("domain", updatedAccount.getDomainUuid()); + updatedAccount.setDomainId(domainID); + s_logger.debug("Successfully updated account :"+account.getUuid()+" in source Region: "+region.getId()); + return updatedAccount; + } else { + throw new CloudRuntimeException("Error while updating account :"+account.getUuid()+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Account disableAccount(String accountName, Long domainId, Long accountId, Boolean lockRequested) throws ConcurrentOperationException, ResourceUnavailableException { + Account account = null; + if (accountId != null) { + account = _accountDao.findById(accountId); + } else { + account = _accountDao.findActiveAccount(accountName, domainId); + } + + if (account == null || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + throw new InvalidParameterValueException("Unable to find active account by accountId: " + accountId + " OR by name: " + accountName + " in domain " + domainId); + } + + String accountUUID = account.getUuid(); + + String command = "disableAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.LOCK, lockRequested.toString())); + params.add(new NameValuePair(ApiConstants.ID, accountUUID)); + DomainVO domain = _domainDao.findById(domainId); + if(domain != null){ + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, domain.getUuid())); + } + + int regionId = account.getRegionId(); + if(getId() == regionId){ + Account retAccount = null; + if(lockRequested){ + retAccount = _accountMgr.lockAccount(accountName, domainId, accountId); + } else { + retAccount = _accountMgr.disableAccount(accountName, domainId, accountId); + } + if(retAccount != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully disabled account :"+accountUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while disabling account :"+accountUUID+" in Region: "+region.getId()); + } + } + } + return retAccount; + } else { + //First disable account in the Region where account is created + Region region = _regionDao.findById(regionId); + Account retAccount = RegionsApiUtil.makeAccountAPICall(region, command, params); + if (retAccount != null) { + s_logger.debug("Successfully disabled account :"+accountUUID+" in source Region: "+region.getId()); + return retAccount; + } else { + throw new CloudRuntimeException("Error while disabling account :"+accountUUID+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Account enableAccount(String accountName, Long domainId, Long accountId) { + // Check if account exists + Account account = null; + if (accountId != null) { + account = _accountDao.findById(accountId); + } else { + account = _accountDao.findActiveAccount(accountName, domainId); + } + + if (account == null || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + throw new InvalidParameterValueException("Unable to find account by accountId: " + accountId + " OR by name: " + accountName + " in domain " + domainId); + } + + String accountUUID = account.getUuid(); + + String command = "enableAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, accountUUID)); + params.add(new NameValuePair(ApiConstants.ACCOUNT, accountName)); + DomainVO domain = _domainDao.findById(domainId); + if(domain != null){ + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, domain.getUuid())); + } + + int regionId = account.getRegionId(); + if(getId() == regionId){ + Account retAccount = _accountMgr.enableAccount(accountName, domainId, accountId); + if(retAccount != null){ + List regions = _regionDao.listAll(); + + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully enabled account :"+accountUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while enabling account :"+accountUUID+" in Region: "+region.getId()); + } + } + } + return retAccount; + } else { + //First disable account in the Region where account is created + Region region = _regionDao.findById(regionId); + Account retAccount = RegionsApiUtil.makeAccountAPICall(region, command, params); + if (retAccount != null) { + s_logger.debug("Successfully enabled account :"+accountUUID+" in source Region: "+region.getId()); + return retAccount; + } else { + throw new CloudRuntimeException("Error while enabling account :"+accountUUID+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteUser(DeleteUserCmd cmd) { + long id = cmd.getId(); + + UserVO user = _userDao.findById(id); + + if (user == null) { + throw new InvalidParameterValueException("The specified user doesn't exist in the system"); + } + + String userUUID = user.getUuid(); + int regionId = user.getRegionId(); + + String command = "deleteUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, userUUID)); + + if(getId() == regionId){ + if(_accountMgr.deleteUser(cmd)){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted user :"+userUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while deleting account :"+userUUID+" in Region: "+region.getId()); + } + } + return true; + } else { + return false; + } + } else { + //First delete in the Region where account is created + Region region = _regionDao.findById(regionId); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted user :"+userUUID+" in source Region: "+region.getId()); + return true; + } else { + s_logger.error("Error while deleting user :"+userUUID+" in source Region: "+region.getId()); + return false; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Domain updateDomain(UpdateDomainCmd cmd) { + long id = cmd.getId(); + DomainVO domain = _domainDao.findById(id); + if(domain == null){ + throw new InvalidParameterValueException("The specified domain doesn't exist in the system"); + } + + String domainUUID = domain.getUuid(); + + String command = "updateDomain"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, domainUUID)); + params.add(new NameValuePair(ApiConstants.NAME, cmd.getDomainName())); + params.add(new NameValuePair(ApiConstants.NETWORK_DOMAIN, cmd.getNetworkDomain())); + + int regionId = domain.getRegionId(); + if(getId() == regionId){ + Domain updatedDomain = _domainMgr.updateDomain(cmd); + if(updatedDomain != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully updated updatedDomain :"+domainUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while updating updatedDomain :"+domainUUID+" in Region: "+region.getId()); + } + } + } + return updatedDomain; + } else { + //First update in the Region where domain was created + Region region = _regionDao.findById(regionId); + RegionDomain updatedDomain = RegionsApiUtil.makeDomainAPICall(region, command, params); + if (updatedDomain != null) { + Long parentId = _identityDao.getIdentityId("domain", updatedDomain.getParentUuid()); + updatedDomain.setParent(parentId); + s_logger.debug("Successfully updated user :"+domainUUID+" in source Region: "+region.getId()); + return (DomainVO)updatedDomain; + } else { + throw new CloudRuntimeException("Error while updating user :"+domainUUID+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteDomain(Long id, Boolean cleanup) { + DomainVO domain = _domainDao.findById(id); + if(domain == null){ + throw new InvalidParameterValueException("The specified domain doesn't exist in the system"); + } + + String domainUUID = domain.getUuid(); + + String command = "deleteDomain"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, domainUUID)); + params.add(new NameValuePair(ApiConstants.CLEANUP, cleanup.toString())); + + int regionId = domain.getRegionId(); + if(getId() == regionId){ + if(_domainMgr.deleteDomain(id, cleanup)){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted domain :"+domainUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while deleting domain :"+domainUUID+" in Region: "+region.getId()); + } + } + return true; + } else { + return false; + } + } else { + //First delete in the Region where domain is created + Region region = _regionDao.findById(regionId); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted domain :"+domainUUID+" in Region: "+region.getId()); + return true; + } else { + s_logger.error("Error while deleting domain :"+domainUUID+" in Region: "+region.getId()); + return false; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount updateUser(UpdateUserCmd cmd) { + long id = cmd.getId(); + + UserVO user = _userDao.findById(id); + if (user == null) { + throw new InvalidParameterValueException("The specified user doesn't exist in the system"); + } + + String userUUID = user.getUuid(); + + String command = "updateUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, userUUID)); + params.add(new NameValuePair(ApiConstants.API_KEY, cmd.getApiKey())); + params.add(new NameValuePair(ApiConstants.EMAIL, cmd.getEmail())); + params.add(new NameValuePair(ApiConstants.FIRSTNAME, cmd.getFirstname())); + params.add(new NameValuePair(ApiConstants.LASTNAME, cmd.getLastname())); + params.add(new NameValuePair(ApiConstants.PASSWORD, cmd.getPassword())); + params.add(new NameValuePair(ApiConstants.SECRET_KEY, cmd.getSecretKey())); + params.add(new NameValuePair(ApiConstants.TIMEZONE, cmd.getTimezone())); + params.add(new NameValuePair(ApiConstants.USERNAME, cmd.getUsername())); + + int regionId = user.getRegionId(); + if(getId() == regionId){ + UserAccount updateUser = _accountMgr.updateUser(cmd); + if(updateUser != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully updated user :"+userUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while updating user :"+userUUID+" in Region: "+region.getId()); + } + } + } + return updateUser; + } else { + //First update in the Region where user was created + Region region = _regionDao.findById(regionId); + UserAccount updateUser = RegionsApiUtil.makeUserAccountAPICall(region, command, params); + if (updateUser != null) { + s_logger.debug("Successfully updated user :"+userUUID+" in source Region: "+region.getId()); + return updateUser; + } else { + throw new CloudRuntimeException("Error while updating user :"+userUUID+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount disableUser(Long userId) { + UserVO user = _userDao.findById(userId); + if (user == null || user.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to find active user by id " + userId); + } + + int regionId = user.getRegionId(); + + String command = "disableUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, user.getUuid())); + + if(getId() == regionId){ + UserAccount disabledUser = _accountMgr.disableUser(userId); + if(disabledUser != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully disabled user :"+user.getUuid()+" in Region: "+region.getId()); + } else { + s_logger.error("Error while disabling user :"+user.getUuid()+" in Region: "+region.getId()); + } + } + } + return disabledUser; + } else { + //First disable in the Region where user was created + Region region = _regionDao.findById(regionId); + UserAccount disabledUser = RegionsApiUtil.makeUserAccountAPICall(region, command, params); + if (disabledUser != null) { + s_logger.debug("Successfully disabled user :"+user.getUuid()+" in source Region: "+region.getId()); + return disabledUser; + } else { + throw new CloudRuntimeException("Error while disabling user :"+user.getUuid()+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount enableUser(long userId) { + UserVO user = _userDao.findById(userId); + if (user == null || user.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to find active user by id " + userId); + } + + int regionId = user.getRegionId(); + + String command = "enableUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, user.getUuid())); + + if(getId() == regionId){ + UserAccount enabledUser = _accountMgr.enableUser(userId); + if(enabledUser != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully enabled user :"+user.getUuid()+" in Region: "+region.getId()); + } else { + s_logger.error("Error while disabling user :"+user.getUuid()+" in Region: "+region.getId()); + } + } + } + return enabledUser; + } else { + //First enable in the Region where user was created + Region region = _regionDao.findById(regionId); + UserAccount enabledUser = RegionsApiUtil.makeUserAccountAPICall(region, command, params); + if (enabledUser != null) { + s_logger.debug("Successfully enabled user :"+user.getUuid()+" in source Region: "+region.getId()); + return enabledUser; + } else { + throw new CloudRuntimeException("Error while enabling user :"+user.getUuid()+" in source Region: "+region.getId()); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/RegionServiceImpl.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/RegionServiceImpl.java b/server/src/org/apache/cloudstack/region/RegionServiceImpl.java new file mode 100755 index 0000000..db592ad --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionServiceImpl.java @@ -0,0 +1,299 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.api.command.admin.account.DeleteAccountCmd; +import org.apache.cloudstack.api.command.admin.account.DisableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.EnableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.domain.DeleteDomainCmd; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.DisableUserCmd; +import org.apache.cloudstack.api.command.admin.user.EnableUserCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import org.apache.cloudstack.api.command.user.region.ListRegionsCmd; +import org.apache.cloudstack.region.dao.RegionDao; +import org.apache.log4j.Logger; + +import com.cloud.domain.Domain; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.DomainManager; +import com.cloud.user.UserAccount; +import com.cloud.user.UserContext; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.component.Inject; +import com.cloud.utils.component.Manager; + +@Local(value = { RegionService.class }) +public class RegionServiceImpl implements RegionService, Manager { + public static final Logger s_logger = Logger.getLogger(RegionServiceImpl.class); + + @Inject + private RegionDao _regionDao; + @Inject + private AccountDao _accountDao; + @Inject + private UserDao _userDao; + @Inject + private DomainDao _domainDao; + @Inject + private RegionManager _regionMgr; + @Inject + private AccountManager _accountMgr; + @Inject + private DomainManager _domainMgr; + + private String _name; + + @Override + public boolean configure(final String name, final Map params) throws ConfigurationException { + _name = name; + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + /** + * {@inheritDoc} + */ + @Override + public Region addRegion(int id, String name, String endPoint, String apiKey, String secretKey) { + //Check for valid Name + //Check valid end_point url + return _regionMgr.addRegion(id, name, endPoint, apiKey, secretKey); + } + + /** + * {@inheritDoc} + */ + @Override + public Region updateRegion(int id, String name, String endPoint, String apiKey, String secretKey) { + //Check for valid Name + //Check valid end_point url + return _regionMgr.updateRegion(id, name, endPoint, apiKey, secretKey); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean removeRegion(int id) { + return _regionMgr.removeRegion(id); + } + + /** + * {@inheritDoc} + */ + @Override + public List listRegions(ListRegionsCmd cmd) { + return _regionMgr.listRegions(cmd.getId(), cmd.getName()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteUserAccount(DeleteAccountCmd cmd) { + boolean result = false; + if(checkIsPropagate(cmd.getIsPropagate())){ + result = _accountMgr.deleteUserAccount(cmd.getId()); + } else { + result = _regionMgr.deleteUserAccount(cmd.getId()); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Account updateAccount(UpdateAccountCmd cmd) { + Account result = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + result = _accountMgr.updateAccount(cmd); + } else { + result = _regionMgr.updateAccount(cmd); + } + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Account disableAccount(DisableAccountCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException { + Account result = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + if(cmd.getLockRequested()) + result = _accountMgr.lockAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId()); + else + result = _accountMgr.disableAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId()); + } else { + result = _regionMgr.disableAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId(), cmd.getLockRequested()); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Account enableAccount(EnableAccountCmd cmd) { + Account result = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + result = _accountMgr.enableAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId()); + } else { + result = _regionMgr.enableAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId()); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteUser(DeleteUserCmd cmd) { + boolean result = false; + if(checkIsPropagate(cmd.getIsPropagate())){ + result = _accountMgr.deleteUser(cmd); + } else { + result = _regionMgr.deleteUser(cmd); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Domain updateDomain(UpdateDomainCmd cmd) { + Domain domain = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + domain = _domainMgr.updateDomain(cmd); + } else { + domain = _regionMgr.updateDomain(cmd); + } + return domain; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteDomain(DeleteDomainCmd cmd) { + boolean result = false; + if(checkIsPropagate(cmd.getIsPropagate())){ + result = _domainMgr.deleteDomain(cmd.getId(), cmd.getCleanup()); + } else { + result = _regionMgr.deleteDomain(cmd.getId(), cmd.getCleanup()); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount updateUser(UpdateUserCmd cmd){ + UserAccount user = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + user = _accountMgr.updateUser(cmd); + } else { + user = _regionMgr.updateUser(cmd); + } + return user; + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount disableUser(DisableUserCmd cmd) { + UserAccount user = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + user = _accountMgr.disableUser(cmd.getId()); + } else { + user = _regionMgr.disableUser(cmd.getId()); + } + return user; + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount enableUser(EnableUserCmd cmd) { + UserAccount user = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + user = _accountMgr.enableUser(cmd.getId()); + } else { + user = _regionMgr.enableUser(cmd.getId()); + } + return user; + } + + private boolean isRootAdmin(short accountType) { + return (accountType == Account.ACCOUNT_TYPE_ADMIN); + } + + /** + * Check isPopagate flag, Only ROOT Admin can use this param + * @param isPopagate + * @return + */ + private boolean checkIsPropagate(Boolean isPopagate){ + if(isPopagate == null || !isPopagate){ + return false; + } + // Only Admin can use isPopagate flag + UserContext ctx = UserContext.current(); + Account caller = ctx.getCaller(); + if(!isRootAdmin(caller.getType())){ + throw new PermissionDeniedException("isPropagate param cannot be used by non ROOT Admin"); + } + return true; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/RegionSyncVO.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/RegionSyncVO.java b/server/src/org/apache/cloudstack/region/RegionSyncVO.java new file mode 100644 index 0000000..271f8e3 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionSyncVO.java @@ -0,0 +1,93 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.utils.db.GenericDao; + + +@Entity +@Table(name="region_sync") +public class RegionSyncVO implements RegionSync { + + @Id + @Column(name="id") + private long id; + + @Column(name="region_id") + private int regionId; + + @Column(name="api") + private String api; + + @Column(name=GenericDao.CREATED_COLUMN) + private Date createDate; + + @Column(name="processed") + boolean processed; + + public RegionSyncVO() { + } + + public RegionSyncVO(int regionId, String api) { + this.regionId = regionId; + this.api = api; + } + + public int getRegionId() { + return regionId; + } + + public void setRegionId(int regionId) { + this.regionId = regionId; + } + + public String getApi() { + return api; + } + + public void setApi(String api) { + this.api = api; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public boolean isProcessed() { + return processed; + } + + public void setProcessed(boolean processed) { + this.processed = processed; + } + + public long getId() { + return id; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/RegionUser.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/RegionUser.java b/server/src/org/apache/cloudstack/region/RegionUser.java new file mode 100644 index 0000000..298638e --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionUser.java @@ -0,0 +1,76 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import com.cloud.user.UserVO; + +public class RegionUser extends UserVO { + String accountUuid; + String created; + String account; + String accounttype; + String domainid; + String domain; + + public RegionUser() { + } + + public String getAccountuuid() { + return accountUuid; + } + + public void setAccountuuid(String accountUuid) { + this.accountUuid = accountUuid; + } + + public void setCreated(String created) { + this.created = created; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getAccounttype() { + return accounttype; + } + + public void setAccounttype(String accounttype) { + this.accounttype = accounttype; + } + + public String getDomainid() { + return domainid; + } + + public void setDomainid(String domainid) { + this.domainid = domainid; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/RegionVO.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/RegionVO.java b/server/src/org/apache/cloudstack/region/RegionVO.java new file mode 100644 index 0000000..0c36db2 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionVO.java @@ -0,0 +1,93 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + + +@Entity +@Table(name="region") +public class RegionVO implements Region{ + + @Id + @Column(name="id") + private int id; + + @Column(name="name") + private String name; + + @Column(name="end_point") + private String endPoint; + + @Column(name="api_key") + private String apiKey; + + @Column(name="secret_key") + private String secretKey; + + public RegionVO() { + } + + public RegionVO(int id, String name, String endPoint, String apiKey, String secretKey) { + this.id = id; + this.name = name; + this.endPoint = endPoint; + this.apiKey = apiKey; + this.secretKey = secretKey; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEndPoint() { + return endPoint; + } + + public void setEndPoint(String endPoint) { + this.endPoint = endPoint; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/RegionsApiUtil.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/RegionsApiUtil.java b/server/src/org/apache/cloudstack/region/RegionsApiUtil.java new file mode 100644 index 0000000..c7625db --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionsApiUtil.java @@ -0,0 +1,306 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.log4j.Logger; + +import com.cloud.domain.DomainVO; +import com.cloud.user.UserAccount; +import com.cloud.user.UserAccountVO; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; + +/** + * Utility class for making API calls between peer Regions + * + */ +public class RegionsApiUtil { + public static final Logger s_logger = Logger.getLogger(RegionsApiUtil.class); + + /** + * Makes an api call using region service end_point, api command and params + * @param region + * @param command + * @param params + * @return True, if api is successful + */ + protected static boolean makeAPICall(Region region, String command, List params){ + try { + String apiParams = buildParams(command, params); + String url = buildUrl(apiParams, region); + HttpClient client = new HttpClient(); + HttpMethod method = new GetMethod(url); + if( client.executeMethod(method) == 200){ + return true; + } else { + return false; + } + } catch (HttpException e) { + s_logger.error(e.getMessage()); + return false; + } catch (IOException e) { + s_logger.error(e.getMessage()); + return false; + } + } + + /** + * Makes an api call using region service end_point, api command and params + * Returns Account object on success + * @param region + * @param command + * @param params + * @return + */ + protected static RegionAccount makeAccountAPICall(Region region, String command, List params){ + try { + String url = buildUrl(buildParams(command, params), region); + HttpClient client = new HttpClient(); + HttpMethod method = new GetMethod(url); + if( client.executeMethod(method) == 200){ + InputStream is = method.getResponseBodyAsStream(); + //Translate response to Account object + XStream xstream = new XStream(new DomDriver()); + xstream.alias("account", RegionAccount.class); + xstream.alias("user", RegionUser.class); + xstream.aliasField("id", RegionAccount.class, "uuid"); + xstream.aliasField("name", RegionAccount.class, "accountName"); + xstream.aliasField("accounttype", RegionAccount.class, "type"); + xstream.aliasField("domainid", RegionAccount.class, "domainUuid"); + xstream.aliasField("networkdomain", RegionAccount.class, "networkDomain"); + xstream.aliasField("id", RegionUser.class, "uuid"); + xstream.aliasField("accountId", RegionUser.class, "accountUuid"); + ObjectInputStream in = xstream.createObjectInputStream(is); + return (RegionAccount)in.readObject(); + } else { + return null; + } + } catch (HttpException e) { + s_logger.error(e.getMessage()); + return null; + } catch (IOException e) { + s_logger.error(e.getMessage()); + return null; + } catch (ClassNotFoundException e) { + s_logger.error(e.getMessage()); + return null; + } + } + + /** + * Makes an api call using region service end_point, api command and params + * Returns Domain object on success + * @param region + * @param command + * @param params + * @return + */ + protected static RegionDomain makeDomainAPICall(Region region, String command, List params){ + try { + String url = buildUrl(buildParams(command, params), region); + HttpClient client = new HttpClient(); + HttpMethod method = new GetMethod(url); + if( client.executeMethod(method) == 200){ + InputStream is = method.getResponseBodyAsStream(); + XStream xstream = new XStream(new DomDriver()); + //Translate response to Domain object + xstream.alias("domain", RegionDomain.class); + xstream.aliasField("id", RegionDomain.class, "uuid"); + xstream.aliasField("parentdomainid", RegionDomain.class, "parentUuid"); + xstream.aliasField("networkdomain", DomainVO.class, "networkDomain"); + ObjectInputStream in = xstream.createObjectInputStream(is); + return (RegionDomain)in.readObject(); + } else { + return null; + } + } catch (HttpException e) { + s_logger.error(e.getMessage()); + return null; + } catch (IOException e) { + s_logger.error(e.getMessage()); + return null; + } catch (ClassNotFoundException e) { + s_logger.error(e.getMessage()); + return null; + } + } + + /** + * Makes an api call using region service end_point, api command and params + * Returns UserAccount object on success + * @param region + * @param command + * @param params + * @return + */ + protected static UserAccount makeUserAccountAPICall(Region region, String command, List params){ + try { + String url = buildUrl(buildParams(command, params), region); + HttpClient client = new HttpClient(); + HttpMethod method = new GetMethod(url); + if( client.executeMethod(method) == 200){ + InputStream is = method.getResponseBodyAsStream(); + XStream xstream = new XStream(new DomDriver()); + xstream.alias("useraccount", UserAccountVO.class); + xstream.aliasField("id", UserAccountVO.class, "uuid"); + ObjectInputStream in = xstream.createObjectInputStream(is); + return (UserAccountVO)in.readObject(); + } else { + return null; + } + } catch (HttpException e) { + s_logger.error(e.getMessage()); + return null; + } catch (IOException e) { + s_logger.error(e.getMessage()); + return null; + } catch (ClassNotFoundException e) { + s_logger.error(e.getMessage()); + return null; + } + } + + /** + * Builds parameters string with command and encoded param values + * @param command + * @param params + * @return + */ + protected static String buildParams(String command, List params) { + StringBuffer paramString = new StringBuffer("command="+command); + Iterator iter = params.iterator(); + try { + while(iter.hasNext()){ + NameValuePair param = iter.next(); + if(param.getValue() != null && !(param.getValue().isEmpty())){ + paramString.append("&"+param.getName()+"="+URLEncoder.encode(param.getValue(), "UTF-8")); + } + } + } + catch (UnsupportedEncodingException e) { + s_logger.error(e.getMessage()); + return null; + } + return paramString.toString(); + } + + /** + * Build URL for api call using region end_point + * Parameters are sorted and signed using secret_key + * @param apiParams + * @param region + * @return + */ + private static String buildUrl(String apiParams, Region region) { + + String apiKey = region.getApiKey(); + String secretKey = region.getSecretKey(); + + + if (apiKey == null || secretKey == null) { + return region.getEndPoint() +"?"+ apiParams; + } + + String encodedApiKey; + try { + encodedApiKey = URLEncoder.encode(apiKey, "UTF-8"); + + List sortedParams = new ArrayList(); + sortedParams.add("apikey=" + encodedApiKey.toLowerCase()); + StringTokenizer st = new StringTokenizer(apiParams, "&"); + String url = null; + boolean first = true; + while (st.hasMoreTokens()) { + String paramValue = st.nextToken(); + String param = paramValue.substring(0, paramValue.indexOf("=")); + String value = paramValue.substring(paramValue.indexOf("=") + 1, paramValue.length()); + if (first) { + url = param + "=" + value; + first = false; + } else { + url = url + "&" + param + "=" + value; + } + sortedParams.add(param.toLowerCase() + "=" + value.toLowerCase()); + } + Collections.sort(sortedParams); + + + //Construct the sorted URL and sign and URL encode the sorted URL with your secret key + String sortedUrl = null; + first = true; + for (String param : sortedParams) { + if (first) { + sortedUrl = param; + first = false; + } else { + sortedUrl = sortedUrl + "&" + param; + } + } + String encodedSignature = signRequest(sortedUrl, secretKey); + + String finalUrl = region.getEndPoint() +"?"+apiParams+ "&apiKey=" + apiKey + "&signature=" + encodedSignature; + + return finalUrl; + + } catch (UnsupportedEncodingException e) { + s_logger.error(e.getMessage()); + return null; + } + } + + /** + * 1. Signs a string with a secret key using SHA-1 2. Base64 encode the result 3. URL encode the final result + * + * @param request + * @param key + * @return + */ + private static String signRequest(String request, String key) { + try { + Mac mac = Mac.getInstance("HmacSHA1"); + SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacSHA1"); + mac.init(keySpec); + mac.update(request.getBytes()); + byte[] encryptedBytes = mac.doFinal(); + return URLEncoder.encode(Base64.encodeBase64String(encryptedBytes), "UTF-8"); + } catch (Exception ex) { + s_logger.error(ex.getMessage()); + return null; + } + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/dao/RegionDao.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/dao/RegionDao.java b/server/src/org/apache/cloudstack/region/dao/RegionDao.java new file mode 100644 index 0000000..1360eac --- /dev/null +++ b/server/src/org/apache/cloudstack/region/dao/RegionDao.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region.dao; + +import java.util.List; + +import org.apache.cloudstack.region.RegionVO; + +import com.cloud.utils.db.GenericDao; + +public interface RegionDao extends GenericDao { + + RegionVO findByName(String name); + + List listByNameAndId(Integer id, String name); +} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java b/server/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java new file mode 100644 index 0000000..feb6e62 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java @@ -0,0 +1,62 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region.dao; + +import java.util.List; + +import javax.ejb.Local; + +import org.apache.cloudstack.region.RegionVO; +import org.apache.log4j.Logger; + +import com.cloud.user.UserVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Local(value={RegionDao.class}) +public class RegionDaoImpl extends GenericDaoBase implements RegionDao { + private static final Logger s_logger = Logger.getLogger(RegionDaoImpl.class); + protected SearchBuilder NameSearch; + protected SearchBuilder AllFieldsSearch; + + public RegionDaoImpl(){ + NameSearch = createSearchBuilder(); + NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ); + NameSearch.done(); + + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), SearchCriteria.Op.EQ); + AllFieldsSearch.done(); + } + + @Override + public RegionVO findByName(String name) { + SearchCriteria sc = NameSearch.create(); + sc.setParameters("name", NameSearch); + return findOneBy(sc); + } + + @Override + public List listByNameAndId(Integer id, String name) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("id", id); + sc.setParameters("name", name); + return listBy(sc); + } +} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/dao/RegionSyncDao.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/dao/RegionSyncDao.java b/server/src/org/apache/cloudstack/region/dao/RegionSyncDao.java new file mode 100644 index 0000000..df287e5 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/dao/RegionSyncDao.java @@ -0,0 +1,24 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region.dao; + +import org.apache.cloudstack.region.RegionSyncVO; + +import com.cloud.utils.db.GenericDao; + +public interface RegionSyncDao extends GenericDao { +} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/server/src/org/apache/cloudstack/region/dao/RegionSyncDaoImpl.java ---------------------------------------------------------------------- diff --git a/server/src/org/apache/cloudstack/region/dao/RegionSyncDaoImpl.java b/server/src/org/apache/cloudstack/region/dao/RegionSyncDaoImpl.java new file mode 100644 index 0000000..a8fa33f --- /dev/null +++ b/server/src/org/apache/cloudstack/region/dao/RegionSyncDaoImpl.java @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region.dao; + +import javax.ejb.Local; + +import org.apache.cloudstack.region.RegionSyncVO; +import org.apache.log4j.Logger; + +import com.cloud.utils.db.GenericDaoBase; + +@Local(value={RegionSyncDao.class}) +public class RegionSyncDaoImpl extends GenericDaoBase implements RegionSyncDao { + private static final Logger s_logger = Logger.getLogger(RegionSyncDaoImpl.class); + + public RegionSyncDaoImpl(){ + + } +} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8b1a5b1d/setup/db/create-schema.sql ---------------------------------------------------------------------- diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 9a5dc2b..d50d1fa 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -2259,7 +2259,7 @@ CREATE TABLE `cloud`.`netscaler_pod_ref` ( CREATE TABLE `cloud`.`region` ( `id` int unsigned NOT NULL UNIQUE, - `name` varchar(255) NOT NULL, + `name` varchar(255) NOT NULL UNIQUE, `end_point` varchar(255) NOT NULL, `api_key` varchar(255), `secret_key` varchar(255),