コード例 #1
0
 @Override
 public Map<String, UsageNetworkVO> getRecentNetworkStats() {
   Transaction txn = Transaction.open(Transaction.USAGE_DB);
   String sql = SELECT_LATEST_STATS;
   PreparedStatement pstmt = null;
   try {
     pstmt = txn.prepareAutoCloseStatement(sql);
     ResultSet rs = pstmt.executeQuery();
     Map<String, UsageNetworkVO> returnMap = new HashMap<String, UsageNetworkVO>();
     while (rs.next()) {
       long accountId = rs.getLong(1);
       long zoneId = rs.getLong(2);
       Long hostId = rs.getLong(3);
       String hostType = rs.getString(4);
       Long networkId = rs.getLong(5);
       long bytesSent = rs.getLong(6);
       long bytesReceived = rs.getLong(7);
       long aggBytesReceived = rs.getLong(8);
       long aggBytesSent = rs.getLong(9);
       long eventTimeMillis = rs.getLong(10);
       if (hostId != 0) {
         returnMap.put(
             zoneId + "-" + accountId + "-Host-" + hostId,
             new UsageNetworkVO(
                 accountId,
                 zoneId,
                 hostId,
                 hostType,
                 networkId,
                 bytesSent,
                 bytesReceived,
                 aggBytesReceived,
                 aggBytesSent,
                 eventTimeMillis));
       } else {
         returnMap.put(
             zoneId + "-" + accountId,
             new UsageNetworkVO(
                 accountId,
                 zoneId,
                 hostId,
                 hostType,
                 networkId,
                 bytesSent,
                 bytesReceived,
                 aggBytesReceived,
                 aggBytesSent,
                 eventTimeMillis));
       }
     }
     return returnMap;
   } catch (Exception ex) {
     s_logger.error("error getting recent usage network stats", ex);
   } finally {
     txn.close();
   }
   return null;
 }
コード例 #2
0
 @Override
 public void run() {
   try {
     Transaction txn = Transaction.open("SG Work");
     try {
       work();
     } finally {
       txn.close("SG Work");
     }
   } catch (Throwable th) {
     try {
       s_logger.error("Problem with SG work", th);
     } catch (Throwable th2) {
     }
   }
 }
コード例 #3
0
  /**
   * This request registers the user Cloud.com account holder to the S3 service. The Cloud.com
   * account holder saves his API access and secret keys with the S3 service so that each rest call
   * he makes can be verified was originated from him. The given API access and secret key are saved
   * into the "usercredentials" database table.
   *
   * <p>This is an unauthenticated REST call. The only required parameters are 'accesskey' and
   * 'secretkey'.
   *
   * <p>To verify that the given keys represent an existing account they are used to execute the
   * Cloud.com's listAccounts API function. If the keys do not represent a valid account the
   * listAccounts function will fail.
   *
   * <p>A user can call this REST function any number of times, on each call the Cloud.com secret
   * key is simply over writes any previously stored value.
   *
   * <p>As with all REST calls HTTPS should be used to ensure their security.
   */
  @DB
  private void setUserKeys(HttpServletRequest request, HttpServletResponse response) {
    String[] accessKey = null;
    String[] secretKey = null;

    try {
      // -> both these parameters are required
      accessKey = request.getParameterValues("accesskey");
      if (null == accessKey || 0 == accessKey.length) {
        response.sendError(530, "Missing accesskey parameter");
        return;
      }

      secretKey = request.getParameterValues("secretkey");
      if (null == secretKey || 0 == secretKey.length) {
        response.sendError(530, "Missing secretkey parameter");
        return;
      }
    } catch (Exception e) {
      logger.error("SetUserKeys exception " + e.getMessage(), e);
      response.setStatus(500);
      endResponse(response, "SetUserKeys exception " + e.getMessage());
      return;
    }

    try {
      // -> use the keys to see if the account actually exists
      // ServiceProvider.getInstance().getEC2Engine().validateAccount( accessKey[0], secretKey[0] );
      // UserCredentialsDaoImpl credentialDao = new UserCredentialsDao();
      Transaction txn = Transaction.open(Transaction.AWSAPI_DB);
      txn.start();
      UserCredentialsVO user = new UserCredentialsVO(accessKey[0], secretKey[0]);
      user = ucDao.persist(user);
      txn.commit();
      txn.close();
      // credentialDao.setUserKeys( accessKey[0], secretKey[0] );

    } catch (Exception e) {
      logger.error("SetUserKeys " + e.getMessage(), e);
      response.setStatus(401);
      endResponse(response, e.toString());
      return;
    }
    response.setStatus(200);
    endResponse(response, "User keys set successfully");
  }
