From baa861006127daf0da7d762a2913cd6b9c458588 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Tue, 12 Apr 2016 10:57:55 -0700 Subject: [PATCH 1/2] CLOUDSTACK-9351: Add ids parameter to resource listing API calls --- .../apache/cloudstack/api/ApiConstants.java | 1 + .../user/snapshot/ListSnapshotsCmd.java | 7 ++ .../user/template/ListTemplatesCmd.java | 8 ++ .../user/vmsnapshot/ListVMSnapshotCmd.java | 7 ++ .../command/user/volume/ListVolumesCmd.java | 8 ++ .../query/MutualExclusiveIdsManagerBase.java | 62 +++++++++++ .../com/cloud/api/query/QueryManagerImpl.java | 21 +++- .../storage/snapshot/SnapshotManagerImpl.java | 9 +- .../vm/snapshot/VMSnapshotManagerImpl.java | 9 +- .../MutualExclusiveIdsManagerBaseTest.java | 102 ++++++++++++++++++ 10 files changed, 225 insertions(+), 9 deletions(-) create mode 100755 server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java create mode 100755 server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index ef4ff9a0fe9f..6f3152b75a70 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -551,6 +551,7 @@ public class ApiConstants { public static final String VM_SNAPSHOT_DESCRIPTION = "description"; public static final String VM_SNAPSHOT_DISPLAYNAME = "name"; public static final String VM_SNAPSHOT_ID = "vmsnapshotid"; + public static final String VM_SNAPSHOT_IDS = "vmsnapshotids"; public static final String VM_SNAPSHOT_DISK_IDS = "vmsnapshotdiskids"; public static final String VM_SNAPSHOT_MEMORY = "snapshotmemory"; public static final String VM_SNAPSHOT_QUIESCEVM = "quiescevm"; diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java index 47a6876d09fa..97bb187dd525 100644 --- a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java @@ -48,6 +48,9 @@ public class ListSnapshotsCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = SnapshotResponse.class, description = "lists snapshot by snapshot ID") private Long id; + @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=SnapshotResponse.class, description="the IDs of the snapshots, mutually exclusive with id", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.INTERVAL_TYPE, type = CommandType.STRING, description = "valid values are HOURLY, DAILY, WEEKLY, and MONTHLY.") private String intervalType; @@ -120,4 +123,8 @@ public void execute() { setResponseObject(response); } + + public List getIds() { + return ids; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java index 7a2a15834ac9..772ca2749e7d 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java @@ -18,6 +18,7 @@ import org.apache.log4j.Logger; +import java.util.List; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandJobType; import org.apache.cloudstack.api.ApiConstants; @@ -50,6 +51,9 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "the template ID") private Long id; + @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=TemplateResponse.class, description="the IDs of the templates, mutually exclusive with id", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the template name") private String templateName; @@ -132,4 +136,8 @@ public void execute() { response.setResponseName(getCommandName()); setResponseObject(response); } + + public List getIds() { + return ids; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java index c9bc2430d265..ad5126e4680d 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java @@ -39,6 +39,9 @@ public class ListVMSnapshotCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.VM_SNAPSHOT_ID, type = CommandType.UUID, entityType = VMSnapshotResponse.class, description = "The ID of the VM snapshot") private Long id; + @Parameter(name=ApiConstants.VM_SNAPSHOT_IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=VMSnapshotResponse.class, description="the IDs of the vm snapshots, mutually exclusive with vmsnapshotid", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.STATE, type = CommandType.STRING, description = "state of the virtual machine snapshot") private String state; @@ -84,4 +87,8 @@ public String getCommandName() { return s_name; } + public List getIds() { + return ids; + } + } diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java index cc218f71972e..059def7c1676 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java @@ -18,6 +18,7 @@ import org.apache.log4j.Logger; +import java.util.List; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandJobType; @@ -53,6 +54,9 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VolumeResponse.class, description = "the ID of the disk volume") private Long id; + @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=VolumeResponse.class, description="the IDs of the volumes, mutually exclusive with id", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name of the disk volume") private String volumeName; @@ -153,4 +157,8 @@ public void execute() { response.setResponseName(getCommandName()); setResponseObject(response); } + + public List getIds() { + return ids; + } } diff --git a/server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java b/server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java new file mode 100755 index 000000000000..c7b32225b5cc --- /dev/null +++ b/server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java @@ -0,0 +1,62 @@ +// +// 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.api.query; + +import java.util.ArrayList; +import java.util.List; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.SearchCriteria; + +public class MutualExclusiveIdsManagerBase extends ManagerBase { + + /*** + * Include ids list in query criteria if ids is not null + * @param sc search criteria, class type SearchCriteria + * @param ids ids list, class type List + */ + protected void setIdsListToSearchCriteria(SearchCriteria sc, List ids){ + if (ids != null && !ids.isEmpty()) { + sc.setParameters("idIN", ids.toArray()); + } + } + + /*** + * Mutually exclusive parameters id and ids for API calls.
+ * Retrieve a list of ids or a list containing id depending on which of them is not null, or null if both are null + * @param id entity id, class type T + * @param ids entities ids, class type List + * @return if id is not null return a list containing id else return ids, if both parameters are null -> return null + * @throws InvalidParameterValueException - if id and ids are both not null + */ + protected List getIdsListFromCmd(T id, List ids){ + List idsList = null; + if (id != null) { + if (ids != null && !ids.isEmpty()) { + throw new InvalidParameterValueException("Specify either id or ids but not both parameters"); + } + idsList = new ArrayList(); + idsList.add(id); + } else { + idsList = ids; + } + return idsList; + } +} diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 94929577a399..781b1959adf3 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -205,7 +205,6 @@ import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; import com.cloud.utils.Ternary; -import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; @@ -222,7 +221,7 @@ import com.cloud.vm.dao.VMInstanceDao; @Component -public class QueryManagerImpl extends ManagerBase implements QueryService, Configurable { +public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements QueryService, Configurable { public static final Logger s_logger = Logger.getLogger(QueryManagerImpl.class); @@ -1731,6 +1730,8 @@ private Pair, Integer> searchForVolumesInternal(ListVolumesCm Long zoneId = cmd.getZoneId(); Long podId = cmd.getPodId(); + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + Ternary domainIdRecursiveListProject = new Ternary( cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, @@ -1754,6 +1755,7 @@ private Pair, Integer> searchForVolumesInternal(ListVolumesCm sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("volumeType", sb.entity().getVolumeType(), SearchCriteria.Op.LIKE); sb.and("instanceId", sb.entity().getVmId(), SearchCriteria.Op.EQ); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); @@ -1790,6 +1792,8 @@ private Pair, Integer> searchForVolumesInternal(ListVolumesCm sc.setParameters("display", display); } + setIdsListToSearchCriteria(sc, ids); + sc.setParameters("systemUse", 1); if (tags != null && !tags.isEmpty()) { @@ -3077,14 +3081,15 @@ private Pair, Integer> searchForTemplatesInternal(ListTempl return searchForTemplatesInternal(id, cmd.getTemplateName(), cmd.getKeyword(), templateFilter, false, null, cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType, showDomr, - cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl); + cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl, + cmd.getIds()); } private Pair, Integer> searchForTemplatesInternal(Long templateId, String name, String keyword, TemplateFilter templateFilter, boolean isIso, Boolean bootable, Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean showDomr, boolean onlyReady, List permittedAccounts, Account caller, ListProjectResourcesCriteria listProjectResourcesCriteria, - Map tags, boolean showRemovedTmpl) { + Map tags, boolean showRemovedTmpl, List ids) { // check if zone is configured, if not, just return empty list List hypers = null; @@ -3104,6 +3109,9 @@ private Pair, Integer> searchForTemplatesInternal(Long temp SearchBuilder sb = _templateJoinDao.createSearchBuilder(); sb.select(null, Func.DISTINCT, sb.entity().getTempZonePair()); // select distinct (templateId, zoneId) pair + if (ids != null && !ids.isEmpty()){ + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); + } SearchCriteria sc = sb.create(); // verify templateId parameter and specially handle it @@ -3149,6 +3157,8 @@ private Pair, Integer> searchForTemplatesInternal(Long temp // hypers = _resourceMgr.listAvailHypervisorInZone(null, null); // } + setIdsListToSearchCriteria(sc, ids); + // add criteria for project or not if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) { sc.addAnd("accountType", SearchCriteria.Op.NEQ, Account.ACCOUNT_TYPE_PROJECT); @@ -3386,7 +3396,8 @@ private Pair, Integer> searchForIsosInternal(ListIsosCmd cm return searchForTemplatesInternal(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(), cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType, true, - cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO); + cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO, + null); } @Override diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 65f51404182e..757ab6110cd4 100644 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -58,6 +58,7 @@ import com.cloud.agent.api.DeleteSnapshotsDirCommand; import com.cloud.alert.AlertManager; import com.cloud.api.commands.ListRecurringSnapshotScheduleCmd; +import com.cloud.api.query.MutualExclusiveIdsManagerBase; import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.ClusterVO; @@ -112,7 +113,6 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; -import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; @@ -129,7 +129,7 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component -public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, SnapshotApiService { +public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements SnapshotManager, SnapshotApiService { private static final Logger s_logger = Logger.getLogger(SnapshotManagerImpl.class); @Inject VMTemplateDao _templateDao; @@ -512,6 +512,8 @@ public Pair, Integer> listSnapshots(ListSnapshotsCmd cm } } + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + Ternary domainIdRecursiveListProject = new Ternary(cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); Long domainId = domainIdRecursiveListProject.first(); @@ -526,6 +528,7 @@ public Pair, Integer> listSnapshots(ListSnapshotsCmd cm sb.and("volumeId", sb.entity().getVolumeId(), SearchCriteria.Op.EQ); sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("snapshotTypeEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.IN); sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.NEQ); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); @@ -565,6 +568,8 @@ public Pair, Integer> listSnapshots(ListSnapshotsCmd cm sc.setParameters("dataCenterId", zoneId); } + setIdsListToSearchCriteria(sc, ids); + if (name != null) { sc.setParameters("name", "%" + name + "%"); } diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index c113e3c9203b..d8f459627b89 100644 --- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -46,6 +46,7 @@ import org.apache.cloudstack.jobs.JobInfo; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import com.cloud.api.query.MutualExclusiveIdsManagerBase; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; @@ -77,7 +78,6 @@ import com.cloud.utils.Predicate; import com.cloud.utils.ReflectionUse; import com.cloud.utils.Ternary; -import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.Filter; import com.cloud.utils.db.SearchBuilder; @@ -99,7 +99,7 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component -public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotManager, VMSnapshotService, VmWorkJobHandler { +public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements VMSnapshotManager, VMSnapshotService, VmWorkJobHandler { private static final Logger s_logger = Logger.getLogger(VMSnapshotManagerImpl.class); public static final String VM_WORK_JOB_HANDLER = VMSnapshotManagerImpl.class.getSimpleName(); @@ -176,6 +176,8 @@ public List listVMSnapshots(ListVMSnapshotCmd cmd) { String name = cmd.getVmSnapshotName(); String accountName = cmd.getAccountName(); + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + Ternary domainIdRecursiveListProject = new Ternary( cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, listAll, @@ -193,6 +195,7 @@ public List listVMSnapshots(ListVMSnapshotCmd cmd) { sb.and("status", sb.entity().getState(), SearchCriteria.Op.IN); sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("display_name", sb.entity().getDisplayName(), SearchCriteria.Op.EQ); sb.and("account_id", sb.entity().getAccountId(), SearchCriteria.Op.EQ); sb.done(); @@ -209,6 +212,8 @@ public List listVMSnapshots(ListVMSnapshotCmd cmd) { sc.setParameters("vm_id", vmId); } + setIdsListToSearchCriteria(sc, ids); + if (domainId != null) { sc.setParameters("domain_id", domainId); } diff --git a/server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java b/server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java new file mode 100755 index 000000000000..a4d92614b3f6 --- /dev/null +++ b/server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java @@ -0,0 +1,102 @@ +// +// 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.api.query; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.never; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.db.SearchCriteria; + +@RunWith(MockitoJUnitRunner.class) +public class MutualExclusiveIdsManagerBaseTest { + + @Mock + SearchCriteria sc; + + private static Long id1 = 1L; + private static Long id2 = 2L; + + private List idsList; + private List idsEmptyList; + private List expectedListId; + private List expectedListIds; + + private MutualExclusiveIdsManagerBase mgr = new MutualExclusiveIdsManagerBase(); + + @Before + public void setup() { + idsList = Arrays.asList(id1, id2); + idsEmptyList = Arrays.asList(); + expectedListId = Arrays.asList(id1); + expectedListIds = Arrays.asList(id1, id2); + } + + @Test + public void testSetIdsListToSearchCriteria(){ + mgr.setIdsListToSearchCriteria(sc, idsList); + Mockito.verify(sc).setParameters(Mockito.same("idIN"), Mockito.same(id1), Mockito.same(id2)); + } + + @Test + public void testSetIdsListToSearchCriteriaEmptyList(){ + mgr.setIdsListToSearchCriteria(sc, idsEmptyList); + Mockito.verify(sc, never()).setParameters(Mockito.anyString(), Mockito.any()); + } + + @Test + public void testGetIdsListId(){ + List result = mgr.getIdsListFromCmd(id1, idsEmptyList); + assertEquals(expectedListId, result); + } + + @Test + public void testGetIdsListProvideList(){ + List result = mgr.getIdsListFromCmd(null, idsList); + assertEquals(expectedListIds, result); + } + + @Test(expected=InvalidParameterValueException.class) + public void testGetIdsListBothNotNull(){ + mgr.getIdsListFromCmd(id1, idsList); + } + + @Test + public void testGetIdsListBothNull(){ + List result = mgr.getIdsListFromCmd(null, null); + assertNull(result); + } + + @Test + public void testGetIdsEmptyListIdNull(){ + List result = mgr.getIdsListFromCmd(null, idsEmptyList); + assertEquals(idsEmptyList, result); + } +} From b9d75c6ffaf382468b6a0359ee24bb2915615d9b Mon Sep 17 00:00:00 2001 From: nvazquez Date: Wed, 4 May 2016 16:00:44 -0300 Subject: [PATCH 2/2] CLOUDSTACK-9351: Add marvin test and add it to travis file --- .travis.yml | 2 +- .../smoke/test_list_ids_parameter.py | 295 ++++++++++++++++++ 2 files changed, 296 insertions(+), 1 deletion(-) create mode 100755 test/integration/smoke/test_list_ids_parameter.py diff --git a/.travis.yml b/.travis.yml index 1441fa4871f5..d160e487aa1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ env: - PATH=$HOME/.local/bin:$PATH matrix: - TESTS="smoke/test_affinity_groups smoke/test_affinity_groups_projects smoke/test_deploy_vgpu_enabled_vm smoke/test_deploy_vm_iso smoke/test_deploy_vm_root_resize smoke/test_deploy_vm_with_userdata smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_guest_vlan_range" - - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_loadbalance smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" + - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_list_ids_parameter smoke/test_loadbalance smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" - TESTS="smoke/test_over_provisioning smoke/test_password_server smoke/test_portable_publicip smoke/test_primary_storage smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_reset_vm_on_reboot smoke/test_resource_detail" - TESTS="smoke/test_router_dhcphosts smoke/test_routers smoke/test_routers_iptables_default_policy smoke/test_routers_network_ops smoke/test_scale_vm smoke/test_secondary_storage smoke/test_service_offerings smoke/test_snapshots smoke/test_ssvm smoke/test_templates" - TESTS="smoke/test_usage_events smoke/test_vm_life_cycle smoke/test_vm_snapshots smoke/test_volumes smoke/test_vpc_redundant smoke/test_vpc_router_nics smoke/test_vpc_vpn smoke/misc/test_deploy_vm smoke/misc/test_vm_ha smoke/misc/test_escalations_templates smoke/misc/test_vm_sync" diff --git a/test/integration/smoke/test_list_ids_parameter.py b/test/integration/smoke/test_list_ids_parameter.py new file mode 100755 index 000000000000..be9554bf415f --- /dev/null +++ b/test/integration/smoke/test_list_ids_parameter.py @@ -0,0 +1,295 @@ +# 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. +""" Tests for API listing methods using 'ids' parameter +""" +#Import Local Modules +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.lib.utils import (cleanup_resources, + validateList) +from marvin.lib.base import (Account, + Volume, + DiskOffering, + Template, + ServiceOffering, + Snapshot, + VmSnapshot, + VirtualMachine) +from marvin.lib.common import (get_domain, + get_zone, get_template) +from marvin.codes import FAILED, PASS +from nose.plugins.attrib import attr +#Import System modules +import time + +_multiprocess_shared_ = True +class TestListIdsParams(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + testClient = super(TestListIdsParams, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.services = testClient.getParsedTestDataConfig() + cls.hypervisor = testClient.getHypervisorInfo() + cls.domain = get_domain(cls.apiclient) + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + + cls.disk_offering = DiskOffering.create( + cls.apiclient, + cls.services["disk_offering"] + ) + + cls.account = Account.create( + cls.apiclient, + cls.services["account"], + domainid=cls.domain.id + ) + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.services["service_offerings"]["tiny"] + ) + + template = get_template( + cls.apiclient, + cls.zone.id, + cls.services["ostype"] + ) + if template == FAILED: + assert False, "get_template() failed to return template with description %s" % cls.services["ostype"] + + cls.services["template"]["ostypeid"] = template.ostypeid + cls.services["template_2"]["ostypeid"] = template.ostypeid + cls.services["ostypeid"] = template.ostypeid + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["mode"] = cls.zone.networktype + + #Create 3 VMs + cls.virtual_machine_1 = VirtualMachine.create( + cls.apiclient, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + cls.virtual_machine_2 = VirtualMachine.create( + cls.apiclient, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + cls.virtual_machine_3 = VirtualMachine.create( + cls.apiclient, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + + #Take 3 VM1 Snapshots + #PLEASE UNCOMMENT ONCE VM SNAPSHOT DELAY BUG AFTER VM CREATION IS FIXED + """cls.vmsnapshot_1 = VmSnapshot.create( + cls.apiclient, + cls.virtual_machine_1.id + ) + cls.vmsnapshot_2 = VmSnapshot.create( + cls.apiclient, + cls.virtual_machine_1.id + ) + cls.vmsnapshot_3 = VmSnapshot.create( + cls.apiclient, + cls.virtual_machine_1.id + )""" + + #Stop VMs + cls.virtual_machine_1.stop(cls.apiclient) + cls.virtual_machine_2.stop(cls.apiclient) + cls.virtual_machine_3.stop(cls.apiclient) + + #Get ROOT volumes of 3 VMs + vm1RootVolumeResponse = Volume.list( + cls.apiclient, + virtualmachineid=cls.virtual_machine_1.id, + type='ROOT', + listall=True + ) + vm2RootVolumeResponse = Volume.list( + cls.apiclient, + virtualmachineid=cls.virtual_machine_2.id, + type='ROOT', + listall=True + ) + vm3RootVolumeResponse = Volume.list( + cls.apiclient, + virtualmachineid=cls.virtual_machine_3.id, + type='ROOT', + listall=True + ) + cls.vm1_root_volume = vm1RootVolumeResponse[0] + cls.vm2_root_volume = vm2RootVolumeResponse[0] + cls.vm3_root_volume = vm3RootVolumeResponse[0] + + #Take 3 snapshots of VM2's ROOT volume + cls.snapshot_1 = Snapshot.create( + cls.apiclient, + cls.vm2_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + cls.snapshot_2 = Snapshot.create( + cls.apiclient, + cls.vm2_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + cls.snapshot_3 = Snapshot.create( + cls.apiclient, + cls.vm2_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + + #Create 3 templates + cls.template_1 = Template.create( + cls.apiclient, + cls.services["template"], + cls.vm3_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + cls.template_2 = Template.create( + cls.apiclient, + cls.services["template_2"], + cls.vm3_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + cls.template_3 = Template.create( + cls.apiclient, + cls.services["template_2"], + cls.vm3_root_volume.id, + account=cls.account.name, + domainid=cls.account.domainid + ) + + cls._cleanup = [ + cls.disk_offering, + cls.account, + cls.service_offering, + cls.snapshot_1, + cls.snapshot_2, + cls.snapshot_3 + ] + + @classmethod + def tearDownClass(cls): + cls.apiclient = super(TestListIdsParams, cls).getClsTestClient().getApiClient() + try: + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_01_list_volumes(self): + """Test listing Volumes using 'ids' parameter + """ + list_volume_response = Volume.list( + self.apiclient, + ids=[self.vm1_root_volume.id, self.vm2_root_volume.id, self.vm3_root_volume.id], + type='ROOT', + listAll=True + ) + self.assertEqual( + isinstance(list_volume_response, list), + True, + "List Volume response was not a valid list" + ) + self.assertEqual( + len(list_volume_response), + 3, + "ListVolumes response expected 3 Volumes, received %s" % len(list_volume_response) + ) + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_02_list_templates(self): + """Test listing Templates using 'ids' parameter + """ + list_template_response = Template.list( + self.apiclient, + templatefilter='all', + ids=[self.template_1.id, self.template_2.id, self.template_3.id], + account=self.account.name, + domainid=self.account.domainid, + listAll=True + ) + self.assertEqual( + isinstance(list_template_response, list), + True, + "ListTemplates response was not a valid list" + ) + self.assertEqual( + len(list_template_response), + 3, + "ListTemplates response expected 3 Templates, received %s" % len(list_template_response) + ) + + @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + def test_03_list_snapshots(self): + """Test listing Snapshots using 'ids' parameter + """ + list_snapshot_response = Snapshot.list( + self.apiclient, + ids=[self.snapshot_1.id, self.snapshot_2.id, self.snapshot_3.id], + listAll=True + ) + self.assertEqual( + isinstance(list_snapshot_response, list), + True, + "ListSnapshots response was not a valid list" + ) + self.assertEqual( + len(list_snapshot_response), + 3, + "ListSnapshots response expected 3 Snapshots, received %s" % len(list_snapshot_response) + ) + + #PLEASE UNCOMMENT ONCE VM SNAPSHOT DELAY BUG AFTER VM CREATION IS FIXED + #@attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + #def test_04_list_vm_snapshots(self): + """Test listing VMSnapshots using 'vmsnapshotids' parameter + """ + """list_vm_snapshot_response = VmSnapshot.list( + self.apiclient, + vmsnapshotids=[self.vmsnapshot_1.id, self.vmsnapshot_2.id, self.vmsnapshot_3.id], + listall=True + ) + self.assertEqual( + isinstance(list_vm_snapshot_response, list), + True, + "ListVMSnapshots response was not a valid list" + ) + self.assertEqual( + len(list_vm_snapshot_response), + 3, + "ListVMSnapshots response expected 3 VMSnapshots, received %s" % len(list_vm_snapshot_response) + )"""