diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index c4833d3433a..d385fa9ed07 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.config.Configuration; import org.apache.cloudstack.ha.HAConfig; import org.apache.cloudstack.storage.object.Bucket; import org.apache.cloudstack.storage.object.ObjectStore; +import org.apache.cloudstack.quota.QuotaTariff; import org.apache.cloudstack.usage.Usage; import org.apache.cloudstack.vm.schedule.VMSchedule; @@ -729,6 +730,11 @@ public class EventTypes { public static final String EVENT_BUCKET_DELETE = "BUCKET.DELETE"; public static final String EVENT_BUCKET_UPDATE = "BUCKET.UPDATE"; + // Quota + public static final String EVENT_QUOTA_TARIFF_CREATE = "QUOTA.TARIFF.CREATE"; + public static final String EVENT_QUOTA_TARIFF_DELETE = "QUOTA.TARIFF.DELETE"; + public static final String EVENT_QUOTA_TARIFF_UPDATE = "QUOTA.TARIFF.UPDATE"; + static { // TODO: need a way to force author adding event types to declare the entity details as well, with out braking @@ -1178,6 +1184,11 @@ public class EventTypes { entityEventDetails.put(EVENT_BUCKET_CREATE, Bucket.class); entityEventDetails.put(EVENT_BUCKET_UPDATE, Bucket.class); entityEventDetails.put(EVENT_BUCKET_DELETE, Bucket.class); + + // Quota + entityEventDetails.put(EVENT_QUOTA_TARIFF_CREATE, QuotaTariff.class); + entityEventDetails.put(EVENT_QUOTA_TARIFF_DELETE, QuotaTariff.class); + entityEventDetails.put(EVENT_QUOTA_TARIFF_UPDATE, QuotaTariff.class); } public static String getEntityForEvent(String eventName) { diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java b/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java index affceb4e3f9..aafc039b36b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java @@ -80,7 +80,8 @@ public enum ApiCommandResourceType { VpnCustomerGateway(com.cloud.network.Site2SiteCustomerGateway.class), ManagementServer(org.apache.cloudstack.management.ManagementServerHost.class), ObjectStore(org.apache.cloudstack.storage.object.ObjectStore.class), - Bucket(org.apache.cloudstack.storage.object.Bucket.class); + Bucket(org.apache.cloudstack.storage.object.Bucket.class), + QuotaTariff(org.apache.cloudstack.quota.QuotaTariff.class); private final Class clazz; diff --git a/api/src/main/java/org/apache/cloudstack/quota/QuotaTariff.java b/api/src/main/java/org/apache/cloudstack/quota/QuotaTariff.java new file mode 100644 index 00000000000..7de66a168f9 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/quota/QuotaTariff.java @@ -0,0 +1,25 @@ +// 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 +// 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; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface QuotaTariff extends InternalIdentity, Identity { + +} diff --git a/engine/schema/src/main/java/com/cloud/network/security/dao/SecurityGroupVMMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/security/dao/SecurityGroupVMMapDaoImpl.java index a2ec95ccb67..803955a562c 100644 --- a/engine/schema/src/main/java/com/cloud/network/security/dao/SecurityGroupVMMapDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/security/dao/SecurityGroupVMMapDaoImpl.java @@ -131,7 +131,7 @@ public class SecurityGroupVMMapDaoImpl extends GenericDaoBase sc = ListBySecurityGroupAndStates.create(); sc.setParameters("securityGroupId", securityGroupId); sc.setParameters("states", (Object[])vmStates); - return listBy(sc, null, true); + return listBy(sc, null); } @Override diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41900to41910.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41900to41910.java new file mode 100644 index 00000000000..6085faba634 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41900to41910.java @@ -0,0 +1,66 @@ +// 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.upgrade.dao; + +import com.cloud.utils.exception.CloudRuntimeException; + +import java.io.InputStream; +import java.sql.Connection; + +public class Upgrade41900to41910 implements DbUpgrade { + + @Override + public String[] getUpgradableVersionRange() { + return new String[] {"4.19.0.0", "4.19.1.0"}; + } + + @Override + public String getUpgradedVersion() { + return "4.19.1.0"; + } + + @Override + public boolean supportsRollingUpgrade() { + return false; + } + + @Override + public InputStream[] getPrepareScripts() { + final String scriptFile = "META-INF/db/schema-41900to41910.sql"; + final InputStream script = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFile); + if (script == null) { + throw new CloudRuntimeException("Unable to find " + scriptFile); + } + + return new InputStream[] {script}; + } + + @Override + public void performDataMigration(Connection conn) { + } + + @Override + public InputStream[] getCleanupScripts() { + final String scriptFile = "META-INF/db/schema-41900to41910-cleanup.sql"; + final InputStream script = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFile); + if (script == null) { + throw new CloudRuntimeException("Unable to find " + scriptFile); + } + + return new InputStream[] {script}; + } +} diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41900to41910-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-41900to41910-cleanup.sql new file mode 100644 index 00000000000..b580d42686f --- /dev/null +++ b/engine/schema/src/main/resources/META-INF/db/schema-41900to41910-cleanup.sql @@ -0,0 +1,20 @@ +-- 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. + +--; +-- Schema upgrade cleanup from 4.19.0.0 to 4.19.1.0 +--; diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41900to41910.sql b/engine/schema/src/main/resources/META-INF/db/schema-41900to41910.sql new file mode 100644 index 00000000000..e704d61d70c --- /dev/null +++ b/engine/schema/src/main/resources/META-INF/db/schema-41900to41910.sql @@ -0,0 +1,32 @@ +-- 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. + +--; +-- Schema upgrade from 4.19.0.0 to 4.19.1.0 +--; + +-- Updates the populated Quota tariff's types VM_DISK_BYTES_READ, VM_DISK_BYTES_WRITE, VM_DISK_IO_READ and VM_DISK_IO_WRITE to the correct unit. + +UPDATE cloud_usage.quota_tariff +SET usage_unit = 'Bytes', updated_on = NOW() +WHERE effective_on = '2010-05-04 00:00:00' +AND name IN ('VM_DISK_BYTES_READ', 'VM_DISK_BYTES_WRITE'); + +UPDATE cloud_usage.quota_tariff +SET usage_unit = 'IOPS', updated_on = NOW() +WHERE effective_on = '2010-05-04 00:00:00' +AND name IN ('VM_DISK_IO_READ', 'VM_DISK_IO_WRITE'); diff --git a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java index fdb48e31f55..d510cb93d40 100644 --- a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java @@ -1502,9 +1502,9 @@ public abstract class GenericDaoBase extends Compone } else { _idField.set(entity, id); } - } else { - id = (ID)_idField.get(entity); } + + id = (ID)_idField.get(entity); } } catch (final IllegalAccessException e) { throw new CloudRuntimeException("Yikes! ", e); diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java index 2bd3409953a..8cbec8c8598 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java @@ -229,4 +229,14 @@ public class QuotaTariffDaoImpl extends GenericDaoBase impl return quotaTariffs.get(0); } + + @Override + public QuotaTariffVO findByIdIncludingRemoved(Long id) { + return Transaction.execute(TransactionLegacy.USAGE_DB, (TransactionCallback) status -> super.findByIdIncludingRemoved(id)); + } + + @Override + public QuotaTariffVO findByUuidIncludingRemoved(String uuid) { + return Transaction.execute(TransactionLegacy.USAGE_DB, (TransactionCallback) status -> super.findByUuidIncludingRemoved(uuid)); + } } diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/vo/QuotaTariffVO.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/vo/QuotaTariffVO.java index 5b07cadb94a..40a751c6200 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/vo/QuotaTariffVO.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/vo/QuotaTariffVO.java @@ -17,7 +17,7 @@ package org.apache.cloudstack.quota.vo; import com.cloud.utils.DateUtil; -import org.apache.cloudstack.api.InternalIdentity; +import org.apache.cloudstack.quota.QuotaTariff; import org.apache.cloudstack.quota.constant.QuotaTypes; import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; @@ -40,7 +40,7 @@ import java.util.UUID; @Entity @Table(name = "quota_tariff") -public class QuotaTariffVO implements InternalIdentity { +public class QuotaTariffVO implements QuotaTariff { private static final long serialVersionUID = -7117933766387653203L; @Id @@ -243,6 +243,7 @@ public class QuotaTariffVO implements InternalIdentity { return description; } + @Override public String getUuid() { return uuid; } diff --git a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffCreateCmd.java b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffCreateCmd.java index 8e5de241064..ef9ffc23d13 100644 --- a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffCreateCmd.java +++ b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffCreateCmd.java @@ -20,6 +20,7 @@ import com.cloud.user.Account; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -27,6 +28,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.QuotaResponseBuilder; import org.apache.cloudstack.api.response.QuotaTariffResponse; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.quota.vo.QuotaTariffVO; import javax.inject.Inject; @@ -68,6 +70,7 @@ public class QuotaTariffCreateCmd extends BaseCmd { @Override public void execute() { + CallContext.current().setEventDetails(String.format("Tariff: %s, description: %s, value: %s", getName(), getDescription(), getValue())); QuotaTariffVO result = responseBuilder.createQuotaTariff(this); if (result == null) { @@ -132,4 +135,8 @@ public class QuotaTariffCreateCmd extends BaseCmd { this.endDate = endDate; } + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.QuotaTariff; + } } diff --git a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffDeleteCmd.java b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffDeleteCmd.java index 699854ebac3..7810760c56e 100644 --- a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffDeleteCmd.java +++ b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffDeleteCmd.java @@ -21,12 +21,14 @@ import com.cloud.user.Account; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.response.QuotaResponseBuilder; import org.apache.cloudstack.api.response.QuotaTariffResponse; import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; import javax.inject.Inject; @@ -47,6 +49,7 @@ public class QuotaTariffDeleteCmd extends BaseCmd { @Override public void execute() { + CallContext.current().setEventDetails(String.format("Tariff id: %s", getId())); boolean result = responseBuilder.deleteQuotaTariff(getId()); SuccessResponse response = new SuccessResponse(getCommandName()); response.setSuccess(result); @@ -58,4 +61,8 @@ public class QuotaTariffDeleteCmd extends BaseCmd { return Account.ACCOUNT_ID_SYSTEM; } + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.QuotaTariff; + } } diff --git a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java index d5c5ca198b8..175500604d6 100644 --- a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java +++ b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java @@ -20,6 +20,7 @@ import com.cloud.user.Account; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -27,6 +28,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.QuotaResponseBuilder; import org.apache.cloudstack.api.response.QuotaTariffResponse; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.quota.vo.QuotaTariffVO; import javax.inject.Inject; @@ -109,6 +111,7 @@ public class QuotaTariffUpdateCmd extends BaseCmd { @Override public void execute() { + CallContext.current().setEventDetails(String.format("Tariff: %s, description: %s, value: %s", getName(), getDescription(), getValue())); final QuotaTariffVO result = _responseBuilder.updateQuotaTariffPlan(this); if (result == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update quota tariff plan"); @@ -123,4 +126,8 @@ public class QuotaTariffUpdateCmd extends BaseCmd { return Account.ACCOUNT_ID_SYSTEM; } + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.QuotaTariff; + } } diff --git a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java index d7f2832831a..d4996887a40 100644 --- a/plugins/database/quota/src/main/java/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java +++ b/plugins/database/quota/src/main/java/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java @@ -44,6 +44,7 @@ import org.apache.cloudstack.api.command.QuotaStatementCmd; import org.apache.cloudstack.api.command.QuotaTariffCreateCmd; import org.apache.cloudstack.api.command.QuotaTariffListCmd; import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.quota.QuotaManager; import org.apache.cloudstack.quota.QuotaManagerImpl; import org.apache.cloudstack.quota.QuotaService; @@ -78,6 +79,8 @@ import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; @Component public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { @@ -383,6 +386,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { } @Override + @ActionEvent(eventType = EventTypes.EVENT_QUOTA_TARIFF_UPDATE, eventDescription = "updating Quota Tariff") public QuotaTariffVO updateQuotaTariffPlan(QuotaTariffUpdateCmd cmd) { String name = cmd.getName(); Double value = cmd.getValue(); @@ -406,6 +410,9 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { QuotaTariffVO newQuotaTariff = persistNewQuotaTariff(currentQuotaTariff, name, 0, currentQuotaTariffStartDate, cmd.getEntityOwnerId(), endDate, value, description, activationRule); _quotaTariffDao.updateQuotaTariff(currentQuotaTariff); + + CallContext.current().setEventResourceId(newQuotaTariff.getId()); + return newQuotaTariff; } @@ -625,6 +632,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { } @Override + @ActionEvent(eventType = EventTypes.EVENT_QUOTA_TARIFF_CREATE, eventDescription = "creating Quota Tariff") public QuotaTariffVO createQuotaTariff(QuotaTariffCreateCmd cmd) { String name = cmd.getName(); int usageType = cmd.getUsageType(); @@ -647,9 +655,14 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { "Please, inform a date in the future or do not pass the parameter to use the current date and time.", startDate)); } - return persistNewQuotaTariff(null, name, usageType, startDate, cmd.getEntityOwnerId(), endDate, value, description, activationRule); + QuotaTariffVO newQuotaTariff = persistNewQuotaTariff(null, name, usageType, startDate, cmd.getEntityOwnerId(), endDate, value, description, activationRule); + + CallContext.current().setEventResourceId(newQuotaTariff.getId()); + + return newQuotaTariff; } + @ActionEvent(eventType = EventTypes.EVENT_QUOTA_TARIFF_DELETE, eventDescription = "removing Quota Tariff") public boolean deleteQuotaTariff(String quotaTariffUuid) { QuotaTariffVO quotaTariff = _quotaTariffDao.findByUuid(quotaTariffUuid); @@ -658,6 +671,9 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { } quotaTariff.setRemoved(_quotaService.computeAdjustedTime(new Date())); + + CallContext.current().setEventResourceId(quotaTariff.getId()); + return _quotaTariffDao.updateQuotaTariff(quotaTariff); } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index ad217f6052d..5465e289a2c 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -420,6 +420,9 @@ public class LibvirtDomainXMLParser { } private static String getTagValue(String tag, Element eElement) { + if (eElement == null) { + return null; + } NodeList tagNodeList = eElement.getElementsByTagName(tag); if (tagNodeList == null || tagNodeList.getLength() == 0) { return null; @@ -427,14 +430,20 @@ public class LibvirtDomainXMLParser { NodeList nlList = tagNodeList.item(0).getChildNodes(); + if (nlList == null || nlList.getLength() == 0) { + return null; + } Node nValue = nlList.item(0); return nValue.getNodeValue(); } private static String getAttrValue(String tag, String attr, Element eElement) { + if (eElement == null) { + return null; + } NodeList tagNode = eElement.getElementsByTagName(tag); - if (tagNode.getLength() == 0) { + if (tag == null || tagNode.getLength() == 0) { return null; } Element node = (Element)tagNode.item(0); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java index 53a745134cf..3813cb39f3c 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java @@ -259,4 +259,126 @@ public class LibvirtDomainXMLParserTest extends TestCase { assertEquals(WatchDogDef.WatchDogModel.I6300ESB, watchDogs.get(0).getModel()); assertEquals(WatchDogDef.WatchDogAction.RESET, watchDogs.get(0).getAction()); } + + @Test + public void testDomainXMLParserWithoutModelName() { + String xml = "\n" + + " testkiran\n" + + " aafaaabc-8657-4efc-9c52-3422d4e04088\n" + + " 2097152\n" + + " 2097152\n" + + " 2\n" + + " \n" + + " hvm\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " destroy\n" + + " restart\n" + + " destroy\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " /usr/libexec/qemu-kvm\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + "