Merge branch '4.19'

This commit is contained in:
Daan Hoogland 2024-04-24 14:01:02 +02:00
commit 0af923e618
25 changed files with 588 additions and 22 deletions

View File

@ -1193,6 +1193,10 @@ public class EventTypes {
entityEventDetails.put(EVENT_QUOTA_TARIFF_UPDATE, QuotaTariff.class); entityEventDetails.put(EVENT_QUOTA_TARIFF_UPDATE, QuotaTariff.class);
} }
public static boolean isNetworkEvent(String eventType) {
return EVENT_NETWORK_CREATE.equals(eventType) || EVENT_NETWORK_DELETE.equals(eventType) ||
EVENT_NETWORK_UPDATE.equals(eventType);
}
public static String getEntityForEvent(String eventName) { public static String getEntityForEvent(String eventName) {
Object entityClass = entityEventDetails.get(eventName); Object entityClass = entityEventDetails.get(eventName);
if (entityClass == null) { if (entityClass == null) {

View File

@ -46,6 +46,7 @@ public class UsageTypes {
public static final int VM_SNAPSHOT_ON_PRIMARY = 27; public static final int VM_SNAPSHOT_ON_PRIMARY = 27;
public static final int BACKUP = 28; public static final int BACKUP = 28;
public static final int BUCKET = 29; public static final int BUCKET = 29;
public static final int NETWORK = 30;
public static final int VPC = 31; public static final int VPC = 31;
public static List<UsageTypeResponse> listUsageTypes() { public static List<UsageTypeResponse> listUsageTypes() {
@ -73,6 +74,7 @@ public class UsageTypes {
responseList.add(new UsageTypeResponse(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage")); responseList.add(new UsageTypeResponse(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage"));
responseList.add(new UsageTypeResponse(BACKUP, "Backup storage usage")); responseList.add(new UsageTypeResponse(BACKUP, "Backup storage usage"));
responseList.add(new UsageTypeResponse(BUCKET, "Bucket storage usage")); responseList.add(new UsageTypeResponse(BUCKET, "Bucket storage usage"));
responseList.add(new UsageTypeResponse(NETWORK, "Network usage"));
responseList.add(new UsageTypeResponse(VPC, "VPC usage")); responseList.add(new UsageTypeResponse(VPC, "VPC usage"));
return responseList; return responseList;
} }

View File

@ -28,10 +28,6 @@
<version>4.20.0.0-SNAPSHOT</version> <version>4.20.0.0-SNAPSHOT</version>
</parent> </parent>
<repositories> <repositories>
<repository>
<id>juniper-contrail</id>
<url>https://juniper.github.io/contrail-maven/snapshots</url>
</repository>
<repository> <repository>
<id>juniper-tungsten-api</id> <id>juniper-tungsten-api</id>
<url>https://github.com/radu-todirica/tungsten-api/raw/master</url> <url>https://github.com/radu-todirica/tungsten-api/raw/master</url>
@ -271,11 +267,6 @@
<artifactId>cloud-plugin-network-nvp</artifactId> <artifactId>cloud-plugin-network-nvp</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-network-contrail</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.cloudstack</groupId> <groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-network-palo-alto</artifactId> <artifactId>cloud-plugin-network-palo-alto</artifactId>
@ -1107,6 +1098,11 @@
<artifactId>cloud-plugin-api-vmware-sioc</artifactId> <artifactId>cloud-plugin-api-vmware-sioc</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-network-contrail</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.cloudstack</groupId> <groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-backup-veeam</artifactId> <artifactId>cloud-plugin-backup-veeam</artifactId>

View File

@ -1466,6 +1466,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
if (isNetworkImplemented(network)) { if (isNetworkImplemented(network)) {
logger.debug("Network id={} is already implemented", networkId); logger.debug("Network id={} is already implemented", networkId);
implemented.set(guru, network); 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; return implemented;
} }
@ -1522,6 +1524,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
network.setRestartRequired(false); network.setRestartRequired(false);
_networksDao.update(network.getId(), network); _networksDao.update(network.getId(), network);
implemented.set(guru, 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; return implemented;
} catch (final NoTransitionException e) { } catch (final NoTransitionException e) {
logger.error(e.getMessage()); logger.error(e.getMessage());
@ -3370,6 +3374,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
final Pair<Class<?>, Long> networkMsg = new Pair<Class<?>, Long>(Network.class, networkFinal.getId()); final Pair<Class<?>, Long> networkMsg = new Pair<Class<?>, Long>(Network.class, networkFinal.getId());
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, networkMsg); _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; return true;
} catch (final CloudRuntimeException e) { } catch (final CloudRuntimeException e) {
logger.error("Failed to delete network", e); logger.error("Failed to delete network", e);

View File

@ -0,0 +1,143 @@
// 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;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.cloudstack.api.InternalIdentity;
import java.util.Date;
@Entity
@Table(name = "usage_networks")
public class UsageNetworksVO implements InternalIdentity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "network_id")
private long networkId;
@Column(name = "network_offering_id")
private long networkOfferingId;
@Column(name = "zone_id")
private long zoneId;
@Column(name = "account_id")
private long accountId;
@Column(name = "domain_id")
private long domainId;
@Column(name = "state")
private String state;
@Column(name = "created")
@Temporal(value = TemporalType.TIMESTAMP)
private Date created = null;
@Column(name = "removed")
@Temporal(value = TemporalType.TIMESTAMP)
private Date removed = null;
protected UsageNetworksVO() {
}
public UsageNetworksVO(long id, long networkId, long networkOfferingId, long zoneId, long accountId, long domainId, String state, Date created, Date removed) {
this.id = id;
this.networkId = networkId;
this.networkOfferingId = networkOfferingId;
this.zoneId = zoneId;
this.domainId = domainId;
this.accountId = accountId;
this.state = state;
this.created = created;
this.removed = removed;
}
public UsageNetworksVO(long networkId, long networkOfferingId, long zoneId, long accountId, long domainId, String state, Date created, Date removed) {
this.networkId = networkId;
this.networkOfferingId = networkOfferingId;
this.zoneId = zoneId;
this.domainId = domainId;
this.accountId = accountId;
this.state = state;
this.created = created;
this.removed = removed;
}
@Override
public long getId() {
return id;
}
public long getZoneId() {
return zoneId;
}
public long getAccountId() {
return accountId;
}
public long getDomainId() {
return domainId;
}
public long getNetworkId() {
return networkId;
}
public void setNetworkId(long networkId) {
this.networkId = networkId;
}
public long getNetworkOfferingId() {
return networkOfferingId;
}
public void setNetworkOfferingId(long networkOfferingId) {
this.networkOfferingId = networkOfferingId;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Date getCreated() {
return created;
}
public Date getRemoved() {
return removed;
}
public void setRemoved(Date removed) {
this.removed = removed;
}
}

View File

@ -113,6 +113,9 @@ public class UsageVO implements Usage, InternalIdentity {
@Column(name = "is_hidden") @Column(name = "is_hidden")
private boolean isHidden = false; private boolean isHidden = false;
@Column(name = "state")
private String state;
public Integer getQuotaCalculated() { public Integer getQuotaCalculated() {
return quotaCalculated; return quotaCalculated;
} }
@ -401,6 +404,14 @@ public class UsageVO implements Usage, InternalIdentity {
this.isHidden = hidden; this.isHidden = hidden;
} }
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override @Override
public String toString() { public String toString() {
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "usageId", "usageType"); return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "usageId", "usageType");

View File

@ -0,0 +1,31 @@
// 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.usage.UsageNetworksVO;
import com.cloud.utils.db.GenericDao;
import java.util.Date;
import java.util.List;
public interface UsageNetworksDao extends GenericDao<UsageNetworksVO, Long> {
void update(long networkId, long newNetworkOffering, String state);
void remove(long networkId, Date removed);
List<UsageNetworksVO> getUsageRecords(Long accountId, Date startDate, Date endDate);
}

View File

@ -0,0 +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.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 = 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;
}
}

View File

@ -67,6 +67,7 @@
<bean id="vMInstanceDaoImpl" class="com.cloud.vm.dao.VMInstanceDaoImpl" /> <bean id="vMInstanceDaoImpl" class="com.cloud.vm.dao.VMInstanceDaoImpl" />
<bean id="vMSnapshotDaoImpl" class="com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl" /> <bean id="vMSnapshotDaoImpl" class="com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl" />
<bean id="VmTemplateDaoImpl" class="org.apache.cloudstack.quota.dao.VmTemplateDaoImpl" /> <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="VpcDaoImpl" class="org.apache.cloudstack.quota.dao.VpcDaoImpl" />
<bean id="volumeDaoImpl" class="com.cloud.storage.dao.VolumeDaoImpl" /> <bean id="volumeDaoImpl" class="com.cloud.storage.dao.VolumeDaoImpl" />
<bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" /> <bean id="reservationDao" class="org.apache.cloudstack.reservation.dao.ReservationDaoImpl" />

View File

@ -197,6 +197,7 @@
<bean id="usageJobDaoImpl" class="com.cloud.usage.dao.UsageJobDaoImpl" /> <bean id="usageJobDaoImpl" class="com.cloud.usage.dao.UsageJobDaoImpl" />
<bean id="usageLoadBalancerPolicyDaoImpl" class="com.cloud.usage.dao.UsageLoadBalancerPolicyDaoImpl" /> <bean id="usageLoadBalancerPolicyDaoImpl" class="com.cloud.usage.dao.UsageLoadBalancerPolicyDaoImpl" />
<bean id="usageNetworkDaoImpl" class="com.cloud.usage.dao.UsageNetworkDaoImpl" /> <bean id="usageNetworkDaoImpl" class="com.cloud.usage.dao.UsageNetworkDaoImpl" />
<bean id="usageNetworksDaoImpl" class="com.cloud.usage.dao.UsageNetworksDaoImpl" />
<bean id="usageNetworkOfferingDaoImpl" class="com.cloud.usage.dao.UsageNetworkOfferingDaoImpl" /> <bean id="usageNetworkOfferingDaoImpl" class="com.cloud.usage.dao.UsageNetworkOfferingDaoImpl" />
<bean id="usagePortForwardingRuleDaoImpl" class="com.cloud.usage.dao.UsagePortForwardingRuleDaoImpl" /> <bean id="usagePortForwardingRuleDaoImpl" class="com.cloud.usage.dao.UsagePortForwardingRuleDaoImpl" />
<bean id="usageSecurityGroupDaoImpl" class="com.cloud.usage.dao.UsageSecurityGroupDaoImpl" /> <bean id="usageSecurityGroupDaoImpl" class="com.cloud.usage.dao.UsageSecurityGroupDaoImpl" />

View File

@ -31,6 +31,20 @@ SET usage_unit = 'IOPS', updated_on = NOW()
WHERE effective_on = '2010-05-04 00:00:00' WHERE effective_on = '2010-05-04 00:00:00'
AND name IN ('VM_DISK_IO_READ', 'VM_DISK_IO_WRITE'); AND name IN ('VM_DISK_IO_READ', 'VM_DISK_IO_WRITE');
-- PR #7236 - [Usage] Create network billing
CREATE TABLE IF NOT EXISTS `cloud_usage`.`usage_networks` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`network_offering_id` bigint(20) unsigned NOT NULL,
`zone_id` bigint(20) unsigned NOT NULL,
`network_id` bigint(20) unsigned NOT NULL,
`account_id` bigint(20) unsigned NOT NULL,
`domain_id` bigint(20) unsigned NOT NULL,
`state` varchar(100) DEFAULT NULL,
`removed` datetime DEFAULT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8;
-- allow for bigger urls -- allow for bigger urls
ALTER TABLE `cloud`.`vm_template` MODIFY COLUMN `url` VARCHAR(1024) DEFAULT NULL COMMENT 'the url where the template exists externally'; ALTER TABLE `cloud`.`vm_template` MODIFY COLUMN `url` VARCHAR(1024) DEFAULT NULL COMMENT 'the url where the template exists externally';

View File

@ -26,6 +26,7 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.cloud.host.HostTagVO; import com.cloud.host.HostTagVO;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.VpcVO;
import javax.inject.Inject; import javax.inject.Inject;
@ -37,6 +38,7 @@ import org.apache.cloudstack.backup.BackupOfferingVO;
import org.apache.cloudstack.backup.dao.BackupOfferingDao; import org.apache.cloudstack.backup.dao.BackupOfferingDao;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.quota.constant.QuotaTypes; import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.dao.NetworkDao;
import org.apache.cloudstack.quota.dao.VmTemplateDao; import org.apache.cloudstack.quota.dao.VmTemplateDao;
import org.apache.cloudstack.quota.dao.VpcDao; import org.apache.cloudstack.quota.dao.VpcDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
@ -173,6 +175,9 @@ public class PresetVariableHelper {
@Inject @Inject
BackupOfferingDao backupOfferingDao; BackupOfferingDao backupOfferingDao;
@Inject
NetworkDao networkDao;
@Inject @Inject
VpcDao vpcDao; VpcDao vpcDao;
@ -280,6 +285,7 @@ public class PresetVariableHelper {
loadPresetVariableValueForNetworkOffering(usageRecord, value); loadPresetVariableValueForNetworkOffering(usageRecord, value);
loadPresetVariableValueForVmSnapshot(usageRecord, value); loadPresetVariableValueForVmSnapshot(usageRecord, value);
loadPresetVariableValueForBackup(usageRecord, value); loadPresetVariableValueForBackup(usageRecord, value);
loadPresetVariableValueForNetwork(usageRecord, value);
loadPresetVariableValueForVpc(usageRecord, value); loadPresetVariableValueForVpc(usageRecord, value);
return value; return value;
@ -697,6 +703,22 @@ public class PresetVariableHelper {
return backupOffering; return backupOffering;
} }
protected void loadPresetVariableValueForNetwork(UsageVO usageRecord, Value value) {
int usageType = usageRecord.getUsageType();
if (usageType != QuotaTypes.NETWORK) {
logNotLoadingMessageInTrace("Network", usageType);
return;
}
Long networkId = usageRecord.getUsageId();
NetworkVO network = networkDao.findByIdIncludingRemoved(networkId);
validateIfObjectIsNull(network, networkId, "Network");
value.setId(network.getUuid());
value.setName(network.getName());
value.setState(usageRecord.getState());
}
protected void loadPresetVariableValueForVpc(UsageVO usageRecord, Value value) { protected void loadPresetVariableValueForVpc(UsageVO usageRecord, Value value) {
int usageType = usageRecord.getUsageType(); int usageType = usageRecord.getUsageType();
if (usageType != QuotaTypes.VPC) { if (usageType != QuotaTypes.VPC) {

View File

@ -43,6 +43,7 @@ public class Value extends GenericPresetVariable {
private BackupOffering backupOffering; private BackupOffering backupOffering;
private String hypervisorType; private String hypervisorType;
private String volumeFormat; private String volumeFormat;
private String state;
public Host getHost() { public Host getHost() {
return host; return host;
@ -205,4 +206,13 @@ public class Value extends GenericPresetVariable {
public String getVolumeFormat() { public String getVolumeFormat() {
return volumeFormat; return volumeFormat;
} }
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
fieldNamesToIncludeInToString.add("state");
}
} }

View File

@ -56,6 +56,7 @@ public class QuotaTypes extends UsageTypes {
quotaTypeList.put(VM_SNAPSHOT_ON_PRIMARY, new QuotaTypes(VM_SNAPSHOT_ON_PRIMARY, "VM_SNAPSHOT_ON_PRIMARY", UsageUnitTypes.GB_MONTH.toString(), "VM Snapshot primary storage usage")); quotaTypeList.put(VM_SNAPSHOT_ON_PRIMARY, new QuotaTypes(VM_SNAPSHOT_ON_PRIMARY, "VM_SNAPSHOT_ON_PRIMARY", UsageUnitTypes.GB_MONTH.toString(), "VM Snapshot primary storage usage"));
quotaTypeList.put(BACKUP, new QuotaTypes(BACKUP, "BACKUP", UsageUnitTypes.GB_MONTH.toString(), "Backup storage usage")); quotaTypeList.put(BACKUP, new QuotaTypes(BACKUP, "BACKUP", UsageUnitTypes.GB_MONTH.toString(), "Backup storage usage"));
quotaTypeList.put(BUCKET, new QuotaTypes(BUCKET, "BUCKET", UsageUnitTypes.GB_MONTH.toString(), "Object Store bucket usage")); quotaTypeList.put(BUCKET, new QuotaTypes(BUCKET, "BUCKET", UsageUnitTypes.GB_MONTH.toString(), "Object Store bucket usage"));
quotaTypeList.put(NETWORK, new QuotaTypes(NETWORK, "NETWORK", UsageUnitTypes.COMPUTE_MONTH.toString(), "Network usage"));
quotaTypeList.put(VPC, new QuotaTypes(VPC, "VPC", UsageUnitTypes.COMPUTE_MONTH.toString(), "VPC usage")); quotaTypeList.put(VPC, new QuotaTypes(VPC, "VPC", UsageUnitTypes.COMPUTE_MONTH.toString(), "VPC usage"));
quotaTypeMap = Collections.unmodifiableMap(quotaTypeList); quotaTypeMap = Collections.unmodifiableMap(quotaTypeList);
} }

View File

@ -0,0 +1,23 @@
// 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 org.apache.cloudstack.quota.dao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.utils.db.GenericDao;
public interface NetworkDao extends GenericDao<NetworkVO, Long> {
}

View File

@ -0,0 +1,27 @@
// 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 org.apache.cloudstack.quota.dao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.utils.db.GenericDaoBase;
/**
* This class was created to specifically use in {@link org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableHelper}.<br/><br/>
* It was not possible to inject {@link com.cloud.network.dao.NetworkDao} due to its complex injection hierarchy.
*/
public class NetworkDaoImpl extends GenericDaoBase<NetworkVO, Long> implements NetworkDao {
}

View File

@ -471,6 +471,7 @@ public class PresetVariableHelperTest {
Mockito.doNothing().when(presetVariableHelperSpy).loadPresetVariableValueForNetworkOffering(Mockito.any(UsageVO.class), Mockito.any(Value.class)); Mockito.doNothing().when(presetVariableHelperSpy).loadPresetVariableValueForNetworkOffering(Mockito.any(UsageVO.class), Mockito.any(Value.class));
Mockito.doNothing().when(presetVariableHelperSpy).loadPresetVariableValueForVmSnapshot(Mockito.any(UsageVO.class), Mockito.any(Value.class)); Mockito.doNothing().when(presetVariableHelperSpy).loadPresetVariableValueForVmSnapshot(Mockito.any(UsageVO.class), Mockito.any(Value.class));
Mockito.doNothing().when(presetVariableHelperSpy).loadPresetVariableValueForBackup(Mockito.any(UsageVO.class), Mockito.any(Value.class)); Mockito.doNothing().when(presetVariableHelperSpy).loadPresetVariableValueForBackup(Mockito.any(UsageVO.class), Mockito.any(Value.class));
Mockito.doNothing().when(presetVariableHelperSpy).loadPresetVariableValueForNetwork(Mockito.any(UsageVO.class), Mockito.any(Value.class));
Mockito.doNothing().when(presetVariableHelperSpy).loadPresetVariableValueForVpc(Mockito.any(UsageVO.class), Mockito.any(Value.class)); Mockito.doNothing().when(presetVariableHelperSpy).loadPresetVariableValueForVpc(Mockito.any(UsageVO.class), Mockito.any(Value.class));
Value result = presetVariableHelperSpy.getPresetVariableValue(usageVoMock); Value result = presetVariableHelperSpy.getPresetVariableValue(usageVoMock);

View File

@ -150,4 +150,12 @@ public class ValueTest {
variable.setVolumeFormat(null); variable.setVolumeFormat(null);
Assert.assertTrue(variable.fieldNamesToIncludeInToString.contains("volumeFormat")); Assert.assertTrue(variable.fieldNamesToIncludeInToString.contains("volumeFormat"));
} }
@Test
public void setStateTestAddFieldStateToCollection() {
Value variable = new Value();
variable.setState(null);
Assert.assertTrue(variable.fieldNamesToIncludeInToString.contains("state"));
}
} }

View File

@ -27,12 +27,6 @@
<version>4.20.0.0-SNAPSHOT</version> <version>4.20.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<repositories>
<repository>
<id>juniper-contrail</id>
<url>https://juniper.github.io/contrail-maven/snapshots</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.apache.cloudstack</groupId> <groupId>org.apache.cloudstack</groupId>

View File

@ -100,7 +100,6 @@
<module>network-elements/bigswitch</module> <module>network-elements/bigswitch</module>
<module>network-elements/dns-notifier</module> <module>network-elements/dns-notifier</module>
<module>network-elements/juniper-contrail</module>
<module>network-elements/elastic-loadbalancer</module> <module>network-elements/elastic-loadbalancer</module>
<module>network-elements/globodns</module> <module>network-elements/globodns</module>
<module>network-elements/internal-loadbalancer</module> <module>network-elements/internal-loadbalancer</module>
@ -231,6 +230,7 @@
<module>hypervisors/vmware</module> <module>hypervisors/vmware</module>
<module>network-elements/cisco-vnmc</module> <module>network-elements/cisco-vnmc</module>
<module>network-elements/nsx</module> <module>network-elements/nsx</module>
<module>network-elements/juniper-contrail</module>
</modules> </modules>
</profile> </profile>
<profile> <profile>

View File

@ -2061,7 +2061,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
if (implementedNetwork == null || implementedNetwork.first() == null) { if (implementedNetwork == null || implementedNetwork.first() == null) {
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) { } catch (ResourceUnavailableException ex) {
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"); CloudRuntimeException e = new CloudRuntimeException("Failed to implement persistent guest network");
@ -3458,7 +3463,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
} }
} }
} }
return getNetwork(network.getId()); Network updatedNetwork = getNetwork(network.getId());
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_UPDATE, updatedNetwork.getAccountId(), updatedNetwork.getDataCenterId(), updatedNetwork.getId(),
updatedNetwork.getName(), updatedNetwork.getNetworkOfferingId(), null, updatedNetwork.getState().name(), Network.class.getName(), updatedNetwork.getUuid(), true);
return updatedNetwork;
} }
protected Pair<Integer, Integer> validateMtuOnUpdate(NetworkVO network, Long zoneId, Integer publicMtu, Integer privateMtu) { protected Pair<Integer, Integer> validateMtuOnUpdate(NetworkVO network, Long zoneId, Integer publicMtu, Integer privateMtu) {

View File

@ -41,6 +41,7 @@ import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import java.util.ArrayList; import java.util.ArrayList;
@ -49,7 +50,6 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class NetworkModelImplTest { public class NetworkModelImplTest {

View File

@ -1035,7 +1035,7 @@ class TestSecuredVmMigration(cloudstackTestCase):
time.sleep(interval) time.sleep(interval)
restarted_host = Host.list( restarted_host = Host.list(
cls.apiclient, cls.apiclient,
hostid=host.id, id=host.id,
type='Routing' type='Routing'
)[0] )[0]
if restarted_host.state == "Up": if restarted_host.state == "Up":
@ -1100,7 +1100,7 @@ class TestSecuredVmMigration(cloudstackTestCase):
time.sleep(interval) time.sleep(interval)
host = Host.list( host = Host.list(
self.apiclient, self.apiclient,
hostid=hostId, id=hostId,
type='Routing' type='Routing'
)[0] )[0]
if host.state != state: if host.state != state:
@ -1160,7 +1160,7 @@ class TestSecuredVmMigration(cloudstackTestCase):
host = Host.list( host = Host.list(
self.apiclient, self.apiclient,
zoneid=self.zone.id, zoneid=self.zone.id,
hostid=host.id, id=host.id,
type='Routing' type='Routing'
)[0] )[0]
if host.details.secured != secured: if host.details.secured != secured:

View File

@ -32,6 +32,9 @@ import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.cloud.network.Network;
import com.cloud.usage.dao.UsageNetworksDao;
import com.cloud.usage.parser.NetworksUsageParser;
import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.Vpc;
import com.cloud.usage.dao.UsageVpcDao; import com.cloud.usage.dao.UsageVpcDao;
import com.cloud.usage.parser.VpcUsageParser; import com.cloud.usage.parser.VpcUsageParser;
@ -168,6 +171,8 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
private QuotaAlertManager _alertManager; private QuotaAlertManager _alertManager;
@Inject @Inject
private QuotaStatement _quotaStatement; private QuotaStatement _quotaStatement;
@Inject
private UsageNetworksDao usageNetworksDao;
@Inject @Inject
private BucketStatisticsDao _bucketStatisticsDao; private BucketStatisticsDao _bucketStatisticsDao;
@ -1043,6 +1048,11 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
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) {
logger.debug("Networks usage not parsed for account [{}}].", account);
}
parsed = VpcUsageParser.parse(account, currentStartDate, currentEndDate); parsed = VpcUsageParser.parse(account, currentStartDate, currentEndDate);
if (!parsed) { if (!parsed) {
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));
@ -1081,6 +1091,8 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
createVmSnapshotOnPrimaryEvent(event); createVmSnapshotOnPrimaryEvent(event);
} else if (isBackupEvent(eventType)) { } else if (isBackupEvent(eventType)) {
createBackupEvent(event); createBackupEvent(event);
} else if (EventTypes.isNetworkEvent(eventType)) {
handleNetworkEvent(event);
} else if (EventTypes.isVpcEvent(eventType)) { } else if (EventTypes.isVpcEvent(eventType)) {
handleVpcEvent(event); handleVpcEvent(event);
} }
@ -2131,6 +2143,21 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
} }
} }
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 {
logger.error("Unknown event type [{}] in Networks event parser. Skipping it.", event.getType());
}
}
private void handleVpcEvent(UsageEventVO event) { private void handleVpcEvent(UsageEventVO event) {
Account account = _accountDao.findByIdIncludingRemoved(event.getAccountId()); Account account = _accountDao.findByIdIncludingRemoved(event.getAccountId());
long domainId = account.getDomainId(); long domainId = account.getDomainId();

View File

@ -0,0 +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.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 = 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;
}
}