コード例 #4
0
  @Override
  public CloudStackServiceOfferingVO getSvcOfferingById(String id) {
    SearchBuilder<CloudStackServiceOfferingVO> searchByID = createSearchBuilder();
    searchByID.and("uuid", searchByID.entity().getUuid(), SearchCriteria.Op.EQ);
    searchByID.done();
    Transaction txn = Transaction.open(Transaction.CLOUD_DB);
    try {
      txn.start();
      SearchCriteria<CloudStackServiceOfferingVO> sc = searchByID.create();
      sc.setParameters("uuid", id);
      return findOneBy(sc);

    } finally {
      txn.commit();
      txn.close();
    }
  }
コード例 #5
0
 @Override
 public void run() {
   try {
     Transaction txn = Transaction.open("SG Cleanup");
     try {
       cleanupFinishedWork();
       cleanupUnfinishedWork();
       // processScheduledWork();
     } finally {
       txn.close("SG Cleanup");
     }
   } catch (Throwable th) {
     try {
       s_logger.error("Problem with SG Cleanup", th);
     } catch (Throwable th2) {
     }
   }
 }
コード例 #6
0
ファイル: UsageDaoImpl.java プロジェクト: vogxn/cloudstack
 @Override
 public void deleteRecordsForAccount(Long accountId) {
   String sql = ((accountId == null) ? DELETE_ALL : DELETE_ALL_BY_ACCOUNTID);
   Transaction txn = Transaction.open(Transaction.USAGE_DB);
   PreparedStatement pstmt = null;
   try {
     txn.start();
     pstmt = txn.prepareAutoCloseStatement(sql);
     if (accountId != null) {
       pstmt.setLong(1, accountId.longValue());
     }
     pstmt.executeUpdate();
     txn.commit();
   } catch (Exception ex) {
     txn.rollback();
     s_logger.error("error retrieving usage vm instances for account id: " + accountId);
   } finally {
     txn.close();
   }
 }
コード例 #7
0
 public void update(UsageVPNUserVO usage) {
   Transaction txn = Transaction.open(Transaction.USAGE_DB);
   PreparedStatement pstmt = null;
   try {
     txn.start();
     if (usage.getDeleted() != null) {
       pstmt = txn.prepareAutoCloseStatement(UPDATE_DELETED);
       pstmt.setString(
           1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), usage.getDeleted()));
       pstmt.setLong(2, usage.getAccountId());
       pstmt.setLong(3, usage.getUserId());
     }
     pstmt.executeUpdate();
     txn.commit();
   } catch (Exception e) {
     txn.rollback();
     s_logger.warn("Error updating UsageVPNUserVO", e);
   } finally {
     txn.close();
   }
 }
