Skip to content

Commit 96ae479

Browse files
SadiJrBryanMLimaSadiJrhsato03
authored
[Usage] Create network billing (#7236)
Co-authored-by: Bryan Lima <bryan.lima@hotmail.com> Co-authored-by: SadiJr <sadi@scclouds.com.br> Co-authored-by: Bryan Lima <42067040+BryanMLima@users.noreply.github.com> Co-authored-by: Henrique Sato <henriquesato2003@gmail.com>
1 parent 0b857de commit 96ae479

File tree

20 files changed

+575
-2
lines changed

20 files changed

+575
-2
lines changed

api/src/main/java/com/cloud/event/EventTypes.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,10 @@ public class EventTypes {
11931193
entityEventDetails.put(EVENT_QUOTA_TARIFF_UPDATE, QuotaTariff.class);
11941194
}
11951195

1196+
public static boolean isNetworkEvent(String eventType) {
1197+
return EVENT_NETWORK_CREATE.equals(eventType) || EVENT_NETWORK_DELETE.equals(eventType) ||
1198+
EVENT_NETWORK_UPDATE.equals(eventType);
1199+
}
11961200
public static String getEntityForEvent(String eventName) {
11971201
Object entityClass = entityEventDetails.get(eventName);
11981202
if (entityClass == null) {

api/src/main/java/org/apache/cloudstack/usage/UsageTypes.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class UsageTypes {
4646
public static final int VM_SNAPSHOT_ON_PRIMARY = 27;
4747
public static final int BACKUP = 28;
4848
public static final int BUCKET = 29;
49+
public static final int NETWORK = 30;
4950
public static final int VPC = 31;
5051

5152
public static List<UsageTypeResponse> listUsageTypes() {
@@ -73,6 +74,7 @@ public static List<UsageTypeResponse> listUsageTypes() {
7374
responseList.add(new UsageTypeResponse(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage"));
7475
responseList.add(new UsageTypeResponse(BACKUP, "Backup storage usage"));
7576
responseList.add(new UsageTypeResponse(BUCKET, "Bucket storage usage"));
77+
responseList.add(new UsageTypeResponse(NETWORK, "Network usage"));
7678
responseList.add(new UsageTypeResponse(VPC, "VPC usage"));
7779
return responseList;
7880
}

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,8 @@ public Pair<NetworkGuru, NetworkVO> implementNetwork(final long networkId, final
14091409
if (isNetworkImplemented(network)) {
14101410
s_logger.debug("Network id=" + networkId + " is already implemented");
14111411
implemented.set(guru, network);
1412+
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_UPDATE, network.getAccountId(), network.getDataCenterId(), network.getId(),
1413+
network.getName(), network.getNetworkOfferingId(), null, network.getState().name(), Network.class.getName(), network.getUuid(), true);
14121414
return implemented;
14131415
}
14141416

@@ -1469,6 +1471,8 @@ public Pair<NetworkGuru, NetworkVO> implementNetwork(final long networkId, final
14691471
network.setRestartRequired(false);
14701472
_networksDao.update(network.getId(), network);
14711473
implemented.set(guru, network);
1474+
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_CREATE, network.getAccountId(), network.getDataCenterId(), network.getId(),
1475+
network.getName(), network.getNetworkOfferingId(), null, null, null, network.getState().name(), network.getUuid());
14721476
return implemented;
14731477
} catch (final NoTransitionException e) {
14741478
s_logger.error(e.getMessage());
@@ -3344,6 +3348,8 @@ public void doInTransactionWithoutResult(final TransactionStatus status) {
33443348
final Pair<Class<?>, Long> networkMsg = new Pair<Class<?>, Long>(Network.class, networkFinal.getId());
33453349
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, networkMsg);
33463350
}
3351+
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_DELETE, network.getAccountId(), network.getDataCenterId(), network.getId(),
3352+
network.getName(), network.getNetworkOfferingId(), null, null, null, Network.class.getName(), network.getUuid());
33473353
return true;
33483354
} catch (final CloudRuntimeException e) {
33493355
s_logger.error("Failed to delete network", e);
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.usage;
18+
19+
import javax.persistence.Column;
20+
import javax.persistence.Entity;
21+
import javax.persistence.GeneratedValue;
22+
import javax.persistence.GenerationType;
23+
import javax.persistence.Id;
24+
import javax.persistence.Table;
25+
import javax.persistence.Temporal;
26+
import javax.persistence.TemporalType;
27+
import org.apache.cloudstack.api.InternalIdentity;
28+
29+
import java.util.Date;
30+
31+
@Entity
32+
@Table(name = "usage_networks")
33+
public class UsageNetworksVO implements InternalIdentity {
34+
@Id
35+
@GeneratedValue(strategy = GenerationType.IDENTITY)
36+
@Column(name = "id")
37+
private long id;
38+
39+
@Column(name = "network_id")
40+
private long networkId;
41+
42+
@Column(name = "network_offering_id")
43+
private long networkOfferingId;
44+
45+
@Column(name = "zone_id")
46+
private long zoneId;
47+
48+
@Column(name = "account_id")
49+
private long accountId;
50+
51+
@Column(name = "domain_id")
52+
private long domainId;
53+
54+
@Column(name = "state")
55+
private String state;
56+
57+
@Column(name = "created")
58+
@Temporal(value = TemporalType.TIMESTAMP)
59+
private Date created = null;
60+
61+
@Column(name = "removed")
62+
@Temporal(value = TemporalType.TIMESTAMP)
63+
private Date removed = null;
64+
65+
protected UsageNetworksVO() {
66+
}
67+
68+
public UsageNetworksVO(long id, long networkId, long networkOfferingId, long zoneId, long accountId, long domainId, String state, Date created, Date removed) {
69+
this.id = id;
70+
this.networkId = networkId;
71+
this.networkOfferingId = networkOfferingId;
72+
this.zoneId = zoneId;
73+
this.domainId = domainId;
74+
this.accountId = accountId;
75+
this.state = state;
76+
this.created = created;
77+
this.removed = removed;
78+
}
79+
80+
public UsageNetworksVO(long networkId, long networkOfferingId, long zoneId, long accountId, long domainId, String state, Date created, Date removed) {
81+
this.networkId = networkId;
82+
this.networkOfferingId = networkOfferingId;
83+
this.zoneId = zoneId;
84+
this.domainId = domainId;
85+
this.accountId = accountId;
86+
this.state = state;
87+
this.created = created;
88+
this.removed = removed;
89+
}
90+
91+
@Override
92+
public long getId() {
93+
return id;
94+
}
95+
96+
public long getZoneId() {
97+
return zoneId;
98+
}
99+
100+
public long getAccountId() {
101+
return accountId;
102+
}
103+
104+
public long getDomainId() {
105+
return domainId;
106+
}
107+
108+
public long getNetworkId() {
109+
return networkId;
110+
}
111+
112+
public void setNetworkId(long networkId) {
113+
this.networkId = networkId;
114+
}
115+
116+
public long getNetworkOfferingId() {
117+
return networkOfferingId;
118+
}
119+
120+
public void setNetworkOfferingId(long networkOfferingId) {
121+
this.networkOfferingId = networkOfferingId;
122+
}
123+
124+
public String getState() {
125+
return state;
126+
}
127+
128+
public void setState(String state) {
129+
this.state = state;
130+
}
131+
132+
public Date getCreated() {
133+
return created;
134+
}
135+
136+
public Date getRemoved() {
137+
return removed;
138+
}
139+
140+
public void setRemoved(Date removed) {
141+
this.removed = removed;
142+
}
143+
}

engine/schema/src/main/java/com/cloud/usage/UsageVO.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ public class UsageVO implements Usage, InternalIdentity {
110110
@Column(name = "is_hidden")
111111
private boolean isHidden = false;
112112

113+
@Column(name = "state")
114+
private String state;
115+
113116
public Integer getQuotaCalculated() {
114117
return quotaCalculated;
115118
}
@@ -398,6 +401,14 @@ public void setHidden(boolean hidden) {
398401
this.isHidden = hidden;
399402
}
400403

404+
public String getState() {
405+
return state;
406+
}
407+
408+
public void setState(String state) {
409+
this.state = state;
410+
}
411+
401412
@Override
402413
public String toString() {
403414
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "usageId", "usageType", "startDate", "endDate");
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.usage.dao;
18+
19+
import com.cloud.usage.UsageNetworksVO;
20+
import com.cloud.utils.db.GenericDao;
21+
22+
import java.util.Date;
23+
import java.util.List;
24+
25+
public interface UsageNetworksDao extends GenericDao<UsageNetworksVO, Long> {
26+
void update(long networkId, long newNetworkOffering, String state);
27+
28+
void remove(long networkId, Date removed);
29+
30+
List<UsageNetworksVO> getUsageRecords(Long accountId, Date startDate, Date endDate);
31+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.usage.dao;
18+
19+
import com.cloud.network.Network;
20+
import com.cloud.usage.UsageNetworksVO;
21+
import com.cloud.utils.DateUtil;
22+
import com.cloud.utils.db.GenericDaoBase;
23+
import com.cloud.utils.db.SearchCriteria;
24+
import com.cloud.utils.db.TransactionLegacy;
25+
import org.apache.log4j.Logger;
26+
import org.springframework.stereotype.Component;
27+
28+
import java.sql.PreparedStatement;
29+
import java.sql.ResultSet;
30+
import java.util.ArrayList;
31+
import java.util.Date;
32+
import java.util.List;
33+
import java.util.TimeZone;
34+
35+
@Component
36+
public class UsageNetworksDaoImpl extends GenericDaoBase<UsageNetworksVO, Long> implements UsageNetworksDao {
37+
private static final Logger LOGGER = Logger.getLogger(UsageNetworksDaoImpl.class);
38+
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 " +
39+
" account_id = ? AND ((removed IS NULL AND created <= ?) OR (created BETWEEN ? AND ?) OR (removed BETWEEN ? AND ?) " +
40+
" OR ((created <= ?) AND (removed >= ?)))";
41+
42+
43+
@Override
44+
public void update(long networkId, long newNetworkOffering, String state) {
45+
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
46+
try {
47+
SearchCriteria<UsageNetworksVO> sc = this.createSearchCriteria();
48+
sc.addAnd("networkId", SearchCriteria.Op.EQ, networkId);
49+
sc.addAnd("removed", SearchCriteria.Op.NULL);
50+
UsageNetworksVO vo = findOneBy(sc);
51+
if (vo != null) {
52+
vo.setNetworkOfferingId(newNetworkOffering);
53+
vo.setState(state);
54+
update(vo.getId(), vo);
55+
}
56+
} catch (final Exception e) {
57+
txn.rollback();
58+
LOGGER.error(String.format("Error updating usage of network due to [%s].", e.getMessage()), e);
59+
} finally {
60+
txn.close();
61+
}
62+
}
63+
64+
@Override
65+
public void remove(long networkId, Date removed) {
66+
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
67+
try {
68+
SearchCriteria<UsageNetworksVO> sc = this.createSearchCriteria();
69+
sc.addAnd("networkId", SearchCriteria.Op.EQ, networkId);
70+
sc.addAnd("removed", SearchCriteria.Op.NULL);
71+
UsageNetworksVO vo = findOneBy(sc);
72+
if (vo != null) {
73+
vo.setRemoved(removed);
74+
vo.setState(Network.State.Destroy.name());
75+
update(vo.getId(), vo);
76+
}
77+
} catch (final Exception e) {
78+
txn.rollback();
79+
LOGGER.error(String.format("Error updating usage of network due to [%s].", e.getMessage()), e);
80+
} finally {
81+
txn.close();
82+
}
83+
}
84+
85+
@Override
86+
public List<UsageNetworksVO> getUsageRecords(Long accountId, Date startDate, Date endDate) {
87+
List<UsageNetworksVO> usageRecords = new ArrayList<>();
88+
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
89+
PreparedStatement pstmt;
90+
try {
91+
int i = 1;
92+
pstmt = txn.prepareAutoCloseStatement(GET_USAGE_RECORDS_BY_ACCOUNT);
93+
pstmt.setLong(i++, accountId);
94+
95+
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
96+
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
97+
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
98+
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
99+
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
100+
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
101+
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
102+
103+
ResultSet rs = pstmt.executeQuery();
104+
while (rs.next()) {
105+
long id = rs.getLong(1);
106+
long networkId = rs.getLong(2);
107+
long networkOfferingId = rs.getLong(3);
108+
long zoneId = rs.getLong(4);
109+
long acctId = rs.getLong(5);
110+
long domId = rs.getLong(6);
111+
String stateTS = rs.getString(7);
112+
Date createdDate = null;
113+
Date removedDate = null;
114+
String createdTS = rs.getString(8);
115+
String removedTS = rs.getString(9);
116+
117+
if (createdTS != null) {
118+
createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS);
119+
}
120+
if (removedTS != null) {
121+
removedDate = DateUtil.parseDateString(s_gmtTimeZone, removedTS);
122+
}
123+
usageRecords.add(new UsageNetworksVO(id, networkId, networkOfferingId, zoneId, acctId, domId, stateTS, createdDate, removedDate));
124+
}
125+
} catch (Exception e) {
126+
txn.rollback();
127+
LOGGER.warn("Error getting networks usage records", e);
128+
} finally {
129+
txn.close();
130+
}
131+
132+
return usageRecords;
133+
}
134+
}

engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
<bean id="vMInstanceDaoImpl" class="com.cloud.vm.dao.VMInstanceDaoImpl" />
6868
<bean id="vMSnapshotDaoImpl" class="com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl" />
6969
<bean id="VmTemplateDaoImpl" class="org.apache.cloudstack.quota.dao.VmTemplateDaoImpl" />
70+
<bean id="NetworkDaoImpl" class="org.apache.cloudstack.quota.dao.NetworkDaoImpl" />
7071
<bean id="VpcDaoImpl" class="org.apache.cloudstack.quota.dao.VpcDaoImpl" />
7172
<bean id="volumeDaoImpl" class="com.cloud.storage.dao.VolumeDaoImpl" />
7273
<bean id="backupOfferingDaoImpl" class="org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl" />

0 commit comments

Comments
 (0)