You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mc...@apache.org on 2014/03/14 00:55:35 UTC

[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<String, String> params) throws Exception {
-         processParameters(cmd, params);
-         CallContext.current().setEventDisplayEnabled(cmd.isDisplayResourceEnabled());
-         cmd.create();
  
+     public void dispatchCreateCmd(final BaseAsyncCreateCmd cmd, final Map<String, String> params) throws Exception {
+         asyncCreationDispatchChain.dispatch(new DispatchTask(cmd, params));
+         CallContext.current().setEventDisplayEnabled(cmd.isDisplayResourceEnabled());
      }
  
 +    private void doAccessChecks(BaseCmd cmd, Map<Object, AccessType> 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<String, String> params, boolean execute) throws Exception {
-         processParameters(cmd, params);
-         CallContext ctx = CallContext.current();
+     public void dispatch(final BaseCmd cmd, final Map<String, String> 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<String, String> params) {
-         Map<Object, AccessType> entitiesToAccess = new HashMap<Object, AccessType>();
-         Map<String, Object> 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<Field> 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<Long> listParam = (List<Long>)field.get(cmd);
-                                             for (Long entityId : listParam) {
-                                                 Object entityObj = s_instance._entityMgr.findById(entity, entityId);
-                                                 entitiesToAccess.put(entityObj, checkAccess.accessType());
-                                             }
-                                             break;
-                                         /*
-                                          * case STRING: List<String> listParam =
-                                          * new ArrayList<String>(); 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<Class<?>> apiCmdList = s_apiNameCmdClassMap.get(apiName);
 +            if (apiCmdList == null) {
 +                apiCmdList = new ArrayList<Class<?>>();
 +                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<Long> 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<Long>();
+             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<UserVmJoinVO> 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<List<UserVmJoinVO>, Integer> searchForUserVMsByCriteria(Criteria c, Account caller, Long domainId, boolean isRecursive, List<Long> permittedAccounts,
 -        boolean listAll, ListProjectResourcesCriteria listProjectResourcesCriteria, Map<String, String> 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<UserVmJoinVO> 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<TemplateJoinVO> 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<ServiceOfferingDetailsVO> detailsVO = null;
 -        if (details != null) {
 +            if (details != null) {
-                 List<ServiceOfferingDetailsVO> detailsVO = new ArrayList<ServiceOfferingDetailsVO>();
+             // 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<ServiceOfferingDetailsVO>();
 -            for (Entry<String, String> detailEntry : details.entrySet()) {
 +                for (Entry<String, String> 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<State, VirtualMachine.Event, VirtualMachine> {
 -
 -    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<StoragePoolAllocator> _storagePoolAllocators;
 -
 -    public List<StoragePoolAllocator> getStoragePoolAllocators() {
 -        return _storagePoolAllocators;
 -    }
 +public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager, Listener,
 +        StateListener<State, VirtualMachine.Event, VirtualMachine> {
 +
 +    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<StoragePoolAllocator> _storagePoolAllocators;
 +
 +    public List<StoragePoolAllocator> getStoragePoolAllocators() {
 +        return _storagePoolAllocators;
 +    }
  
      public void setStoragePoolAllocators(List<StoragePoolAllocator> 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<DeploymentPlanner> _planners;
  
 -    protected List<DeploymentPlanner> _planners;
 -
 -    public List<DeploymentPlanner> getPlanners() {
 -        return _planners;
 -    }
 +    public List<DeploymentPlanner> getPlanners() {
 +        return _planners;
 +    }
  
      public void setPlanners(List<DeploymentPlanner> 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<Map<Volume, List<StoragePool>>, List<Volume>> result = findSuitablePoolsForVolumes(vmProfile, lastPlan, avoids, HostAllocator.RETURN_UPTO_ALL);
 -                Map<Volume, List<StoragePool>> suitableVolumeStoragePools = result.first();
 -                List<Volume> readyAndReusedVolumes = result.second();
 -
 -                // choose the potential pool for this VM for this host
 -                if (!suitableVolumeStoragePools.isEmpty()) {
 -                    List<Host> suitableHosts = new ArrayList<Host>();
 -                    suitableHosts.add(host);
 -                    Pair<Host, Map<Volume, StoragePool>> potentialResources = findPotentialDeploymentResources(
 +                Map<Volume, List<StoragePool>> suitableVolumeStoragePools = result.first();
 +                List<Volume> readyAndReusedVolumes = result.second();
 +
 +                // choose the potential pool for this VM for this host
 +                if (!suitableVolumeStoragePools.isEmpty()) {
 +                    List<Host> suitableHosts = new ArrayList<Host>();
 +                    suitableHosts.add(host);
 +                    Pair<Host, Map<Volume, StoragePool>> 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<Volume, StoragePool> 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<Volume, StoragePool> 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<IPAddressVO, InsufficientAddressCapacityException>() {
              @Override
              public IPAddressVO doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
 -                StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in ");
 -                boolean fetchFromDedicatedRange = false;
 -                List<Long> dedicatedVlanDbIds = new ArrayList<Long>();
 -                List<Long> nonDedicatedVlanDbIds = new ArrayList<Long>();
 -
 -                SearchCriteria<IPAddressVO> 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<Long> dedicatedVlanDbIds = new ArrayList<Long>();
 +        List<Long> nonDedicatedVlanDbIds = new ArrayList<Long>();
 +
 +        SearchCriteria<IPAddressVO> 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<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId());
 -                for (AccountVlanMapVO map : maps) {
 -                    if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
 -                        dedicatedVlanDbIds.add(map.getVlanDbId());
 -                }
 -                List<VlanVO> 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<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId());
 +        for (AccountVlanMapVO map : maps) {
 +            if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
 +                dedicatedVlanDbIds.add(map.getVlanDbId());
 +        }
 +        List<VlanVO> 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<IPAddressVO> addrs = _ipAddressDao.lockRows(sc, filter, true);
 +        List<IPAddressVO> 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
----------------------------------------------------------------------