コード例 #8
0
    @Override
    public void run() {
      try {
        SearchCriteria<HostVO> sc = _hostDao.createSearchCriteria();
        sc.addAnd("status", SearchCriteria.Op.EQ, Status.Up.toString());
        sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.Storage.toString());

        ConcurrentHashMap<Long, StorageStats> storageStats =
            new ConcurrentHashMap<Long, StorageStats>();
        List<HostVO> hosts = _hostDao.search(sc, null);
        for (HostVO host : hosts) {
          GetStorageStatsCommand command = new GetStorageStatsCommand(host.getGuid());
          Answer answer = _agentMgr.easySend(host.getId(), command);
          if (answer != null && answer.getResult()) {
            storageStats.put(host.getId(), (StorageStats) answer);
          }
        }

        sc = _hostDao.createSearchCriteria();
        sc.addAnd("status", SearchCriteria.Op.EQ, Status.Up.toString());
        sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.SecondaryStorage.toString());

        hosts = _hostDao.search(sc, null);
        for (HostVO host : hosts) {
          GetStorageStatsCommand command = new GetStorageStatsCommand(host.getGuid());
          Answer answer = _agentMgr.easySend(host.getId(), command);
          if (answer != null && answer.getResult()) {
            storageStats.put(host.getId(), (StorageStats) answer);
          }
        }
        _storageStats = storageStats;

        ConcurrentHashMap<Long, StorageStats> storagePoolStats =
            new ConcurrentHashMap<Long, StorageStats>();

        List<StoragePoolVO> storagePools = _storagePoolDao.listAll();
        for (StoragePoolVO pool : storagePools) {
          GetStorageStatsCommand command =
              new GetStorageStatsCommand(pool.getUuid(), pool.getPoolType(), pool.getPath());
          Answer answer = _storageManager.sendToPool(pool, command);
          if (answer != null && answer.getResult()) {
            storagePoolStats.put(pool.getId(), (StorageStats) answer);
          }
        }
        _storagePoolStats = storagePoolStats;

        // a list to store the new capacity entries that will be committed once everything is
        // calculated
        List<CapacityVO> newCapacities = new ArrayList<CapacityVO>();

        // Updating the storage entries and creating new ones if they dont exist.
        Transaction txn = Transaction.open(Transaction.CLOUD_DB);
        try {
          if (s_logger.isTraceEnabled()) {
            s_logger.trace("recalculating system storage capacity");
          }
          txn.start();
          for (Long hostId : storageStats.keySet()) {
            StorageStats stats = storageStats.get(hostId);
            short capacityType = -1;
            HostVO host = _hostDao.findById(hostId);
            host.setTotalSize(stats.getCapacityBytes());
            _hostDao.update(host.getId(), host);

            SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria();
            capacitySC.addAnd("hostOrPoolId", SearchCriteria.Op.EQ, hostId);
            capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, host.getDataCenterId());

            if (Host.Type.SecondaryStorage.equals(host.getType())) {
              capacityType = CapacityVO.CAPACITY_TYPE_SECONDARY_STORAGE;
            } else if (Host.Type.Storage.equals(host.getType())) {
              capacityType = CapacityVO.CAPACITY_TYPE_STORAGE;
            }
            if (-1 != capacityType) {
              capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, capacityType);
              List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
              if (capacities.size() == 0) { // Create a new one
                CapacityVO capacity =
                    new CapacityVO(
                        host.getId(),
                        host.getDataCenterId(),
                        host.getPodId(),
                        stats.getByteUsed(),
                        stats.getCapacityBytes(),
                        capacityType);
                _capacityDao.persist(capacity);
              } else { // Update if it already exists.
                CapacityVO capacity = capacities.get(0);
                capacity.setUsedCapacity(stats.getByteUsed());
                capacity.setTotalCapacity(stats.getCapacityBytes());
                _capacityDao.update(capacity.getId(), capacity);
              }
            }
          } // End of for
          txn.commit();
        } catch (Exception ex) {
          txn.rollback();
          s_logger.error("Unable to start transaction for storage capacity update");
        } finally {
          txn.close();
        }

        for (Long poolId : storagePoolStats.keySet()) {
          StorageStats stats = storagePoolStats.get(poolId);
          StoragePoolVO pool = _storagePoolDao.findById(poolId);

          if (pool == null) {
            continue;
          }

          pool.setCapacityBytes(stats.getCapacityBytes());
          long available = stats.getCapacityBytes() - stats.getByteUsed();
          if (available < 0) {
            available = 0;
          }
          pool.setAvailableBytes(available);
          _storagePoolDao.update(pool.getId(), pool);

          _storageManager.createCapacityEntry(pool, 0L);
        }
      } catch (Throwable t) {
        s_logger.error("Error trying to retrieve storage stats", t);
      }
    }
