Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 10FF210E7B for ; Thu, 13 Mar 2014 23:56:04 +0000 (UTC) Received: (qmail 25215 invoked by uid 500); 13 Mar 2014 23:55:37 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 24692 invoked by uid 500); 13 Mar 2014 23:55:15 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 23907 invoked by uid 99); 13 Mar 2014 23:54:57 -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, 13 Mar 2014 23:54:57 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id BD8B898079B; Thu, 13 Mar 2014 23:54:56 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: mchen@apache.org To: commits@cloudstack.apache.org Date: Thu, 13 Mar 2014 23:55:35 -0000 Message-Id: In-Reply-To: <12b9daed0a9e4902903d5ca04a968f98@git.apache.org> References: <12b9daed0a9e4902903d5ca04a968f98@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [42/50] [abbrv] Merge branch 'master' into rbac. http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/api/ApiDispatcher.java ---------------------------------------------------------------------- diff --cc server/src/com/cloud/api/ApiDispatcher.java index 4bc6578,27ff952..95074e2 --- a/server/src/com/cloud/api/ApiDispatcher.java +++ b/server/src/com/cloud/api/ApiDispatcher.java @@@ -33,14 -21,10 +21,13 @@@ import java.util.Map import javax.annotation.PostConstruct; import javax.inject.Inject; -import com.cloud.event.EventTypes; -import com.cloud.utils.ReflectUtil; -import com.cloud.vm.VirtualMachine; ++import org.apache.log4j.Logger; ++ +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.acl.InfrastructureEntity; - import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; - import org.apache.cloudstack.api.ACL; +import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; - import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCreateCmd; import org.apache.cloudstack.api.BaseAsyncCustomIdCmd; @@@ -50,43 -33,26 +36,33 @@@ import org.apache.cloudstack.api.BaseCu import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.jobs.AsyncJob; import org.apache.cloudstack.framework.jobs.AsyncJobManager; --import org.apache.log4j.Logger; - import com.cloud.exception.InvalidParameterValueException; + import com.cloud.api.dispatch.DispatchChain; + import com.cloud.api.dispatch.DispatchChainFactory; + import com.cloud.api.dispatch.DispatchTask; ++import com.cloud.event.EventTypes; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; - import com.cloud.utils.DateUtil; +import com.cloud.utils.ReflectUtil; - import com.cloud.utils.db.EntityManager; - import com.cloud.utils.exception.CSExceptionErrorCode; - import com.cloud.utils.exception.CloudRuntimeException; ++import com.cloud.vm.VirtualMachine; public class ApiDispatcher { private static final Logger s_logger = Logger.getLogger(ApiDispatcher.class.getName()); Long _createSnapshotQueueSizeLimit; + @Inject - AsyncJobManager _asyncMgr = null; - @Inject - AccountManager _accountMgr = null; + AsyncJobManager _asyncMgr; + + @Inject - EntityManager _entityMgr = null; ++ AccountManager _accountMgr; + - private static ApiDispatcher s_instance; + @Inject() + protected DispatchChainFactory dispatchChainFactory; - public static ApiDispatcher getInstance() { - return s_instance; - } + protected DispatchChain standardDispatchChain; + + protected DispatchChain asyncCreationDispatchChain; public ApiDispatcher() { } @@@ -100,41 -67,37 +77,54 @@@ _createSnapshotQueueSizeLimit = snapshotLimit; } - public void dispatchCreateCmd(BaseAsyncCreateCmd cmd, Map params) throws Exception { - processParameters(cmd, params); - CallContext.current().setEventDisplayEnabled(cmd.isDisplayResourceEnabled()); - cmd.create(); + public void dispatchCreateCmd(final BaseAsyncCreateCmd cmd, final Map params) throws Exception { + asyncCreationDispatchChain.dispatch(new DispatchTask(cmd, params)); + CallContext.current().setEventDisplayEnabled(cmd.isDisplayResourceEnabled()); } + private void doAccessChecks(BaseCmd cmd, Map entitiesToAccess) { + Account caller = CallContext.current().getCallingAccount(); + + APICommand commandAnnotation = cmd.getClass().getAnnotation(APICommand.class); + String apiName = commandAnnotation != null ? commandAnnotation.name() : null; + + if (!entitiesToAccess.isEmpty()) { + for (Object entity : entitiesToAccess.keySet()) { + if (entity instanceof ControlledEntity) { + _accountMgr.checkAccess(caller, entitiesToAccess.get(entity), false, apiName, (ControlledEntity) entity); + } else if (entity instanceof InfrastructureEntity) { + //FIXME: Move this code in adapter, remove code from Account manager + } + } + } + } + - public void dispatch(BaseCmd cmd, Map params, boolean execute) throws Exception { - processParameters(cmd, params); - CallContext ctx = CallContext.current(); + public void dispatch(final BaseCmd cmd, final Map params, final boolean execute) throws Exception { + // Let the chain of responsibility dispatch gradually + standardDispatchChain.dispatch(new DispatchTask(cmd, params)); + + final CallContext ctx = CallContext.current(); ctx.setEventDisplayEnabled(cmd.isDisplayResourceEnabled()); + // TODO This if shouldn't be here. Use polymorphism and move it to validateSpecificParameters if (cmd instanceof BaseAsyncCmd) { - BaseAsyncCmd asyncCmd = (BaseAsyncCmd)cmd; - String startEventId = params.get("ctxStartEventId"); + final BaseAsyncCmd asyncCmd = (BaseAsyncCmd)cmd; + final String startEventId = params.get(ApiConstants.CTX_START_EVENT_ID); + String uuid = params.get(ApiConstants.UUID); ctx.setStartEventId(Long.valueOf(startEventId)); + // Fow now use the key from EventTypes.java rather than getInstanceType bcz the later doesn't refer to the interfaces + // Add the resource id in the call context, also add some other first class object ids (for now vm) if available. + // TODO - this should be done for all the uuids passed in the cmd - so should be moved where uuid to id conversion happens. + if(EventTypes.getEntityForEvent(asyncCmd.getEventType()) != null){ + ctx.putContextParameter(EventTypes.getEntityForEvent(asyncCmd.getEventType()), uuid); + } + if(params.get(ApiConstants.VIRTUAL_MACHINE_ID) != null){ + ctx.putContextParameter(ReflectUtil.getEntityName(VirtualMachine.class), params.get(ApiConstants.VIRTUAL_MACHINE_ID)); + } + // Synchronise job on the object if needed if (asyncCmd.getJob() != null && asyncCmd.getSyncObjId() != null && asyncCmd.getSyncObjType() != null) { Long queueSizeLimit = null; @@@ -163,392 -127,6 +154,6 @@@ } cmd.execute(); - -- } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public static void processParameters(BaseCmd cmd, Map params) { - Map entitiesToAccess = new HashMap(); - Map unpackedParams = cmd.unpackParams(params); - - if (cmd instanceof BaseListCmd) { - Object pageSizeObj = unpackedParams.get(ApiConstants.PAGE_SIZE); - Long pageSize = null; - if (pageSizeObj != null) { - pageSize = Long.valueOf((String)pageSizeObj); - } - - if ((unpackedParams.get(ApiConstants.PAGE) == null) && (pageSize != null && !pageSize.equals(BaseListCmd.s_pageSizeUnlimited))) { - ServerApiException ex = new ServerApiException(ApiErrorCode.PARAM_ERROR, "\"page\" parameter is required when \"pagesize\" is specified"); - ex.setCSErrorCode(CSExceptionErrorCode.getCSErrCode(ex.getClass().getName())); - throw ex; - } else if (pageSize == null && (unpackedParams.get(ApiConstants.PAGE) != null)) { - throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "\"pagesize\" parameter is required when \"page\" is specified"); - } - } - - List fields = ReflectUtil.getAllFieldsForClass(cmd.getClass(), BaseCmd.class); - - for (Field field : fields) { - Parameter parameterAnnotation = field.getAnnotation(Parameter.class); - if ((parameterAnnotation == null) || !parameterAnnotation.expose()) { - continue; - } - - //TODO: Annotate @Validate on API Cmd classes, FIXME how to process Validate - RoleType[] allowedRoles = parameterAnnotation.authorized(); - if (allowedRoles.length > 0) { - boolean permittedParameter = false; - Account caller = CallContext.current().getCallingAccount(); - for (RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { - permittedParameter = true; - break; - } - } - if (!permittedParameter) { - s_logger.debug("Ignoring paremeter " + parameterAnnotation.name() + " as the caller is not authorized to pass it in"); - continue; - } - } - - Object paramObj = unpackedParams.get(parameterAnnotation.name()); - if (paramObj == null) { - if (parameterAnnotation.required()) { - throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to execute API command " + - cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8) + " due to missing parameter " + parameterAnnotation.name()); - } - continue; - } - - // marshall the parameter into the correct type and set the field value - try { - setFieldValue(field, cmd, paramObj, parameterAnnotation); - } catch (IllegalArgumentException argEx) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Unable to execute API command " + cmd.getCommandName() + " due to invalid value " + paramObj + " for parameter " + - parameterAnnotation.name()); - } - throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to execute API command " + - cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8) + " due to invalid value " + paramObj + " for parameter " + - parameterAnnotation.name()); - } catch (ParseException parseEx) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Invalid date parameter " + paramObj + " passed to command " + cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8)); - } - throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to parse date " + paramObj + " for command " + - cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8) + ", please pass dates in the format mentioned in the api documentation"); - } catch (InvalidParameterValueException invEx) { - throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to execute API command " + - cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8) + " due to invalid value. " + invEx.getMessage()); - } catch (CloudRuntimeException cloudEx) { - s_logger.error("CloudRuntimeException", cloudEx); - // FIXME: Better error message? This only happens if the API command is not executable, which typically - //means - // there was - // and IllegalAccessException setting one of the parameters. - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Internal error executing API command " + - cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8)); - } - - //check access on the resource this field points to - try { - ACL checkAccess = field.getAnnotation(ACL.class); - CommandType fieldType = parameterAnnotation.type(); - - if (checkAccess != null) { - // Verify that caller can perform actions in behalf of vm owner - //acumulate all Controlled Entities together. - - //parse the array of resource types and in case of map check access on key or value or both as specified in @acl - //implement external dao for classes that need findByName - //for maps, specify access to be checkd on key or value. - - // find the controlled entity DBid by uuid - if (parameterAnnotation.entityType() != null) { - Class[] entityList = parameterAnnotation.entityType()[0].getAnnotation(EntityReference.class).value(); - - for (Class entity : entityList) { - // Check if the parameter type is a single - // Id or list of id's/name's - switch (fieldType) { - case LIST: - CommandType listType = parameterAnnotation.collectionType(); - switch (listType) { - case LONG: - case UUID: - List listParam = (List)field.get(cmd); - for (Long entityId : listParam) { - Object entityObj = s_instance._entityMgr.findById(entity, entityId); - entitiesToAccess.put(entityObj, checkAccess.accessType()); - } - break; - /* - * case STRING: List listParam = - * new ArrayList(); listParam = - * (List)field.get(cmd); for(String - * entityName: listParam){ - * ControlledEntity entityObj = - * (ControlledEntity - * )daoClassInstance(entityId); - * entitiesToAccess.add(entityObj); } - * break; - */ - default: - break; - } - break; - case LONG: - case UUID: - Object entityObj = s_instance._entityMgr.findById(entity, (Long)field.get(cmd)); - entitiesToAccess.put(entityObj, checkAccess.accessType()); - break; - default: - break; - } - - if (ControlledEntity.class.isAssignableFrom(entity)) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("ControlledEntity name is:" + entity.getName()); - } + } - if (InfrastructureEntity.class.isAssignableFrom(entity)) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("InfrastructureEntity name is:" + entity.getName()); - } - } - } - - } - - } - - } catch (IllegalArgumentException e) { - s_logger.error("Error initializing command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible."); - throw new CloudRuntimeException("Internal error initializing parameters for command " + cmd.getCommandName() + " [field " + field.getName() + - " is not accessible]"); - } catch (IllegalAccessException e) { - s_logger.error("Error initializing command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible."); - throw new CloudRuntimeException("Internal error initializing parameters for command " + cmd.getCommandName() + " [field " + field.getName() + - " is not accessible]"); - } - - } - - //check access on the entities. - getInstance().doAccessChecks(cmd, entitiesToAccess); - - } - - private static Long translateUuidToInternalId(String uuid, Parameter annotation) { - if (uuid.equals("-1")) { - // FIXME: This is to handle a lot of hardcoded special cases where -1 is sent - // APITODO: Find and get rid of all hardcoded params in API Cmds and service layer - return -1L; - } - Long internalId = null; - // If annotation's empty, the cmd existed before 3.x try conversion to long - boolean isPre3x = annotation.since().isEmpty(); - // Match against Java's UUID regex to check if input is uuid string - boolean isUuid = uuid.matches("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"); - // Enforce that it's uuid for newly added apis from version 3.x - if (!isPre3x && !isUuid) - return null; - // Allow both uuid and internal id for pre3x apis - if (isPre3x && !isUuid) { - try { - internalId = Long.parseLong(uuid); - } catch (NumberFormatException e) { - internalId = null; - } - if (internalId != null) - return internalId; - } - // There may be multiple entities defined on the @EntityReference of a Response.class - // UUID CommandType would expect only one entityType, so use the first entityType - Class[] entities = annotation.entityType()[0].getAnnotation(EntityReference.class).value(); - // Go through each entity which is an interface to a VO class and get a VO object - // Try to getId() for the object using reflection, break on first non-null value - for (Class entity : entities) { - // For backward compatibility, we search within removed entities and let service layer deal - // with removed ones, return empty response or error - Object objVO = s_instance._entityMgr.findByUuidIncludingRemoved(entity, uuid); - if (objVO == null) { - continue; - } - // Invoke the getId method, get the internal long ID - // If that fails hide exceptions as the uuid may not exist - try { - internalId = ((InternalIdentity)objVO).getId(); - } catch (IllegalArgumentException e) { - } catch (NullPointerException e) { - } - // Return on first non-null Id for the uuid entity - if (internalId != null) - break; - } - if (internalId == null) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Object entity uuid = " + uuid + " does not exist in the database."); - throw new InvalidParameterValueException("Invalid parameter " + annotation.name() + " value=" + uuid + - " due to incorrect long value format, or entity does not exist or due to incorrect parameter annotation for the field in api cmd class."); - } - return internalId; - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private static void setFieldValue(Field field, BaseCmd cmdObj, Object paramObj, Parameter annotation) throws IllegalArgumentException, ParseException { - try { - field.setAccessible(true); - CommandType fieldType = annotation.type(); - switch (fieldType) { - case BOOLEAN: - field.set(cmdObj, Boolean.valueOf(paramObj.toString())); - break; - case DATE: - // This piece of code is for maintaining backward compatibility - // and support both the date formats(Bug 9724) - // Do the date messaging for ListEventsCmd only - if (cmdObj instanceof ListEventsCmd || cmdObj instanceof DeleteEventsCmd || cmdObj instanceof ArchiveEventsCmd || - cmdObj instanceof ArchiveAlertsCmd || cmdObj instanceof DeleteAlertsCmd) { - boolean isObjInNewDateFormat = isObjInNewDateFormat(paramObj.toString()); - if (isObjInNewDateFormat) { - DateFormat newFormat = BaseCmd.NEW_INPUT_FORMAT; - synchronized (newFormat) { - field.set(cmdObj, newFormat.parse(paramObj.toString())); - } - } else { - DateFormat format = BaseCmd.INPUT_FORMAT; - synchronized (format) { - Date date = format.parse(paramObj.toString()); - if (field.getName().equals("startDate")) { - date = messageDate(date, 0, 0, 0); - } else if (field.getName().equals("endDate")) { - date = messageDate(date, 23, 59, 59); - } - field.set(cmdObj, date); - } - } - } else { - DateFormat format = BaseCmd.INPUT_FORMAT; - synchronized (format) { - format.setLenient(false); - field.set(cmdObj, format.parse(paramObj.toString())); - } - } - break; - case FLOAT: - // Assuming that the parameters have been checked for required before now, - // we ignore blank or null values and defer to the command to set a default - // value for optional parameters ... - if (paramObj != null && isNotBlank(paramObj.toString())) { - field.set(cmdObj, Float.valueOf(paramObj.toString())); - } - break; - case INTEGER: - // Assuming that the parameters have been checked for required before now, - // we ignore blank or null values and defer to the command to set a default - // value for optional parameters ... - if (paramObj != null && isNotBlank(paramObj.toString())) { - field.set(cmdObj, Integer.valueOf(paramObj.toString())); - } - break; - case LIST: - List listParam = new ArrayList(); - StringTokenizer st = new StringTokenizer(paramObj.toString(), ","); - while (st.hasMoreTokens()) { - String token = st.nextToken(); - CommandType listType = annotation.collectionType(); - switch (listType) { - case INTEGER: - listParam.add(Integer.valueOf(token)); - break; - case UUID: - if (token.isEmpty()) - break; - Long internalId = translateUuidToInternalId(token, annotation); - listParam.add(internalId); - break; - case LONG: { - listParam.add(Long.valueOf(token)); - } - break; - case SHORT: - listParam.add(Short.valueOf(token)); - case STRING: - listParam.add(token); - break; - } - } - field.set(cmdObj, listParam); - break; - case UUID: - if (paramObj.toString().isEmpty()) - break; - Long internalId = translateUuidToInternalId(paramObj.toString(), annotation); - field.set(cmdObj, internalId); - break; - case LONG: - field.set(cmdObj, Long.valueOf(paramObj.toString())); - break; - case SHORT: - field.set(cmdObj, Short.valueOf(paramObj.toString())); - break; - case STRING: - if ((paramObj != null) && paramObj.toString().length() > annotation.length()) { - s_logger.error("Value greater than max allowed length " + annotation.length() + " for param: " + field.getName()); - throw new InvalidParameterValueException("Value greater than max allowed length " + annotation.length() + " for param: " + field.getName()); - } - field.set(cmdObj, paramObj.toString()); - break; - case TZDATE: - field.set(cmdObj, DateUtil.parseTZDateString(paramObj.toString())); - break; - case MAP: - default: - field.set(cmdObj, paramObj); - break; - } - } catch (IllegalAccessException ex) { - s_logger.error("Error initializing command " + cmdObj.getCommandName() + ", field " + field.getName() + " is not accessible."); - throw new CloudRuntimeException("Internal error initializing parameters for command " + cmdObj.getCommandName() + " [field " + field.getName() + - " is not accessible]"); - } - } - - private static boolean isObjInNewDateFormat(String string) { - Matcher matcher = BaseCmd.newInputDateFormat.matcher(string); - return matcher.matches(); - } - - private static Date messageDate(Date date, int hourOfDay, int minute, int second) { - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal.set(Calendar.HOUR_OF_DAY, hourOfDay); - cal.set(Calendar.MINUTE, minute); - cal.set(Calendar.SECOND, second); - return cal.getTime(); - } - - public static void plugService(Field field, BaseCmd cmd) { - - Class fc = field.getType(); - Object instance = null; - - if (instance == null) { - throw new CloudRuntimeException("Unable to plug service " + fc.getSimpleName() + " in command " + cmd.getClass().getSimpleName()); - } - - try { - field.setAccessible(true); - field.set(cmd, instance); - } catch (IllegalArgumentException e) { - s_logger.error("IllegalArgumentException at plugService for command " + cmd.getCommandName() + ", field " + field.getName()); - throw new CloudRuntimeException("Internal error at plugService for command " + cmd.getCommandName() + " [Illegal argumet at field " + field.getName() + "]"); - } catch (IllegalAccessException e) { - s_logger.error("Error at plugService for command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible."); - throw new CloudRuntimeException("Internal error at plugService for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]"); - } - } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/api/ApiResponseHelper.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/api/ApiServer.java ---------------------------------------------------------------------- diff --cc server/src/com/cloud/api/ApiServer.java index 5ab65f4,3502689..e4486c1 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@@ -53,39 -53,12 +53,40 @@@ import javax.naming.ConfigurationExcept import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import com.cloud.event.EventTypes; -import com.cloud.utils.ReflectUtil; -import com.cloud.vm.VirtualMachine; +import org.apache.commons.codec.binary.Base64; +import org.apache.http.ConnectionClosedException; +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpServerConnection; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.entity.BasicHttpEntity; +import org.apache.http.impl.DefaultHttpResponseFactory; +import org.apache.http.impl.DefaultHttpServerConnection; +import org.apache.http.impl.NoConnectionReuseStrategy; +import org.apache.http.impl.SocketHttpServerConnection; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.BasicHttpProcessor; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.apache.http.protocol.HttpRequestHandlerRegistry; +import org.apache.http.protocol.HttpService; +import org.apache.http.protocol.ResponseConnControl; +import org.apache.http.protocol.ResponseContent; +import org.apache.http.protocol.ResponseDate; +import org.apache.http.protocol.ResponseServer; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.api.APICommand; + import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCreateCmd; @@@ -122,12 -94,44 +123,15 @@@ import org.apache.cloudstack.framework. import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; import org.apache.cloudstack.managed.context.ManagedContextRunnable; -import org.apache.commons.codec.binary.Base64; -import org.apache.http.ConnectionClosedException; -import org.apache.http.HttpException; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpServerConnection; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.entity.BasicHttpEntity; -import org.apache.http.impl.DefaultHttpResponseFactory; -import org.apache.http.impl.DefaultHttpServerConnection; -import org.apache.http.impl.NoConnectionReuseStrategy; -import org.apache.http.impl.SocketHttpServerConnection; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.CoreConnectionPNames; -import org.apache.http.params.CoreProtocolPNames; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.BasicHttpProcessor; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpRequestHandler; -import org.apache.http.protocol.HttpRequestHandlerRegistry; -import org.apache.http.protocol.HttpService; -import org.apache.http.protocol.ResponseConnControl; -import org.apache.http.protocol.ResponseContent; -import org.apache.http.protocol.ResponseDate; -import org.apache.http.protocol.ResponseServer; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; + import com.cloud.api.dispatch.DispatchChainFactory; + import com.cloud.api.dispatch.DispatchTask; import com.cloud.api.response.ApiResponseSerializer; import com.cloud.configuration.Config; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.event.ActionEventUtils; ++import com.cloud.event.EventTypes; import com.cloud.exception.AccountLimitException; import com.cloud.exception.CloudAuthenticationException; import com.cloud.exception.InsufficientCapacityException; @@@ -144,6 -148,6 +148,7 @@@ import com.cloud.user.UserAccount import com.cloud.user.UserVO; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; ++import com.cloud.utils.ReflectUtil; import com.cloud.utils.StringUtils; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ManagerBase; @@@ -154,6 -158,6 +159,7 @@@ import com.cloud.utils.db.SearchCriteri import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExceptionProxyObject; ++import com.cloud.vm.VirtualMachine; @Component public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiServerService { @@@ -234,14 -245,12 +248,15 @@@ if (at == null) { throw new CloudRuntimeException(String.format("%s is claimed as a API command, but it doesn't have @APICommand annotation", cmdClass.getName())); } - final String apiName = at.name(); - if (s_apiNameCmdClassMap.containsKey(apiName)) { - s_logger.error("API Cmd class " + cmdClass.getName() + " has non-unique apiname" + apiName); - continue; ++ + String apiName = at.name(); + List> apiCmdList = s_apiNameCmdClassMap.get(apiName); + if (apiCmdList == null) { + apiCmdList = new ArrayList>(); + s_apiNameCmdClassMap.put(apiName, apiCmdList); } - s_apiNameCmdClassMap.put(apiName, cmdClass); + apiCmdList.add(cmdClass); + } setEncodeApiResponse(Boolean.valueOf(_configDao.getValue(Config.EncodeApiResponse.key()))); @@@ -392,10 -414,10 +420,10 @@@ StringUtils.cleanString(response)); } else - buildAuditTrail(auditTrailSb, command[0], response); + buildAuditTrail(auditTrailSb, command[0], response); } else { if (!command[0].equalsIgnoreCase("login") && !command[0].equalsIgnoreCase("logout")) { - String errorString = "Unknown API command: " + command[0]; + final String errorString = "Unknown API command: " + command[0]; s_logger.warn(errorString); auditTrailSb.append(" " + errorString); throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, errorString); @@@ -423,35 -445,35 +451,35 @@@ s_logger.info("PermissionDenied: " + ex.getMessage()); } throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, ex.getMessage(), ex); - } catch (AccountLimitException ex) { + } catch (final AccountLimitException ex) { s_logger.info(ex.getMessage()); throw new ServerApiException(ApiErrorCode.ACCOUNT_RESOURCE_LIMIT_ERROR, ex.getMessage(), ex); - } catch (InsufficientCapacityException ex) { + } catch (final InsufficientCapacityException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); - if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) { + if (!_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, errorMsg, ex); - } catch (ResourceAllocationException ex) { + } catch (final ResourceAllocationException ex) { s_logger.info(ex.getMessage()); throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage(), ex); - } catch (ResourceUnavailableException ex) { + } catch (final ResourceUnavailableException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); - if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) { + if (!_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, errorMsg, ex); - } catch (ServerApiException ex) { + } catch (final ServerApiException ex) { s_logger.info(ex.getDescription()); throw ex; - } catch (Exception ex) { - s_logger.error("unhandled exception executing api command: " + ((command == null) ? "null" : command[0]), ex); + } catch (final Exception ex) { + s_logger.error("unhandled exception executing api command: " + ((command == null) ? "null" : command), ex); String errorMsg = ex.getMessage(); - if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) { + if (!_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } @@@ -553,23 -589,12 +595,12 @@@ // if the command is of the listXXXCommand, we will need to also return the // the job id and status if possible // For those listXXXCommand which we have already created DB views, this step is not needed since async job is joined in their db views. - if (cmdObj instanceof BaseListCmd && !(cmdObj instanceof ListVMsCmd) && !(cmdObj instanceof ListRoutersCmd) - && !(cmdObj instanceof ListSecurityGroupsCmd) - && !(cmdObj instanceof ListTagsCmd) - && !(cmdObj instanceof ListEventsCmd) - && !(cmdObj instanceof ListVMGroupsCmd) - && !(cmdObj instanceof ListProjectsCmd) - && !(cmdObj instanceof ListProjectAccountsCmd) - && !(cmdObj instanceof ListProjectInvitationsCmd) - && !(cmdObj instanceof ListHostsCmd) - && !(cmdObj instanceof ListVolumesCmd) - && !(cmdObj instanceof ListUsersCmd) - && !(cmdObj instanceof ListAccountsCmd) - && !(cmdObj instanceof ListStoragePoolsCmd) - && !(cmdObj instanceof ListDiskOfferingsCmd) - && !(cmdObj instanceof ListServiceOfferingsCmd) - && !(cmdObj instanceof ListZonesCmd) - ) { + if (cmdObj instanceof BaseListCmd && !(cmdObj instanceof ListVMsCmd) && !(cmdObj instanceof ListRoutersCmd) && !(cmdObj instanceof ListSecurityGroupsCmd) && + !(cmdObj instanceof ListTagsCmd) && !(cmdObj instanceof ListEventsCmd) && !(cmdObj instanceof ListVMGroupsCmd) && !(cmdObj instanceof ListProjectsCmd) && + !(cmdObj instanceof ListProjectAccountsCmd) && !(cmdObj instanceof ListProjectInvitationsCmd) && !(cmdObj instanceof ListHostsCmd) && + !(cmdObj instanceof ListVolumesCmd) && !(cmdObj instanceof ListUsersCmd) && !(cmdObj instanceof ListAccountsCmd) && + !(cmdObj instanceof ListStoragePoolsCmd) && !(cmdObj instanceof ListDiskOfferingsCmd) && !(cmdObj instanceof ListServiceOfferingsCmd) && - !(cmdObj instanceof ListZonesByCmd)) { ++ !(cmdObj instanceof ListZonesCmd)) { buildAsyncListResponse((BaseListCmd) cmdObj, caller); } @@@ -988,10 -988,10 +1019,10 @@@ .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false) .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) - .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); + .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); // Set up the HTTP protocol processor - BasicHttpProcessor httpproc = new BasicHttpProcessor(); + final BasicHttpProcessor httpproc = new BasicHttpProcessor(); httpproc.addInterceptor(new ResponseDate()); httpproc.addInterceptor(new ResponseServer()); httpproc.addInterceptor(new ResponseContent()); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/api/query/QueryManagerImpl.java ---------------------------------------------------------------------- diff --cc server/src/com/cloud/api/query/QueryManagerImpl.java index 96647f8,47d2aec..0554e3a --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@@ -751,50 -728,95 +751,61 @@@ public class QueryManagerImpl extends M Boolean isRecursive = domainIdRecursiveListProject.second(); ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); + Filter searchFilter = new Filter(UserVmJoinVO.class, "id", true, cmd.getStartIndex(), + cmd.getPageSizeVal()); + + List ids = null; + if (cmd.getId() != null) { + if (cmd.getIds() != null && !cmd.getIds().isEmpty()) { + throw new InvalidParameterValueException("Specify either id or ids but not both parameters"); + } + ids = new ArrayList(); + ids.add(cmd.getId()); + } else { + ids = cmd.getIds(); + } + - Criteria c = new Criteria("id", Boolean.TRUE, cmd.getStartIndex(), cmd.getPageSizeVal()); - // Criteria c = new Criteria(null, Boolean.FALSE, cmd.getStartIndex(), - // cmd.getPageSizeVal()); //version without default sorting - c.addCriteria(Criteria.KEYWORD, cmd.getKeyword()); - c.addCriteria(Criteria.ID, ids); - c.addCriteria(Criteria.NAME, cmd.getName()); - c.addCriteria(Criteria.STATE, cmd.getState()); - c.addCriteria(Criteria.DATACENTERID, cmd.getZoneId()); - c.addCriteria(Criteria.GROUPID, cmd.getGroupId()); - c.addCriteria(Criteria.FOR_VIRTUAL_NETWORK, cmd.getForVirtualNetwork()); - c.addCriteria(Criteria.NETWORKID, cmd.getNetworkId()); - c.addCriteria(Criteria.TEMPLATE_ID, cmd.getTemplateId()); - c.addCriteria(Criteria.ISO_ID, cmd.getIsoId()); - c.addCriteria(Criteria.VPC_ID, cmd.getVpcId()); - c.addCriteria(Criteria.AFFINITY_GROUP_ID, cmd.getAffinityGroupId()); - c.addCriteria(Criteria.SERVICE_OFFERING_ID, cmd.getServiceOfferingId()); - c.addCriteria(Criteria.DISPLAY, cmd.getDisplay()); + // first search distinct vm id by using query criteria and pagination + SearchBuilder sb = _userVmJoinDao.createSearchBuilder(); + sb.select(null, Func.DISTINCT, sb.entity().getId()); // select distinct ids - if (domainId != null) { - c.addCriteria(Criteria.DOMAINID, domainId); + String hypervisor = cmd.getHypervisor(); + Object name = cmd.getName(); + Object state = cmd.getState(); + Object zoneId = cmd.getZoneId(); + Object keyword = cmd.getKeyword(); + boolean isAdmin = false; + boolean isRootAdmin = false; + if (_accountMgr.isAdmin(caller.getType())) { + isAdmin = true; + } + if (_accountMgr.isRootAdmin(caller.getId())) { + isRootAdmin = true; } - if (HypervisorType.getType(hypervisor) != HypervisorType.None) { - c.addCriteria(Criteria.HYPERVISOR, hypervisor); - } else if (hypervisor != null) { + Object groupId = cmd.getGroupId(); + Object networkId = cmd.getNetworkId(); + if (HypervisorType.getType(hypervisor) == HypervisorType.None && hypervisor != null) { + // invalid hypervisor type input throw new InvalidParameterValueException("Invalid HypervisorType " + hypervisor); } - - // ignore these search requests if it's not an admin - if (_accountMgr.isAdmin(caller.getType())) { - c.addCriteria(Criteria.PODID, cmd.getPodId()); - c.addCriteria(Criteria.HOSTID, cmd.getHostId()); - c.addCriteria(Criteria.STORAGE_ID, cmd.getStorageId()); + Object templateId = cmd.getTemplateId(); + Object isoId = cmd.getIsoId(); + Object vpcId = cmd.getVpcId(); + Object affinityGroupId = cmd.getAffinityGroupId(); + Object serviceOffId = cmd.getServiceOfferingId(); + Object pod = null; + Object hostId = null; + Object storageId = null; + if (cmd instanceof ListVMsCmdByAdmin) { + ListVMsCmdByAdmin adCmd = (ListVMsCmdByAdmin)cmd; + pod = adCmd.getPodId(); + hostId = adCmd.getHostId(); + storageId = adCmd.getStorageId(); } - if (!permittedAccounts.isEmpty()) { - c.addCriteria(Criteria.ACCOUNTID, permittedAccounts.toArray()); - } - c.addCriteria(Criteria.ISADMIN, _accountMgr.isAdmin(caller.getType())); - - return searchForUserVMsByCriteria(c, caller, domainId, isRecursive, permittedAccounts, listAll, listProjectResourcesCriteria, tags); - } - - private Pair, Integer> searchForUserVMsByCriteria(Criteria c, Account caller, Long domainId, boolean isRecursive, List permittedAccounts, - boolean listAll, ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags) { - Filter searchFilter = new Filter(UserVmJoinVO.class, c.getOrderBy(), c.getAscending(), c.getOffset(), c.getLimit()); - boolean isRootAdmin = _accountMgr.isRootAdmin(caller.getType()); - - // first search distinct vm id by using query criteria and pagination - SearchBuilder sb = _userVmJoinDao.createSearchBuilder(); - sb.select(null, Func.DISTINCT, sb.entity().getId()); // select distinct - // ids - _accountMgr.buildACLViewSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); - - Object id = c.getCriteria(Criteria.ID); - Object name = c.getCriteria(Criteria.NAME); - Object state = c.getCriteria(Criteria.STATE); - Object notState = c.getCriteria(Criteria.NOTSTATE); - Object zoneId = c.getCriteria(Criteria.DATACENTERID); - Object pod = c.getCriteria(Criteria.PODID); - Object hostId = c.getCriteria(Criteria.HOSTID); - Object hostName = c.getCriteria(Criteria.HOSTNAME); - Object keyword = c.getCriteria(Criteria.KEYWORD); - Object isAdmin = c.getCriteria(Criteria.ISADMIN); - assert c.getCriteria(Criteria.IPADDRESS) == null : "We don't support search by ip address on VM any more. If you see this assert, it means we have to find a different way to search by the nic table."; - Object groupId = c.getCriteria(Criteria.GROUPID); - Object networkId = c.getCriteria(Criteria.NETWORKID); - Object hypervisor = c.getCriteria(Criteria.HYPERVISOR); - Object storageId = c.getCriteria(Criteria.STORAGE_ID); - Object templateId = c.getCriteria(Criteria.TEMPLATE_ID); - Object isoId = c.getCriteria(Criteria.ISO_ID); - Object vpcId = c.getCriteria(Criteria.VPC_ID); - Object affinityGroupId = c.getCriteria(Criteria.AFFINITY_GROUP_ID); - Object serviceOffId = c.getCriteria(Criteria.SERVICE_OFFERING_ID); - Object display = c.getCriteria(Criteria.DISPLAY); - sb.and("displayName", sb.entity().getDisplayName(), SearchCriteria.Op.LIKE); - sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); sb.and("stateEQ", sb.entity().getState(), SearchCriteria.Op.EQ); sb.and("stateNEQ", sb.entity().getState(), SearchCriteria.Op.NEQ); @@@ -877,8 -899,11 +888,11 @@@ sc.setParameters("display", display); } -- if (id != null) { - sc.setParameters("id", id); - List idList = (id instanceof List ? (List)id : null); ++ if (ids != null) { ++ List idList = (ids instanceof List ? (List)ids : null); + if (idList != null && !idList.isEmpty()) { + sc.setParameters("idIN", idList.toArray()); + } } if (templateId != null) { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java ---------------------------------------------------------------------- diff --cc server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java index 92f5110,07b4c91..1cab6e8 --- a/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java @@@ -59,9 -57,9 +59,9 @@@ public class TemplateJoinDaoImpl extend public static final Logger s_logger = Logger.getLogger(TemplateJoinDaoImpl.class); @Inject - private ConfigurationDao _configDao; + private ConfigurationDao _configDao; @Inject - public AccountService _accountService; + private AccountService _accountService; private final SearchBuilder tmpltIdPairSearch; @@@ -98,24 -96,33 +98,23 @@@ _count = "select count(distinct temp_zone_pair) from template_view WHERE "; } - private String getTemplateStatus(TemplateJoinVO template) { - boolean isAdmin = false; - Account caller = CallContext.current().getCallingAccount(); - if ((caller == null) || _accountService.isAdmin(caller.getType())) { - isAdmin = true; - } - - // If the user is an Admin, add the template download status String templateStatus = null; - if (isAdmin || caller.getId() == template.getAccountId()) { - // add download status - if (template.getDownloadState() != Status.DOWNLOADED) { - templateStatus = "Processing"; - if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) { - if (template.getDownloadPercent() == 100) { - templateStatus = "Installing Template"; - } else { - templateStatus = template.getDownloadPercent() + "% Downloaded"; - } + if (template.getDownloadState() != Status.DOWNLOADED) { + templateStatus = "Processing"; + if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) { + if (template.getDownloadPercent() == 100) { + templateStatus = "Installing Template"; } else { - templateStatus = template.getErrorString(); + templateStatus = template.getDownloadPercent() + "% Downloaded"; } - } else if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { - templateStatus = "Download Complete"; } else { - templateStatus = "Successfully Installed"; + templateStatus = template.getErrorString(); } + } else if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { + templateStatus = "Download Complete"; + } else { + templateStatus = "Successfully Installed"; } return templateStatus; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java ---------------------------------------------------------------------- diff --cc server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index a5dfb16,235902c..779ddb4 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@@ -42,9 -40,10 +42,11 @@@ import org.apache.cloudstack.framework. import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.api.query.vo.UserVmJoinVO; + import com.cloud.gpu.GPU; import com.cloud.hypervisor.Hypervisor.HypervisorType; + import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.user.Account; +import com.cloud.user.AccountManager; import com.cloud.uservm.UserVm; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/api/query/vo/EventJoinVO.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/configuration/ConfigurationManagerImpl.java ---------------------------------------------------------------------- diff --cc server/src/com/cloud/configuration/ConfigurationManagerImpl.java index b739d30,2d4539c..9b9bd13 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@@ -2035,13 -2075,62 +2076,62 @@@ public class ConfigurationManagerImpl e if ((iopsWriteRate != null) && (iopsWriteRate > 0)) offering.setIopsWriteRate(iopsWriteRate); - if ((offering = _serviceOfferingDao.persist(offering)) != null) { + if (hypervisorSnapshotReserve != null && hypervisorSnapshotReserve < 0) { + throw new InvalidParameterValueException("If provided, Hypervisor Snapshot Reserve must be greater than or equal to 0."); + } + + offering.setHypervisorSnapshotReserve(hypervisorSnapshotReserve); + + List detailsVO = null; - if (details != null) { + if (details != null) { - List detailsVO = new ArrayList(); + // Check if the user has passed the gpu-type before passing the VGPU type + if (!details.containsKey(GPU.Keys.pciDevice.toString()) && details.containsKey(GPU.Keys.vgpuType.toString())) { + throw new InvalidParameterValueException("Please specify the gpu type"); + } + detailsVO = new ArrayList(); - for (Entry detailEntry : details.entrySet()) { + for (Entry detailEntry : details.entrySet()) { + String value = null; + if (detailEntry.getKey().equals(GPU.Keys.pciDevice.toString())) { + for (GPU.Type type : GPU.Type.values()) { + if (detailEntry.getValue().equals(type.toString())) { + value = detailEntry.getValue(); + } + } + if (value == null) { + throw new InvalidParameterValueException("Please specify valid gpu type"); + } + } + if (detailEntry.getKey().equals(GPU.Keys.vgpuType.toString())) { + if (details.get(GPU.Keys.pciDevice.toString()).equals(GPU.Type.GPU_Passthrough.toString())) { + throw new InvalidParameterValueException("vgpuTypes are supported only with vGPU pciDevice"); + } + if (detailEntry.getValue() == null) { + throw new InvalidParameterValueException("With vGPU as pciDevice, vGPUType value cannot be null"); + } + for (GPU.vGPUType entry : GPU.vGPUType.values()) { + if (detailEntry.getValue().equals(entry.getType())) { + value = entry.getType(); + } + } + if (value == null || detailEntry.getValue().equals(GPU.vGPUType.passthrough.getType())) { + throw new InvalidParameterValueException("Please specify valid vGPU type"); + } + } - detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), detailEntry.getKey(), detailEntry.getValue(), true)); - } + detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), detailEntry.getKey(), detailEntry.getValue(), true)); + } + // If pciDevice type is passed, put the default VGPU type as 'passthrough' + if (details.containsKey(GPU.Keys.pciDevice.toString()) + && !details.containsKey(GPU.Keys.vgpuType.toString())) { + detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), + GPU.Keys.vgpuType.toString(), GPU.vGPUType.passthrough.getType(), true)); + } + } + if ((offering = _serviceOfferingDao.persist(offering)) != null) { + if (detailsVO != null && !detailsVO.isEmpty()) { + for (int index = 0; index < detailsVO.size(); index++) { + detailsVO.get(index).setResourceId(offering.getId()); + } _serviceOfferingDetailsDao.saveDetails(detailsVO); } CallContext.current().setEventDetails("Service offering id=" + offering.getId()); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java ---------------------------------------------------------------------- diff --cc server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index ee8cc4d,f76e485..74c141e --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@@ -61,108 -61,112 +61,112 @@@ import com.cloud.agent.api.Command import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.manager.allocator.HostAllocator; -import com.cloud.capacity.CapacityManager; -import com.cloud.capacity.dao.CapacityDao; -import com.cloud.configuration.Config; -import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterDetailsVO; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenterVO; +import com.cloud.capacity.CapacityManager; +import com.cloud.capacity.dao.CapacityDao; +import com.cloud.configuration.Config; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; import com.cloud.dc.DedicatedResourceVO; -import com.cloud.dc.Pod; -import com.cloud.dc.dao.ClusterDao; -import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.Pod; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DedicatedResourceDao; -import com.cloud.dc.dao.HostPodDao; -import com.cloud.deploy.DeploymentPlanner.ExcludeList; -import com.cloud.deploy.DeploymentPlanner.PlannerResourceUsage; -import com.cloud.deploy.dao.PlannerHostReservationDao; -import com.cloud.exception.AffinityConflictException; -import com.cloud.exception.ConnectionException; -import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.deploy.DeploymentPlanner.PlannerResourceUsage; +import com.cloud.deploy.dao.PlannerHostReservationDao; +import com.cloud.exception.AffinityConflictException; +import com.cloud.exception.ConnectionException; +import com.cloud.exception.InsufficientServerCapacityException; + import com.cloud.gpu.GPU; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.host.Status; -import com.cloud.host.dao.HostDao; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.offering.ServiceOffering; -import com.cloud.org.Cluster; -import com.cloud.org.Grouping; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.Status; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.offering.ServiceOffering; +import com.cloud.org.Cluster; +import com.cloud.org.Grouping; + import com.cloud.resource.ResourceManager; -import com.cloud.resource.ResourceState; +import com.cloud.resource.ResourceState; + import com.cloud.service.ServiceOfferingDetailsVO; + import com.cloud.service.dao.ServiceOfferingDetailsDao; -import com.cloud.storage.DiskOfferingVO; -import com.cloud.storage.ScopeType; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.ScopeType; import com.cloud.storage.Storage; -import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolHostVO; -import com.cloud.storage.Volume; -import com.cloud.storage.VolumeVO; -import com.cloud.storage.dao.DiskOfferingDao; -import com.cloud.storage.dao.GuestOSCategoryDao; -import com.cloud.storage.dao.GuestOSDao; -import com.cloud.storage.dao.StoragePoolHostDao; -import com.cloud.storage.dao.VolumeDao; -import com.cloud.user.AccountManager; -import com.cloud.utils.DateUtil; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.Pair; -import com.cloud.utils.component.Manager; -import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.TransactionCallback; -import com.cloud.utils.db.TransactionStatus; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.GuestOSCategoryDao; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.AccountManager; +import com.cloud.utils.DateUtil; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.component.Manager; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.fsm.StateListener; -import com.cloud.vm.DiskProfile; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachine.Event; -import com.cloud.vm.VirtualMachine.State; +import com.cloud.utils.fsm.StateListener; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.Event; +import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.dao.VMInstanceDao; - +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + @Local(value = {DeploymentPlanningManager.class}) -public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager, Listener, - StateListener { - - private static final Logger s_logger = Logger.getLogger(DeploymentPlanningManagerImpl.class); - @Inject - AgentManager _agentMgr; - @Inject - protected UserVmDao _vmDao; - @Inject - protected VMInstanceDao _vmInstanceDao; - @Inject - protected AffinityGroupDao _affinityGroupDao; - @Inject - protected AffinityGroupVMMapDao _affinityGroupVMMapDao; - @Inject - AffinityGroupService _affinityGroupService; - @Inject - DataCenterDao _dcDao; - @Inject - PlannerHostReservationDao _plannerHostReserveDao; - private int _vmCapacityReleaseInterval; - @Inject - MessageBus _messageBus; - private Timer _timer = null; - private long _hostReservationReleasePeriod = 60L * 60L * 1000L; // one hour by default - @Inject - protected VMReservationDao _reservationDao; - - private static final long INITIAL_RESERVATION_RELEASE_CHECKER_DELAY = 30L * 1000L; // thirty seconds expressed in milliseconds - protected long _nodeId = -1; - - protected List _storagePoolAllocators; - - public List getStoragePoolAllocators() { - return _storagePoolAllocators; - } +public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager, Listener, + StateListener { + + private static final Logger s_logger = Logger.getLogger(DeploymentPlanningManagerImpl.class); + @Inject + AgentManager _agentMgr; + @Inject + protected UserVmDao _vmDao; + @Inject + protected VMInstanceDao _vmInstanceDao; + @Inject + protected AffinityGroupDao _affinityGroupDao; + @Inject + protected AffinityGroupVMMapDao _affinityGroupVMMapDao; + @Inject + AffinityGroupService _affinityGroupService; + @Inject + DataCenterDao _dcDao; + @Inject + PlannerHostReservationDao _plannerHostReserveDao; + private int _vmCapacityReleaseInterval; + @Inject + MessageBus _messageBus; + private Timer _timer = null; + private long _hostReservationReleasePeriod = 60L * 60L * 1000L; // one hour by default + @Inject + protected VMReservationDao _reservationDao; + + private static final long INITIAL_RESERVATION_RELEASE_CHECKER_DELAY = 30L * 1000L; // thirty seconds expressed in milliseconds + protected long _nodeId = -1; + + protected List _storagePoolAllocators; + + public List getStoragePoolAllocators() { + return _storagePoolAllocators; + } public void setStoragePoolAllocators(List storagePoolAllocators) { _storagePoolAllocators = storagePoolAllocators; @@@ -213,12 -217,16 +217,16 @@@ DataStoreManager dataStoreMgr; @Inject protected ClusterDetailsDao _clusterDetailsDao; + @Inject + protected ResourceManager _resourceMgr; + @Inject + protected ServiceOfferingDetailsDao _serviceOfferingDetailsDao; + + protected List _planners; - protected List _planners; - - public List getPlanners() { - return _planners; - } + public List getPlanners() { + return _planners; + } public void setPlanners(List planners) { _planners = planners; @@@ -318,50 -326,54 +326,54 @@@ DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), hostIdSpecified, plan.getPoolId(), null, plan.getReservationContext()); - + Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, lastPlan, avoids, HostAllocator.RETURN_UPTO_ALL); - Map> suitableVolumeStoragePools = result.first(); - List readyAndReusedVolumes = result.second(); - - // choose the potential pool for this VM for this host - if (!suitableVolumeStoragePools.isEmpty()) { - List suitableHosts = new ArrayList(); - suitableHosts.add(host); - Pair> potentialResources = findPotentialDeploymentResources( + Map> suitableVolumeStoragePools = result.first(); + List readyAndReusedVolumes = result.second(); + + // choose the potential pool for this VM for this host + if (!suitableVolumeStoragePools.isEmpty()) { + List suitableHosts = new ArrayList(); + suitableHosts.add(host); + Pair> potentialResources = findPotentialDeploymentResources( suitableHosts, suitableVolumeStoragePools, avoids, getPlannerUsage(planner, vmProfile, plan, avoids), readyAndReusedVolumes); - if (potentialResources != null) { - Pod pod = _podDao.findById(host.getPodId()); - Cluster cluster = _clusterDao.findById(host.getClusterId()); - Map storageVolMap = potentialResources.second(); - // remove the reused vol<->pool from destination, since - // we don't have to prepare this volume. - for (Volume vol : readyAndReusedVolumes) { - storageVolMap.remove(vol); - } - DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap); - s_logger.debug("Returning Deployment Destination: " + dest); - return dest; - } - } - } - s_logger.debug("Cannnot deploy to specified host, returning."); - return null; - } - - if (vm.getLastHostId() != null && haVmTag == null) { - s_logger.debug("This VM has last host_id specified, trying to choose the same host: " + vm.getLastHostId()); - - HostVO host = _hostDao.findById(vm.getLastHostId()); + if (potentialResources != null) { + Pod pod = _podDao.findById(host.getPodId()); + Cluster cluster = _clusterDao.findById(host.getClusterId()); + Map storageVolMap = potentialResources.second(); + // remove the reused vol<->pool from destination, since + // we don't have to prepare this volume. + for (Volume vol : readyAndReusedVolumes) { + storageVolMap.remove(vol); + } + DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap); + s_logger.debug("Returning Deployment Destination: " + dest); + return dest; + } + } + } + s_logger.debug("Cannnot deploy to specified host, returning."); + return null; + } + + if (vm.getLastHostId() != null && haVmTag == null) { + s_logger.debug("This VM has last host_id specified, trying to choose the same host: " + vm.getLastHostId()); + + HostVO host = _hostDao.findById(vm.getLastHostId()); + ServiceOfferingDetailsVO offeringDetails = null; - if (host == null) { - s_logger.debug("The last host of this VM cannot be found"); - } else if (avoids.shouldAvoid(host)) { - s_logger.debug("The last host of this VM is in avoid set"); - } else if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)) { + if (host == null) { + s_logger.debug("The last host of this VM cannot be found"); + } else if (avoids.shouldAvoid(host)) { + s_logger.debug("The last host of this VM is in avoid set"); + } else if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)) { s_logger.debug("The last Host, hostId: " + host.getId() + " already has max Running VMs(count includes system VMs), skipping this and trying other available hosts"); + } else if ((offeringDetails = _serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.vgpuType.toString())) != null + && !_resourceMgr.isGPUDeviceAvailable(host.getId(), offeringDetails.getValue())){ + s_logger.debug("The last host of this VM does not have required GPU devices available"); - } else { - if (host.getStatus() == Status.Up && host.getResourceState() == ResourceState.Enabled) { + } else { + if (host.getStatus() == Status.Up && host.getResourceState() == ResourceState.Enabled) { boolean hostTagsMatch = true; if(offering.getHostTag() != null){ _hostDao.loadHostTags(host); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/network/IpAddressManagerImpl.java ---------------------------------------------------------------------- diff --cc server/src/com/cloud/network/IpAddressManagerImpl.java index 5905fd3,15d1458..4b7d4b9 --- a/server/src/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/com/cloud/network/IpAddressManagerImpl.java @@@ -660,115 -660,115 +660,115 @@@ public class IpAddressManagerImpl exten IPAddressVO addr = Transaction.execute(new TransactionCallbackWithException() { @Override public IPAddressVO doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException { - StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in "); - boolean fetchFromDedicatedRange = false; - List dedicatedVlanDbIds = new ArrayList(); - List nonDedicatedVlanDbIds = new ArrayList(); - - SearchCriteria sc = null; - if (podId != null) { - sc = AssignIpAddressFromPodVlanSearch.create(); - sc.setJoinParameters("podVlanMapSB", "podId", podId); - errorMessage.append(" pod id=" + podId); - } else { - sc = AssignIpAddressSearch.create(); - errorMessage.append(" zone id=" + dcId); - } + StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in "); + boolean fetchFromDedicatedRange = false; + List dedicatedVlanDbIds = new ArrayList(); + List nonDedicatedVlanDbIds = new ArrayList(); + + SearchCriteria sc = null; + if (podId != null) { + sc = AssignIpAddressFromPodVlanSearch.create(); + sc.setJoinParameters("podVlanMapSB", "podId", podId); + errorMessage.append(" pod id=" + podId); + } else { + sc = AssignIpAddressSearch.create(); + errorMessage.append(" zone id=" + dcId); + } - // If owner has dedicated Public IP ranges, fetch IP from the dedicated range - // Otherwise fetch IP from the system pool - List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId()); - for (AccountVlanMapVO map : maps) { - if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId())) - dedicatedVlanDbIds.add(map.getVlanDbId()); - } - List nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId); - for (VlanVO nonDedicatedVlan : nonDedicatedVlans) { - if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId())) - nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId()); - } - if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) { - fetchFromDedicatedRange = true; - sc.setParameters("vlanId", dedicatedVlanDbIds.toArray()); + // If owner has dedicated Public IP ranges, fetch IP from the dedicated range + // Otherwise fetch IP from the system pool + List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId()); + for (AccountVlanMapVO map : maps) { + if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId())) + dedicatedVlanDbIds.add(map.getVlanDbId()); + } + List nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId); + for (VlanVO nonDedicatedVlan : nonDedicatedVlans) { + if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId())) + nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId()); + } + if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) { + fetchFromDedicatedRange = true; + sc.setParameters("vlanId", dedicatedVlanDbIds.toArray()); errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray())); - } else if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { - sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); + } else if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { + sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); - } else { - if (podId != null) { - InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); - ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); - throw ex; - } - s_logger.warn(errorMessage.toString()); - InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId); - ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); - throw ex; - } + } else { + if (podId != null) { + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); + ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); + throw ex; + } + s_logger.warn(errorMessage.toString()); + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId); + ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); + throw ex; + } - sc.setParameters("dc", dcId); + sc.setParameters("dc", dcId); - DataCenter zone = _entityMgr.findById(DataCenter.class, dcId); + DataCenter zone = _entityMgr.findById(DataCenter.class, dcId); - // for direct network take ip addresses only from the vlans belonging to the network - if (vlanUse == VlanType.DirectAttached) { - sc.setJoinParameters("vlan", "networkId", guestNetworkId); - errorMessage.append(", network id=" + guestNetworkId); - } - sc.setJoinParameters("vlan", "type", vlanUse); + // for direct network take ip addresses only from the vlans belonging to the network + if (vlanUse == VlanType.DirectAttached) { + sc.setJoinParameters("vlan", "networkId", guestNetworkId); + errorMessage.append(", network id=" + guestNetworkId); + } + sc.setJoinParameters("vlan", "type", vlanUse); - if (requestedIp != null) { - sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp); - errorMessage.append(": requested ip " + requestedIp + " is not available"); - } + if (requestedIp != null) { + sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp); + errorMessage.append(": requested ip " + requestedIp + " is not available"); + } - Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l); + Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l); - List addrs = _ipAddressDao.lockRows(sc, filter, true); + List addrs = _ipAddressDao.lockRows(sc, filter, true); - // If all the dedicated IPs of the owner are in use fetch an IP from the system pool - if (addrs.size() == 0 && fetchFromDedicatedRange) { - // Verify if account is allowed to acquire IPs from the system - boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId()); - if (useSystemIps && nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { - fetchFromDedicatedRange = false; - sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); + // If all the dedicated IPs of the owner are in use fetch an IP from the system pool + if (addrs.size() == 0 && fetchFromDedicatedRange) { + // Verify if account is allowed to acquire IPs from the system + boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId()); + if (useSystemIps && nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { + fetchFromDedicatedRange = false; + sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); - addrs = _ipAddressDao.lockRows(sc, filter, true); - } - } + addrs = _ipAddressDao.lockRows(sc, filter, true); + } + } - if (addrs.size() == 0) { - if (podId != null) { - InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); - // for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object. - ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); - throw ex; - } - s_logger.warn(errorMessage.toString()); - InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId); - ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); - throw ex; - } + if (addrs.size() == 0) { + if (podId != null) { + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); + // for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object. + ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); + throw ex; + } + s_logger.warn(errorMessage.toString()); + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId); + ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); + throw ex; + } - assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size(); + assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size(); - if (!fetchFromDedicatedRange) { - // Check that the maximum number of public IPs for the given accountId will not be exceeded - try { - _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip); - } catch (ResourceAllocationException ex) { - s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner); - throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded."); - } - } + if (!fetchFromDedicatedRange) { + // Check that the maximum number of public IPs for the given accountId will not be exceeded + try { + _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip); + } catch (ResourceAllocationException ex) { + s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner); + throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded."); + } + } - IPAddressVO addr = addrs.get(0); - addr.setSourceNat(sourceNat); - addr.setAllocatedTime(new Date()); - addr.setAllocatedInDomainId(owner.getDomainId()); - addr.setAllocatedToAccountId(owner.getId()); - addr.setSystem(isSystem); + IPAddressVO addr = addrs.get(0); + addr.setSourceNat(sourceNat); + addr.setAllocatedTime(new Date()); + addr.setAllocatedInDomainId(owner.getDomainId()); + addr.setAllocatedToAccountId(owner.getId()); + addr.setSystem(isSystem); if (displayIp != null) { addr.setDisplay(displayIp); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99bdc8d8/server/src/com/cloud/network/NetworkServiceImpl.java ----------------------------------------------------------------------