Skip to content

Commit 49d244f

Browse files
SadiJrSadiJrBryanMLima
authored
[Usage] Create VPC billing (apache#7235)
Co-authored-by: SadiJr <sadi@scclouds.com.br> Co-authored-by: Bryan Lima <bryan.lima@hotmail.com>
1 parent 78e07cf commit 49d244f

16 files changed

Lines changed: 509 additions & 1 deletion

File tree

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,4 +1219,8 @@ public static Class getEntityClassForEvent(String eventName) {
12191219

12201220
return null;
12211221
}
1222+
1223+
public static boolean isVpcEvent(String eventType) {
1224+
return EventTypes.EVENT_VPC_CREATE.equals(eventType) || EventTypes.EVENT_VPC_DELETE.equals(eventType);
1225+
}
12221226
}

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 VPC = 31;
4950

5051
public static List<UsageTypeResponse> listUsageTypes() {
5152
List<UsageTypeResponse> responseList = new ArrayList<UsageTypeResponse>();
@@ -72,6 +73,7 @@ public static List<UsageTypeResponse> listUsageTypes() {
7273
responseList.add(new UsageTypeResponse(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage"));
7374
responseList.add(new UsageTypeResponse(BACKUP, "Backup storage usage"));
7475
responseList.add(new UsageTypeResponse(BUCKET, "Bucket storage usage"));
76+
responseList.add(new UsageTypeResponse(VPC, "VPC usage"));
7577
return responseList;
7678
}
7779
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
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_vpc")
33+
public class UsageVpcVO implements InternalIdentity {
34+
35+
@Id
36+
@GeneratedValue(strategy = GenerationType.IDENTITY)
37+
@Column(name = "id")
38+
private long id;
39+
40+
@Column(name = "vpc_id")
41+
private long vpcId;
42+
43+
@Column(name = "zone_id")
44+
private long zoneId;
45+
46+
@Column(name = "account_id")
47+
private long accountId;
48+
49+
@Column(name = "domain_id")
50+
private long domainId;
51+
52+
53+
@Column(name = "state")
54+
private String state;
55+
56+
@Column(name = "created")
57+
@Temporal(value = TemporalType.TIMESTAMP)
58+
private Date created = null;
59+
60+
@Column(name = "removed")
61+
@Temporal(value = TemporalType.TIMESTAMP)
62+
private Date removed = null;
63+
64+
protected UsageVpcVO(){}
65+
66+
public UsageVpcVO(long id, long vpcId, long zoneId, long accountId, long domainId, String state, Date created, Date removed) {
67+
this.id = id;
68+
this.vpcId = vpcId;
69+
this.zoneId = zoneId;
70+
this.domainId = domainId;
71+
this.accountId = accountId;
72+
this.state = state;
73+
this.created = created;
74+
this.removed = removed;
75+
}
76+
public UsageVpcVO(long vpcId, long zoneId, long accountId, long domainId, String state, Date created, Date removed) {
77+
this.vpcId = vpcId;
78+
this.zoneId = zoneId;
79+
this.domainId = domainId;
80+
this.accountId = accountId;
81+
this.state = state;
82+
this.created = created;
83+
this.removed = removed;
84+
}
85+
86+
@Override
87+
public long getId() {
88+
return id;
89+
}
90+
91+
public long getZoneId() {
92+
return zoneId;
93+
}
94+
95+
public long getAccountId() {
96+
return accountId;
97+
}
98+
99+
public long getDomainId() {
100+
return domainId;
101+
}
102+
103+
public long getVpcId() {
104+
return vpcId;
105+
}
106+
107+
public void setVpcId(long vpcId) {
108+
this.vpcId = vpcId;
109+
}
110+
111+
public String getState() {
112+
return state;
113+
}
114+
115+
public void setState(String state) {
116+
this.state = state;
117+
}
118+
119+
public Date getCreated() {
120+
return created;
121+
}
122+
123+
public Date getRemoved() {
124+
return removed;
125+
}
126+
127+
public void setRemoved(Date removed) {
128+
this.removed = removed;
129+
}
130+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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.UsageVpcVO;
20+
import com.cloud.utils.db.GenericDao;
21+
22+
import java.util.Date;
23+
import java.util.List;
24+
25+
public interface UsageVpcDao extends GenericDao<UsageVpcVO, Long> {
26+
void update(UsageVpcVO usage);
27+
void remove(long vpcId, Date removed);
28+
List<UsageVpcVO> getUsageRecords(Long accountId, Date startDate, Date endDate);
29+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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.vpc.Vpc;
20+
import com.cloud.usage.UsageVpcVO;
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 UsageVpcDaoImpl extends GenericDaoBase<UsageVpcVO, Long> implements UsageVpcDao {
37+
private static final Logger LOGGER = Logger.getLogger(UsageVpcDaoImpl.class);
38+
protected static final String GET_USAGE_RECORDS_BY_ACCOUNT = "SELECT id, vpc_id, zone_id, account_id, domain_id, state, created, removed FROM usage_vpc 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+
@Override
43+
public void update(UsageVpcVO usage) {
44+
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
45+
try {
46+
SearchCriteria<UsageVpcVO> sc = this.createSearchCriteria();
47+
sc.addAnd("vpcId", SearchCriteria.Op.EQ, usage.getVpcId());
48+
sc.addAnd("created", SearchCriteria.Op.EQ, usage.getCreated());
49+
UsageVpcVO vo = findOneBy(sc);
50+
if (vo != null) {
51+
vo.setRemoved(usage.getRemoved());
52+
update(vo.getId(), vo);
53+
}
54+
} catch (final Exception e) {
55+
LOGGER.error(String.format("Error updating usage of VPC due to [%s].", e.getMessage()), e);
56+
txn.rollback();
57+
} finally {
58+
txn.close();
59+
}
60+
}
61+
62+
@Override
63+
public void remove(long vpcId, Date removed) {
64+
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
65+
try {
66+
SearchCriteria<UsageVpcVO> sc = this.createSearchCriteria();
67+
sc.addAnd("vpcId", SearchCriteria.Op.EQ, vpcId);
68+
sc.addAnd("removed", SearchCriteria.Op.NULL);
69+
UsageVpcVO vo = findOneBy(sc);
70+
if (vo != null) {
71+
vo.setRemoved(removed);
72+
vo.setState(Vpc.State.Inactive.name());
73+
update(vo.getId(), vo);
74+
}
75+
} catch (final Exception e) {
76+
txn.rollback();
77+
LOGGER.error(String.format("Error updating usage of VPC due to [%s].", e.getMessage()), e);
78+
} finally {
79+
txn.close();
80+
}
81+
}
82+
83+
@Override
84+
public List<UsageVpcVO> getUsageRecords(Long accountId, Date startDate, Date endDate) {
85+
List<UsageVpcVO> usageRecords = new ArrayList<>();
86+
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
87+
PreparedStatement pstmt;
88+
try {
89+
int i = 1;
90+
pstmt = txn.prepareAutoCloseStatement(GET_USAGE_RECORDS_BY_ACCOUNT);
91+
pstmt.setLong(i++, accountId);
92+
93+
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
94+
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
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+
101+
ResultSet rs = pstmt.executeQuery();
102+
while (rs.next()) {
103+
long id = rs.getLong(1);
104+
long vpcId = rs.getLong(2);
105+
long zoneId = rs.getLong(3);
106+
long acctId = rs.getLong(4);
107+
long domId = rs.getLong(5);
108+
String stateTS = rs.getString(6);
109+
Date createdDate = null;
110+
Date removedDate = null;
111+
String createdTS = rs.getString(7);
112+
String removedTS = rs.getString(8);
113+
114+
if (createdTS != null) {
115+
createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS);
116+
}
117+
if (removedTS != null) {
118+
removedDate = DateUtil.parseDateString(s_gmtTimeZone, removedTS);
119+
}
120+
usageRecords.add(new UsageVpcVO(id, vpcId, zoneId, acctId, domId, stateTS, createdDate, removedDate));
121+
}
122+
} catch (Exception e) {
123+
txn.rollback();
124+
LOGGER.warn("Error getting VPC usage records", e);
125+
} finally {
126+
txn.close();
127+
}
128+
129+
return usageRecords;
130+
}
131+
}

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="VpcDaoImpl" class="org.apache.cloudstack.quota.dao.VpcDaoImpl" />
7071
<bean id="volumeDaoImpl" class="com.cloud.storage.dao.VolumeDaoImpl" />
7172
<bean id="backupOfferingDaoImpl" class="org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl" />
7273
</beans>

engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@
203203
<bean id="usageStorageDaoImpl" class="com.cloud.usage.dao.UsageStorageDaoImpl" />
204204
<bean id="usageVMInstanceDaoImpl" class="com.cloud.usage.dao.UsageVMInstanceDaoImpl" />
205205
<bean id="usageVPNUserDaoImpl" class="com.cloud.usage.dao.UsageVPNUserDaoImpl" />
206+
<bean id="usageVpcDaoImpl" class="com.cloud.usage.dao.UsageVpcDaoImpl" />
206207
<bean id="usageVolumeDaoImpl" class="com.cloud.usage.dao.UsageVolumeDaoImpl" />
207208
<bean id="usageVmDiskDaoImpl" class="com.cloud.usage.dao.UsageVmDiskDaoImpl" />
208209
<bean id="usageBackupDaoImpl" class="com.cloud.usage.dao.UsageBackupDaoImpl" />

engine/schema/src/main/resources/META-INF/db/schema-41900to41910.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,18 @@ UPDATE cloud_usage.quota_tariff
3030
SET usage_unit = 'IOPS', updated_on = NOW()
3131
WHERE effective_on = '2010-05-04 00:00:00'
3232
AND name IN ('VM_DISK_IO_READ', 'VM_DISK_IO_WRITE');
33+
34+
-- PR #7235 - [Usage] Create VPC billing
35+
CREATE TABLE IF NOT EXISTS `cloud_usage`.`usage_vpc` (
36+
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
37+
`vpc_id` bigint(20) unsigned NOT NULL,
38+
`zone_id` bigint(20) unsigned NOT NULL,
39+
`account_id` bigint(20) unsigned NOT NULL,
40+
`domain_id` bigint(20) unsigned NOT NULL,
41+
`state` varchar(100) DEFAULT NULL,
42+
`created` datetime NOT NULL,
43+
`removed` datetime DEFAULT NULL,
44+
PRIMARY KEY (`id`)
45+
) ENGINE=InnoDB CHARSET=utf8;
46+
47+
CALL `cloud_usage`.`IDEMPOTENT_ADD_COLUMN`('cloud_usage.cloud_usage', 'state', 'VARCHAR(100) DEFAULT NULL');

0 commit comments

Comments
 (0)