コード例 #9
0
  /**
   * POST requests do not get authenticated on entry. The associated access key and signature
   * headers are embedded in the message not encoded as HTTP headers.
   */
  private void processRequest(
      HttpServletRequest request, HttpServletResponse response, String method) {
    Transaction txn = Transaction.open("cloudbridge", Transaction.AWSAPI_DB, true);
    try {
      logRequest(request);

      // Our extensions to the S3 REST API for simple management actions
      // are conveyed with Request parameter "Action".
      // The present extensions are either to set up the user credentials
      // (see the cloud-bridge-register script for more detail) or
      // to report our version of this capability.
      // -> unauthenticated calls, should still be done over HTTPS
      String cloudAction = request.getParameter("Action");

      if (!isS3APIEnabled) {
        throw new RuntimeException("Amazon S3 API is disabled.");
      }

      if (null != cloudAction) {
        if (cloudAction.equalsIgnoreCase("SetUserKeys")) {
          setUserKeys(request, response);
          return;
        }

        if (cloudAction.equalsIgnoreCase("SetCertificate"))
          // At present a noop
          return;

        if (cloudAction.equalsIgnoreCase("CloudS3Version")) {
          cloudS3Version(request, response);
          return;
        }
      }

      txn.start();
      // -> authenticated calls
      if (!((method.equalsIgnoreCase("POST")
          && !(request.getQueryString().equalsIgnoreCase("delete"))))) {
        S3AuthParams params = extractRequestHeaders(request);
        authenticateRequest(request, params);
      }

      ServletAction action = routeRequest(request);
      if (action != null) {
        action.execute(request, response);
      } else {
        response.setStatus(404);
        endResponse(response, "File not found");
      }
      txn.close();
    } catch (InvalidBucketName e) {
      logger.error("Unexpected exception " + e.getMessage(), e);
      response.setStatus(400);
      endResponse(response, "Invalid Bucket Name - " + e.toString());
    } catch (PermissionDeniedException e) {
      logger.error("Unexpected exception " + e.getMessage(), e);
      response.setStatus(403);
      endResponse(response, "Access denied - " + e.toString());
    } catch (Throwable e) {
      logger.error("Unexpected exception " + e.getMessage(), e);
      response.setStatus(404);
      endResponse(response, "Bad request");

    } finally {

      try {
        response.flushBuffer();
      } catch (IOException e) {
        logger.error("Unexpected exception " + e.getMessage(), e);
      }
    }
  }
コード例 #10
0
  @Override
  public List<UsageVPNUserVO> getUsageRecords(
      Long accountId, Long domainId, Date startDate, Date endDate, boolean limit, int page) {
    List<UsageVPNUserVO> usageRecords = new ArrayList<UsageVPNUserVO>();

    Long param1 = null;
    String sql = null;
    if (accountId != null) {
      sql = GET_USAGE_RECORDS_BY_ACCOUNT;
      param1 = accountId;
    } else if (domainId != null) {
      sql = GET_USAGE_RECORDS_BY_DOMAIN;
      param1 = domainId;
    } else {
      sql = GET_ALL_USAGE_RECORDS;
    }

    if (limit) {
      int startIndex = 0;
      if (page > 0) {
        startIndex = 500 * (page - 1);
      }
      sql += " LIMIT " + startIndex + ",500";
    }

    Transaction txn = Transaction.open(Transaction.USAGE_DB);
    PreparedStatement pstmt = null;

    try {
      int i = 1;
      pstmt = txn.prepareAutoCloseStatement(sql);
      if (param1 != null) {
        pstmt.setLong(i++, param1);
      }
      pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
      pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
      pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
      pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
      pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
      pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));

      ResultSet rs = pstmt.executeQuery();
      while (rs.next()) {
        // zoneId, account_id, domain_id, user_id, user_name, created, deleted
        Long zoneId = Long.valueOf(rs.getLong(1));
        Long acctId = Long.valueOf(rs.getLong(2));
        Long dId = Long.valueOf(rs.getLong(3));
        long userId = Long.valueOf(rs.getLong(4));
        String userName = rs.getString(5);
        Date createdDate = null;
        Date deletedDate = null;
        String createdTS = rs.getString(6);
        String deletedTS = rs.getString(7);

        if (createdTS != null) {
          createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS);
        }
        if (deletedTS != null) {
          deletedDate = DateUtil.parseDateString(s_gmtTimeZone, deletedTS);
        }

        usageRecords.add(
            new UsageVPNUserVO(zoneId, acctId, dId, userId, userName, createdDate, deletedDate));
      }
    } catch (Exception e) {
      txn.rollback();
      s_logger.warn("Error getting usage records", e);
    } finally {
      txn.close();
    }

    return usageRecords;
  }
