This is an automated email from the ASF dual-hosted git repository. dahn pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 0af923e618180d3fb8f01ecc56b5a8d854ad1d23 Merge: a6f3560152b 0514caedd6a Author: Daan Hoogland <d...@onecht.net> AuthorDate: Wed Apr 24 14:01:02 2024 +0200 Merge branch '4.19' api/src/main/java/com/cloud/event/EventTypes.java | 4 + .../org/apache/cloudstack/usage/UsageTypes.java | 2 + client/pom.xml | 14 +- .../engine/orchestration/NetworkOrchestrator.java | 6 + .../main/java/com/cloud/usage/UsageNetworksVO.java | 143 +++++++++++++++++++++ .../src/main/java/com/cloud/usage/UsageVO.java | 11 ++ .../java/com/cloud/usage/dao/UsageNetworksDao.java | 31 +++++ .../com/cloud/usage/dao/UsageNetworksDaoImpl.java | 136 ++++++++++++++++++++ ...n-daos-between-management-and-usage-context.xml | 1 + .../spring-engine-schema-core-daos-context.xml | 1 + .../resources/META-INF/db/schema-41900to41910.sql | 14 ++ .../presetvariables/PresetVariableHelper.java | 22 ++++ .../activationrule/presetvariables/Value.java | 10 ++ .../cloudstack/quota/constant/QuotaTypes.java | 1 + .../apache/cloudstack/quota/dao/NetworkDao.java | 23 ++++ .../cloudstack/quota/dao/NetworkDaoImpl.java | 27 ++++ .../presetvariables/PresetVariableHelperTest.java | 1 + .../activationrule/presetvariables/ValueTest.java | 8 ++ plugins/network-elements/juniper-contrail/pom.xml | 6 - plugins/pom.xml | 2 +- .../java/com/cloud/network/NetworkServiceImpl.java | 12 +- .../com/cloud/network/NetworkModelImplTest.java | 2 +- test/integration/smoke/test_vm_life_cycle.py | 6 +- .../java/com/cloud/usage/UsageManagerImpl.java | 27 ++++ .../cloud/usage/parser/NetworksUsageParser.java | 100 ++++++++++++++ 25 files changed, 588 insertions(+), 22 deletions(-) diff --cc client/pom.xml index a73aed7d032,794160eb545..1d11fa74650 --- a/client/pom.xml +++ b/client/pom.xml @@@ -25,13 -25,9 +25,9 @@@ <parent> <groupId>org.apache.cloudstack</groupId> <artifactId>cloudstack</artifactId> - <version>4.19.1.0-SNAPSHOT</version> + <version>4.20.0.0-SNAPSHOT</version> </parent> <repositories> - <repository> - <id>juniper-contrail</id> - <url>https://juniper.github.io/contrail-maven/snapshots</url> - </repository> <repository> <id>juniper-tungsten-api</id> <url>https://github.com/radu-todirica/tungsten-api/raw/master</url> diff --cc engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index ba9e5646bb5,c49a0fd09b1..d07fee32276 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@@ -1464,8 -1407,10 +1464,10 @@@ public class NetworkOrchestrator extend NetworkVO network = _networksDao.findById(networkId); final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName()); if (isNetworkImplemented(network)) { - s_logger.debug("Network id=" + networkId + " is already implemented"); + logger.debug("Network id={} is already implemented", networkId); implemented.set(guru, network); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_UPDATE, network.getAccountId(), network.getDataCenterId(), network.getId(), + network.getName(), network.getNetworkOfferingId(), null, network.getState().name(), Network.class.getName(), network.getUuid(), true); return implemented; } @@@ -1522,12 -1471,14 +1524,14 @@@ network.setRestartRequired(false); _networksDao.update(network.getId(), network); implemented.set(guru, network); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_CREATE, network.getAccountId(), network.getDataCenterId(), network.getId(), + network.getName(), network.getNetworkOfferingId(), null, null, null, network.getState().name(), network.getUuid()); return implemented; } catch (final NoTransitionException e) { - s_logger.error(e.getMessage()); + logger.error(e.getMessage()); return new Pair<NetworkGuru, NetworkVO>(null, null); } catch (final CloudRuntimeException | OperationTimedoutException e) { - s_logger.error("Caught exception: " + e.getMessage()); + logger.error("Caught exception: {}", e.getMessage()); return new Pair<NetworkGuru, NetworkVO>(null, null); } finally { if (implemented.first() == null) { @@@ -3370,9 -3348,11 +3374,11 @@@ final Pair<Class<?>, Long> networkMsg = new Pair<Class<?>, Long>(Network.class, networkFinal.getId()); _messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, networkMsg); } + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_DELETE, network.getAccountId(), network.getDataCenterId(), network.getId(), + network.getName(), network.getNetworkOfferingId(), null, null, null, Network.class.getName(), network.getUuid()); return true; } catch (final CloudRuntimeException e) { - s_logger.error("Failed to delete network", e); + logger.error("Failed to delete network", e); return false; } } diff --cc engine/schema/src/main/java/com/cloud/usage/UsageVO.java index 50884e3c012,054ec52e281..b1f6d295fdd --- a/engine/schema/src/main/java/com/cloud/usage/UsageVO.java +++ b/engine/schema/src/main/java/com/cloud/usage/UsageVO.java @@@ -401,14 -401,16 +404,22 @@@ public class UsageVO implements Usage, this.isHidden = hidden; } + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + @Override public String toString() { - return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "usageId", "usageType", "startDate", "endDate"); + return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "usageId", "usageType"); + } + + public String toString(TimeZone timeZone) { + String startDateString = DateUtil.displayDateInTimezone(timeZone, getStartDate()); + String endDateString = DateUtil.displayDateInTimezone(timeZone, getEndDate()); + return String.format("%s,\"startDate\":\"%s\",\"endDate\":\"%s\"}", StringUtils.chop(this.toString()), startDateString, endDateString); } } diff --cc engine/schema/src/main/java/com/cloud/usage/dao/UsageNetworksDaoImpl.java index 00000000000,8829414f3f2..f8ffbf74f85 mode 000000,100644..100644 --- a/engine/schema/src/main/java/com/cloud/usage/dao/UsageNetworksDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/usage/dao/UsageNetworksDaoImpl.java @@@ -1,0 -1,134 +1,136 @@@ + // Licensed to the Apache Software Foundation (ASF) under one + // or more contributor license agreements. See the NOTICE file + // distributed with this work for additional information + // regarding copyright ownership. The ASF licenses this file + // to you under the Apache License, Version 2.0 (the + // "License"); you may not use this file except in compliance + // with the License. You may obtain a copy of the License at + // + // http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, + // software distributed under the License is distributed on an + // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + // KIND, either express or implied. See the License for the + // specific language governing permissions and limitations + // under the License. + package com.cloud.usage.dao; + + import com.cloud.network.Network; + import com.cloud.usage.UsageNetworksVO; + import com.cloud.utils.DateUtil; + import com.cloud.utils.db.GenericDaoBase; + import com.cloud.utils.db.SearchCriteria; + import com.cloud.utils.db.TransactionLegacy; -import org.apache.log4j.Logger; ++ + import org.springframework.stereotype.Component; ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.Logger; + + import java.sql.PreparedStatement; + import java.sql.ResultSet; + import java.util.ArrayList; + import java.util.Date; + import java.util.List; + import java.util.TimeZone; + + @Component + public class UsageNetworksDaoImpl extends GenericDaoBase<UsageNetworksVO, Long> implements UsageNetworksDao { - private static final Logger LOGGER = Logger.getLogger(UsageNetworksDaoImpl.class); ++ private static final Logger LOGGER = LogManager.getLogger(UsageNetworksDaoImpl.class); + protected static final String GET_USAGE_RECORDS_BY_ACCOUNT = "SELECT id, network_id, network_offering_id, zone_id, account_id, domain_id, state, created, removed FROM usage_networks WHERE " + + " account_id = ? AND ((removed IS NULL AND created <= ?) OR (created BETWEEN ? AND ?) OR (removed BETWEEN ? AND ?) " + + " OR ((created <= ?) AND (removed >= ?)))"; + + + @Override + public void update(long networkId, long newNetworkOffering, String state) { + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + try { + SearchCriteria<UsageNetworksVO> sc = this.createSearchCriteria(); + sc.addAnd("networkId", SearchCriteria.Op.EQ, networkId); + sc.addAnd("removed", SearchCriteria.Op.NULL); + UsageNetworksVO vo = findOneBy(sc); + if (vo != null) { + vo.setNetworkOfferingId(newNetworkOffering); + vo.setState(state); + update(vo.getId(), vo); + } + } catch (final Exception e) { + txn.rollback(); + LOGGER.error(String.format("Error updating usage of network due to [%s].", e.getMessage()), e); + } finally { + txn.close(); + } + } + + @Override + public void remove(long networkId, Date removed) { + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + try { + SearchCriteria<UsageNetworksVO> sc = this.createSearchCriteria(); + sc.addAnd("networkId", SearchCriteria.Op.EQ, networkId); + sc.addAnd("removed", SearchCriteria.Op.NULL); + UsageNetworksVO vo = findOneBy(sc); + if (vo != null) { + vo.setRemoved(removed); + vo.setState(Network.State.Destroy.name()); + update(vo.getId(), vo); + } + } catch (final Exception e) { + txn.rollback(); + LOGGER.error(String.format("Error updating usage of network due to [%s].", e.getMessage()), e); + } finally { + txn.close(); + } + } + + @Override + public List<UsageNetworksVO> getUsageRecords(Long accountId, Date startDate, Date endDate) { + List<UsageNetworksVO> usageRecords = new ArrayList<>(); + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + PreparedStatement pstmt; + try { + int i = 1; + pstmt = txn.prepareAutoCloseStatement(GET_USAGE_RECORDS_BY_ACCOUNT); + pstmt.setLong(i++, accountId); + + 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)); + 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()) { + long id = rs.getLong(1); + long networkId = rs.getLong(2); + long networkOfferingId = rs.getLong(3); + long zoneId = rs.getLong(4); + long acctId = rs.getLong(5); + long domId = rs.getLong(6); + String stateTS = rs.getString(7); + Date createdDate = null; + Date removedDate = null; + String createdTS = rs.getString(8); + String removedTS = rs.getString(9); + + if (createdTS != null) { + createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS); + } + if (removedTS != null) { + removedDate = DateUtil.parseDateString(s_gmtTimeZone, removedTS); + } + usageRecords.add(new UsageNetworksVO(id, networkId, networkOfferingId, zoneId, acctId, domId, stateTS, createdDate, removedDate)); + } + } catch (Exception e) { + txn.rollback(); + LOGGER.warn("Error getting networks usage records", e); + } finally { + txn.close(); + } + + return usageRecords; + } + } diff --cc engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml index fc455f872fa,2b6361c8126..d6d72f9228e --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml @@@ -67,8 -67,8 +67,9 @@@ <bean id="vMInstanceDaoImpl" class="com.cloud.vm.dao.VMInstanceDaoImpl" /> <bean id="vMSnapshotDaoImpl" class="com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl" /> <bean id="VmTemplateDaoImpl" class="org.apache.cloudstack.quota.dao.VmTemplateDaoImpl" /> + <bean id="NetworkDaoImpl" class="org.apache.cloudstack.quota.dao.NetworkDaoImpl" /> <bean id="VpcDaoImpl" class="org.apache.cloudstack.quota.dao.VpcDaoImpl" /> <bean id="volumeDaoImpl" class="com.cloud.storage.dao.VolumeDaoImpl" /> + <bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" /> <bean id="backupOfferingDaoImpl" class="org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl" /> </beans> diff --cc plugins/network-elements/juniper-contrail/pom.xml index a6a0df9f9d5,286832d891e..3f71146d580 --- a/plugins/network-elements/juniper-contrail/pom.xml +++ b/plugins/network-elements/juniper-contrail/pom.xml @@@ -24,15 -24,9 +24,9 @@@ <parent> <groupId>org.apache.cloudstack</groupId> <artifactId>cloudstack-plugins</artifactId> - <version>4.19.1.0-SNAPSHOT</version> + <version>4.20.0.0-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> - <repositories> - <repository> - <id>juniper-contrail</id> - <url>https://juniper.github.io/contrail-maven/snapshots</url> - </repository> - </repositories> <dependencies> <dependency> <groupId>org.apache.cloudstack</groupId> diff --cc plugins/pom.xml index bfe3060addf,6ba99f86e69..e29f385dc37 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@@ -230,7 -229,7 +229,8 @@@ <module>backup/veeam</module> <module>hypervisors/vmware</module> <module>network-elements/cisco-vnmc</module> + <module>network-elements/nsx</module> + <module>network-elements/juniper-contrail</module> </modules> </profile> <profile> diff --cc server/src/main/java/com/cloud/network/NetworkServiceImpl.java index 6168de1ef63,068a06427db..1314d7dd574 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@@ -2054,16 -1970,21 +2054,21 @@@ public class NetworkServiceImpl extend try { DeployDestination dest = new DeployDestination(zone, null, null, null); UserVO callerUser = _userDao.findById(CallContext.current().getCallingUserId()); - Journal journal = new Journal.LogJournal("Implementing " + network, s_logger); + Journal journal = new Journal.LogJournal("Implementing " + network, logger); ReservationContext context = new ReservationContextImpl(UUID.randomUUID().toString(), journal, callerUser, caller); - s_logger.debug("Implementing network " + network + " as a part of network provision for persistent network"); + logger.debug("Implementing network " + network + " as a part of network provision for persistent network"); Pair<? extends NetworkGuru, ? extends Network> implementedNetwork = _networkMgr.implementNetwork(network.getId(), dest, context); if (implementedNetwork == null || implementedNetwork.first() == null) { - s_logger.warn("Failed to provision the network " + network); + logger.warn("Failed to provision the network " + network); } - return implementedNetwork.second(); + Network implemented = implementedNetwork.second(); + if (implemented != null) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_CREATE, implemented.getAccountId(), implemented.getDataCenterId(), implemented.getId(), + implemented.getName(), implemented.getNetworkOfferingId(), null, null, null, Network.class.getName(), implemented.getUuid()); + } + return implemented; } catch (ResourceUnavailableException ex) { - s_logger.warn("Failed to implement persistent guest network " + network + "due to ", ex); + logger.warn("Failed to implement persistent guest network " + network + "due to ", ex); CloudRuntimeException e = new CloudRuntimeException("Failed to implement persistent guest network"); e.addProxyObject(network.getUuid(), "networkId"); throw e; diff --cc server/src/test/java/com/cloud/network/NetworkModelImplTest.java index 6eb3e5d186b,d9baa260c68..889031f2b50 --- a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java +++ b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java @@@ -41,15 -28,7 +41,15 @@@ import org.junit.runner.RunWith import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; + import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; - import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class NetworkModelImplTest { diff --cc usage/src/main/java/com/cloud/usage/UsageManagerImpl.java index 2b436bb440c,a5231209574..8cd0a4560ab --- a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java @@@ -1038,14 -1040,19 +1043,19 @@@ public class UsageManagerImpl extends M } } parsed = BucketUsageParser.parse(account, currentStartDate, currentEndDate); - if (s_logger.isDebugEnabled()) { + if (logger.isDebugEnabled()) { if (!parsed) { - s_logger.debug("Bucket usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")"); + logger.debug("Bucket usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")"); } } + parsed = NetworksUsageParser.parse(account, currentStartDate, currentEndDate); + if (!parsed) { - s_logger.debug(String.format("Networks usage not parsed for account [%s].", account)); ++ logger.debug("Networks usage not parsed for account [{}}].", account); + } + parsed = VpcUsageParser.parse(account, currentStartDate, currentEndDate); if (!parsed) { - s_logger.debug(String.format("VPC usage failed to parse for account [%s].", account)); + logger.debug(String.format("VPC usage failed to parse for account [%s].", account)); } return parsed; } @@@ -2131,6 -2137,21 +2143,21 @@@ } } + private void handleNetworkEvent(UsageEventVO event) { + Account account = _accountDao.findByIdIncludingRemoved(event.getAccountId()); + long domainId = account.getDomainId(); + if (EventTypes.EVENT_NETWORK_DELETE.equals(event.getType())) { + usageNetworksDao.remove(event.getResourceId(), event.getCreateDate()); + } else if (EventTypes.EVENT_NETWORK_CREATE.equals(event.getType())) { + UsageNetworksVO usageNetworksVO = new UsageNetworksVO(event.getResourceId(), event.getOfferingId(), event.getZoneId(), event.getAccountId(), domainId, Network.State.Allocated.name(), event.getCreateDate(), null); + usageNetworksDao.persist(usageNetworksVO); + } else if (EventTypes.EVENT_NETWORK_UPDATE.equals(event.getType())) { + usageNetworksDao.update(event.getResourceId(), event.getOfferingId(), event.getResourceType()); + } else { - s_logger.error(String.format("Unknown event type [%s] in Networks event parser. Skipping it.", event.getType())); ++ logger.error("Unknown event type [{}] in Networks event parser. Skipping it.", event.getType()); + } + } + private void handleVpcEvent(UsageEventVO event) { Account account = _accountDao.findByIdIncludingRemoved(event.getAccountId()); long domainId = account.getDomainId(); diff --cc usage/src/main/java/com/cloud/usage/parser/NetworksUsageParser.java index 00000000000,9ebfaa31ce0..a27e2ba226e mode 000000,100644..100644 --- a/usage/src/main/java/com/cloud/usage/parser/NetworksUsageParser.java +++ b/usage/src/main/java/com/cloud/usage/parser/NetworksUsageParser.java @@@ -1,0 -1,99 +1,100 @@@ + // Licensed to the Apache Software Foundation (ASF) under one + // or more contributor license agreements. See the NOTICE file + // distributed with this work for additional information + // regarding copyright ownership. The ASF licenses this file + // to you under the Apache License, Version 2.0 (the + // "License"); you may not use this file except in compliance + // with the License. You may obtain a copy of the License at + // + // http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, + // software distributed under the License is distributed on an + // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + // KIND, either express or implied. See the License for the + // specific language governing permissions and limitations + // under the License. + package com.cloud.usage.parser; + + import com.cloud.usage.UsageNetworksVO; + import com.cloud.usage.UsageVO; + import com.cloud.usage.dao.UsageDao; + import com.cloud.usage.dao.UsageNetworksDao; + import com.cloud.user.AccountVO; + import javax.annotation.PostConstruct; + import javax.inject.Inject; + + import org.apache.cloudstack.usage.UsageTypes; + import org.apache.commons.collections.CollectionUtils; -import org.apache.log4j.Logger; ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.Logger; + import org.springframework.stereotype.Component; + + import java.text.DecimalFormat; + import java.util.Date; + import java.util.List; + + @Component + public class NetworksUsageParser { - private static final Logger LOGGER = Logger.getLogger(NetworksUsageParser.class.getName()); ++ private static final Logger LOGGER = LogManager.getLogger(NetworksUsageParser.class.getName()); + + @Inject + private UsageNetworksDao networksDao; + @Inject + private UsageDao usageDao; + + private static UsageDao staticUsageDao; + private static UsageNetworksDao staticNetworksDao; + + @PostConstruct + void init() { + staticUsageDao = usageDao; + staticNetworksDao = networksDao; + } + + public static boolean parse(AccountVO account, Date startDate, Date endDate) { + LOGGER.debug(String.format("Parsing all networks usage events for account [%s].", account.getId())); + if ((endDate == null) || endDate.after(new Date())) { + endDate = new Date(); + } + + final List<UsageNetworksVO> usageNetworksVO = staticNetworksDao.getUsageRecords(account.getId(), startDate, endDate); + if (CollectionUtils.isEmpty(usageNetworksVO)) { + LOGGER.debug(String.format("Cannot find any VPC usage for account [%s] in period between [%s] and [%s].", account, startDate, endDate)); + return true; + } + + for (final UsageNetworksVO usageNetwork : usageNetworksVO) { + Long zoneId = usageNetwork.getZoneId(); + Date createdDate = usageNetwork.getCreated(); + Date removedDate = usageNetwork.getRemoved(); + if (createdDate.before(startDate)) { + createdDate = startDate; + } + + if (removedDate == null || removedDate.after(endDate)) { + removedDate = endDate; + } + + final long duration = (removedDate.getTime() - createdDate.getTime()) + 1; + final float usage = duration / 1000f / 60f / 60f; + DecimalFormat dFormat = new DecimalFormat("#.######"); + String usageDisplay = dFormat.format(usage); + + long networkId = usageNetwork.getNetworkId(); + long networkOfferingId = usageNetwork.getNetworkOfferingId(); + LOGGER.debug(String.format("Creating network usage record with id [%s], network offering [%s], usage [%s], startDate [%s], and endDate [%s], for account [%s].", + networkId, networkOfferingId, usageDisplay, startDate, endDate, account.getId())); + + String description = String.format("Network usage for network ID: %d, network offering: %d", usageNetwork.getNetworkId(), usageNetwork.getNetworkOfferingId()); + UsageVO usageRecord = + new UsageVO(zoneId, account.getAccountId(), account.getDomainId(), description, usageDisplay + " Hrs", + UsageTypes.NETWORK, (double) usage, null, null, usageNetwork.getNetworkOfferingId(), null, usageNetwork.getNetworkId(), + (long)0, null, startDate, endDate); + usageRecord.setState(usageNetwork.getState()); + staticUsageDao.persist(usageRecord); + } + + return true; + } + }