コード例 #11
0
  public boolean verifyRequest(Map<String, Object[]> requestParameters, Long userId)
      throws ServerApiException {
    try {
      String apiKey = null;
      String secretKey = null;
      String signature = null;
      String unsignedRequest = null;

      String[] command = (String[]) requestParameters.get("command");
      if (command == null) {
        s_logger.info("missing command, ignoring request...");
        return false;
      }

      String commandName = command[0];

      // if userId not null, that mean that user is logged in
      if (userId != null) {
        User user = ApiDBUtils.findUserById(userId);
        try {
          checkCommandAvailable(user, commandName);
        } catch (PermissionDeniedException ex) {
          s_logger.debug(
              "The given command:"
                  + commandName
                  + " does not exist or it is not available for user with id:"
                  + userId);
          throw new ServerApiException(
              ApiErrorCode.UNSUPPORTED_ACTION_ERROR,
              "The given command does not exist or it is not available for user");
        }
        return true;
      } else {
        // check against every available command to see if the command exists or not
        if (!_apiNameCmdClassMap.containsKey(commandName)
            && !commandName.equals("login")
            && !commandName.equals("logout")) {
          s_logger.debug(
              "The given command:"
                  + commandName
                  + " does not exist or it is not available for user with id:"
                  + userId);
          throw new ServerApiException(
              ApiErrorCode.UNSUPPORTED_ACTION_ERROR,
              "The given command does not exist or it is not available for user");
        }
      }

      // - build a request string with sorted params, make sure it's all lowercase
      // - sign the request, verify the signature is the same
      List<String> parameterNames = new ArrayList<String>();

      for (Object paramNameObj : requestParameters.keySet()) {
        parameterNames.add((String) paramNameObj); // put the name in a list that we'll sort later
      }

      Collections.sort(parameterNames);

      String signatureVersion = null;
      String expires = null;

      for (String paramName : parameterNames) {
        // parameters come as name/value pairs in the form String/String[]
        String paramValue = ((String[]) requestParameters.get(paramName))[0];

        if ("signature".equalsIgnoreCase(paramName)) {
          signature = paramValue;
        } else {
          if ("apikey".equalsIgnoreCase(paramName)) {
            apiKey = paramValue;
          } else if ("signatureversion".equalsIgnoreCase(paramName)) {
            signatureVersion = paramValue;
          } else if ("expires".equalsIgnoreCase(paramName)) {
            expires = paramValue;
          }

          if (unsignedRequest == null) {
            unsignedRequest =
                paramName + "=" + URLEncoder.encode(paramValue, "UTF-8").replaceAll("\\+", "%20");
          } else {
            unsignedRequest =
                unsignedRequest
                    + "&"
                    + paramName
                    + "="
                    + URLEncoder.encode(paramValue, "UTF-8").replaceAll("\\+", "%20");
          }
        }
      }

      // if api/secret key are passed to the parameters
      if ((signature == null) || (apiKey == null)) {
        s_logger.debug(
            "Expired session, missing signature, or missing apiKey -- ignoring request. Signature: "
                + signature
                + ", apiKey: "
                + apiKey);
        return false; // no signature, bad request
      }

      Date expiresTS = null;
      // FIXME: Hard coded signature, why not have an enum
      if ("3".equals(signatureVersion)) {
        // New signature authentication. Check for expire parameter and its validity
        if (expires == null) {
          s_logger.debug(
              "Missing Expires parameter -- ignoring request. Signature: "
                  + signature
                  + ", apiKey: "
                  + apiKey);
          return false;
        }
        synchronized (_dateFormat) {
          try {
            expiresTS = _dateFormat.parse(expires);
          } catch (ParseException pe) {
            s_logger.debug("Incorrect date format for Expires parameter", pe);
            return false;
          }
        }
        Date now = new Date(System.currentTimeMillis());
        if (expiresTS.before(now)) {
          s_logger.debug(
              "Request expired -- ignoring ...sig: " + signature + ", apiKey: " + apiKey);
          return false;
        }
      }

      Transaction txn = Transaction.open(Transaction.CLOUD_DB);
      txn.close();
      User user = null;
      // verify there is a user with this api key
      Pair<User, Account> userAcctPair = _accountMgr.findUserByApiKey(apiKey);
      if (userAcctPair == null) {
        s_logger.debug(
            "apiKey does not map to a valid user -- ignoring request, apiKey: " + apiKey);
        return false;
      }

      user = userAcctPair.first();
      Account account = userAcctPair.second();

      if (user.getState() != Account.State.enabled
          || !account.getState().equals(Account.State.enabled)) {
        s_logger.info(
            "disabled or locked user accessing the api, userid = "
                + user.getId()
                + "; name = "
                + user.getUsername()
                + "; state: "
                + user.getState()
                + "; accountState: "
                + account.getState());
        return false;
      }

      UserContext.updateContext(user.getId(), account, null);

      try {
        checkCommandAvailable(user, commandName);
      } catch (PermissionDeniedException ex) {
        s_logger.debug(
            "The given command:" + commandName + " does not exist or it is not available for user");
        throw new ServerApiException(
            ApiErrorCode.UNSUPPORTED_ACTION_ERROR,
            "The given command:"
                + commandName
                + " does not exist or it is not available for user with id:"
                + userId);
      }

      // verify secret key exists
      secretKey = user.getSecretKey();
      if (secretKey == null) {
        s_logger.info(
            "User does not have a secret key associated with the account -- ignoring request, username: "******"HmacSHA1");
      SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
      mac.init(keySpec);
      mac.update(unsignedRequest.getBytes());
      byte[] encryptedBytes = mac.doFinal();
      String computedSignature = Base64.encodeBase64String(encryptedBytes);
      boolean equalSig = signature.equals(computedSignature);
      if (!equalSig) {
        s_logger.info(
            "User signature: "
                + signature
                + " is not equaled to computed signature: "
                + computedSignature);
      }
      return equalSig;
    } catch (ServerApiException ex) {
      throw ex;
    } catch (Exception ex) {
      s_logger.error("unable to verify request signature");
    }
    return false;
  }
コード例 #12
0
    private boolean collectDirectNetworkUsage(HostVO host) {
      s_logger.debug("Direct Network Usage stats collector is running...");

      long zoneId = host.getDataCenterId();
      DetailVO lastCollectDetail = _detailsDao.findDetail(host.getId(), "last_collection");
      if (lastCollectDetail == null) {
        s_logger.warn(
            "Last collection time not available. Skipping direct usage collection for Traffic Monitor: "
                + host.getId());
        return false;
      }
      Date lastCollection = new Date(new Long(lastCollectDetail.getValue()));

      // Get list of IPs currently allocated
      List<IPAddressVO> allocatedIps = listAllocatedDirectIps(zoneId);
      Calendar rightNow = Calendar.getInstance();

      // Allow 2 hours for traffic sentinel to populate historical traffic
      // This coule be made configurable

      rightNow.add(Calendar.HOUR_OF_DAY, -2);
      Date now = rightNow.getTime();

      if (lastCollection.after(now)) {
        s_logger.debug(
            "Current time is less than 2 hours after last collection time : "
                + lastCollection.toString()
                + ". Skipping direct network usage collection");
        return false;
      }

      // Get IP Assign/Release events from lastCollection time till now
      List<UsageEventVO> IpEvents = _eventDao.listDirectIpEvents(lastCollection, now, zoneId);

      Map<String, Date> ipAssigment = new HashMap<String, Date>();
      List<UsageIPAddressVO> IpPartialUsage =
          new ArrayList<
              UsageIPAddressVO>(); // Ips which were allocated only for the part of collection
                                   // duration
      List<UsageIPAddressVO> fullDurationIpUsage =
          new ArrayList<
              UsageIPAddressVO>(); // Ips which were allocated only for the entire collection
                                   // duration

      // Use UsageEvents to track the IP assignment
      // Add them to IpUsage list with account_id , ip_address, alloc_date, release_date

      for (UsageEventVO IpEvent : IpEvents) {
        String address = IpEvent.getResourceName();
        if (EventTypes.EVENT_NET_IP_ASSIGN.equals(IpEvent.getType())) {
          ipAssigment.put(address, IpEvent.getCreateDate());
        } else if (EventTypes.EVENT_NET_IP_RELEASE.equals(IpEvent.getType())) {
          if (ipAssigment.containsKey(address)) {
            Date assigned = ipAssigment.get(address);
            ipAssigment.remove(address);
            IpPartialUsage.add(
                new UsageIPAddressVO(
                    IpEvent.getAccountId(), address, assigned, IpEvent.getCreateDate()));
          } else {
            // Ip was assigned prior to lastCollection Date
            IpPartialUsage.add(
                new UsageIPAddressVO(
                    IpEvent.getAccountId(), address, lastCollection, IpEvent.getCreateDate()));
          }
        }
      }

      List<String> IpList = new ArrayList<String>();
      for (IPAddressVO ip : allocatedIps) {
        if (ip.getAllocatedToAccountId() == AccountVO.ACCOUNT_ID_SYSTEM) {
          // Ignore usage for system account
          continue;
        }
        String address = (ip.getAddress()).toString();
        if (ipAssigment.containsKey(address)) {
          // Ip was assigned during the current period but not release till Date now
          IpPartialUsage.add(
              new UsageIPAddressVO(
                  ip.getAllocatedToAccountId(), address, ipAssigment.get(address), now));
        } else {
          // Ip was not assigned or released during current period. Consider entire duration for
          // usage calculation (lastCollection to now)
          fullDurationIpUsage.add(
              new UsageIPAddressVO(ip.getAllocatedToAccountId(), address, lastCollection, now));
          // Store just the Ips to send the list as part of DirectNetworkUsageCommand
          IpList.add(address);
        }
      }

      List<UserStatisticsVO> collectedStats = new ArrayList<UserStatisticsVO>();

      // Get usage for Ips which were assigned for the entire duration
      if (fullDurationIpUsage.size() > 0) {
        DirectNetworkUsageCommand cmd =
            new DirectNetworkUsageCommand(IpList, lastCollection, now, _TSinclZones, _TSexclZones);
        DirectNetworkUsageAnswer answer =
            (DirectNetworkUsageAnswer) _agentMgr.easySend(host.getId(), cmd);
        if (answer == null || !answer.getResult()) {
          String details = (answer != null) ? answer.getDetails() : "details unavailable";
          String msg =
              "Unable to get network usage stats from "
                  + host.getId()
                  + " due to: "
                  + details
                  + ".";
          s_logger.error(msg);
          return false;
        } else {
          for (UsageIPAddressVO usageIp : fullDurationIpUsage) {
            String publicIp = usageIp.getAddress();
            long[] bytesSentRcvd = answer.get(publicIp);
            Long bytesSent = bytesSentRcvd[0];
            Long bytesRcvd = bytesSentRcvd[1];
            if (bytesSent == null || bytesRcvd == null) {
              s_logger.debug("Incorrect bytes for IP: " + publicIp);
              continue;
            }
            if (bytesSent == 0L && bytesRcvd == 0L) {
              s_logger.trace("Ignore zero bytes for IP: " + publicIp);
              continue;
            }
            UserStatisticsVO stats =
                new UserStatisticsVO(usageIp.getAccountId(), zoneId, null, null, null, null);
            stats.setCurrentBytesSent(bytesSent);
            stats.setCurrentBytesReceived(bytesRcvd);
            collectedStats.add(stats);
          }
        }
      }

      // Get usage for Ips which were assigned for part of the duration period
      for (UsageIPAddressVO usageIp : IpPartialUsage) {
        IpList = new ArrayList<String>();
        IpList.add(usageIp.getAddress());
        DirectNetworkUsageCommand cmd =
            new DirectNetworkUsageCommand(
                IpList, usageIp.getAssigned(), usageIp.getReleased(), _TSinclZones, _TSexclZones);
        DirectNetworkUsageAnswer answer =
            (DirectNetworkUsageAnswer) _agentMgr.easySend(host.getId(), cmd);
        if (answer == null || !answer.getResult()) {
          String details = (answer != null) ? answer.getDetails() : "details unavailable";
          String msg =
              "Unable to get network usage stats from "
                  + host.getId()
                  + " due to: "
                  + details
                  + ".";
          s_logger.error(msg);
          return false;
        } else {
          String publicIp = usageIp.getAddress();
          long[] bytesSentRcvd = answer.get(publicIp);
          Long bytesSent = bytesSentRcvd[0];
          Long bytesRcvd = bytesSentRcvd[1];
          if (bytesSent == null || bytesRcvd == null) {
            s_logger.debug("Incorrect bytes for IP: " + publicIp);
            continue;
          }
          if (bytesSent == 0L && bytesRcvd == 0L) {
            s_logger.trace("Ignore zero bytes for IP: " + publicIp);
            continue;
          }
          UserStatisticsVO stats =
              new UserStatisticsVO(usageIp.getAccountId(), zoneId, null, null, null, null);
          stats.setCurrentBytesSent(bytesSent);
          stats.setCurrentBytesReceived(bytesRcvd);
          collectedStats.add(stats);
        }
      }

      if (collectedStats.size() == 0) {
        s_logger.debug("No new direct network stats. No need to persist");
        return false;
      }
      // Persist all the stats and last_collection time in a single transaction
      Transaction txn = Transaction.open(Transaction.CLOUD_DB);
      try {
        txn.start();
        for (UserStatisticsVO stat : collectedStats) {
          UserStatisticsVO stats =
              _statsDao.lock(
                  stat.getAccountId(),
                  stat.getDataCenterId(),
                  0L,
                  null,
                  host.getId(),
                  "DirectNetwork");
          if (stats == null) {
            stats =
                new UserStatisticsVO(
                    stat.getAccountId(), zoneId, null, host.getId(), "DirectNetwork", 0L);
            stats.setCurrentBytesSent(stat.getCurrentBytesSent());
            stats.setCurrentBytesReceived(stat.getCurrentBytesReceived());
            _statsDao.persist(stats);
          } else {
            stats.setCurrentBytesSent(stats.getCurrentBytesSent() + stat.getCurrentBytesSent());
            stats.setCurrentBytesReceived(
                stats.getCurrentBytesReceived() + stat.getCurrentBytesReceived());
            _statsDao.update(stats.getId(), stats);
          }
        }
        lastCollectDetail.setValue("" + now.getTime());
        _detailsDao.update(lastCollectDetail.getId(), lastCollectDetail);
        txn.commit();
      } finally {
        txn.close();
      }

      return true;
    }