Skip to content

Commit 5779292

Browse files
committed
CLOUDSTACK-6052: List VM enhancement to support querying with multiple VM IDs
New parameter 'ids' added to listVirtualMachine API. The syntax looks like http://localhost:8096/api?command=listVirtualMachines&listAll=true&ids=eddac053-9b12-4d2e-acb7-233de2e98112,009966fc-4d7b-4f84-8609-254979ba0134 The new parameter will be mutually exclusive with the existing 'id' parameter.
1 parent bc4c805 commit 5779292

3 files changed

Lines changed: 76 additions & 4 deletions

File tree

api/src/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd {
6464
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserVmResponse.class, description = "the ID of the virtual machine")
6565
private Long id;
6666

67+
@Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=UserVmResponse.class,
68+
description="the IDs of the virtual machines, mutually exclusive with id")
69+
private List<Long> ids;
70+
6771
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "name of the virtual machine")
6872
private String name;
6973

@@ -135,6 +139,10 @@ public Long getId() {
135139
return id;
136140
}
137141

142+
public List<Long> getIds() {
143+
return ids;
144+
}
145+
138146
public String getName() {
139147
return name;
140148
}

server/src/com/cloud/api/query/QueryManagerImpl.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -728,11 +728,22 @@ private Pair<List<UserVmJoinVO>, Integer> searchForUserVMsInternal(ListVMsCmd cm
728728
Boolean isRecursive = domainIdRecursiveListProject.second();
729729
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
730730

731+
List<Long> ids = null;
732+
if (cmd.getId() != null) {
733+
if (cmd.getIds() != null && !cmd.getIds().isEmpty()) {
734+
throw new InvalidParameterValueException("Specify either id or ids but not both parameters");
735+
}
736+
ids = new ArrayList<Long>();
737+
ids.add(cmd.getId());
738+
} else {
739+
ids = cmd.getIds();
740+
}
741+
731742
Criteria c = new Criteria("id", Boolean.TRUE, cmd.getStartIndex(), cmd.getPageSizeVal());
732743
// Criteria c = new Criteria(null, Boolean.FALSE, cmd.getStartIndex(),
733744
// cmd.getPageSizeVal()); //version without default sorting
734745
c.addCriteria(Criteria.KEYWORD, cmd.getKeyword());
735-
c.addCriteria(Criteria.ID, cmd.getId());
746+
c.addCriteria(Criteria.ID, ids);
736747
c.addCriteria(Criteria.NAME, cmd.getName());
737748
c.addCriteria(Criteria.STATE, cmd.getState());
738749
c.addCriteria(Criteria.DATACENTERID, cmd.getZoneId());
@@ -805,7 +816,7 @@ private Pair<List<UserVmJoinVO>, Integer> searchForUserVMsByCriteria(Criteria c,
805816
Object display = c.getCriteria(Criteria.DISPLAY);
806817

807818
sb.and("displayName", sb.entity().getDisplayName(), SearchCriteria.Op.LIKE);
808-
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
819+
sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN);
809820
sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
810821
sb.and("stateEQ", sb.entity().getState(), SearchCriteria.Op.EQ);
811822
sb.and("stateNEQ", sb.entity().getState(), SearchCriteria.Op.NEQ);
@@ -889,7 +900,10 @@ private Pair<List<UserVmJoinVO>, Integer> searchForUserVMsByCriteria(Criteria c,
889900
}
890901

891902
if (id != null) {
892-
sc.setParameters("id", id);
903+
List<?> idList = (id instanceof List<?> ? (List<?>)id : null);
904+
if (idList != null && !idList.isEmpty()) {
905+
sc.setParameters("idIN", idList.toArray());
906+
}
893907
}
894908

895909
if (templateId != null) {

test/integration/smoke/test_deploy_vm.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ def __init__(self):
5151
"name" : "testvm",
5252
"displayname" : "Test VM",
5353
},
54+
#data reqd for virtual machine creation
55+
"virtual_machine2" : {
56+
"name" : "testvm2",
57+
"displayname" : "Test VM2",
58+
},
5459
#small service offering
5560
"service_offering": {
5661
"small": {
@@ -149,8 +154,53 @@ def test_deploy_vm(self):
149154
msg="VM is not in Running state"
150155
)
151156

157+
@attr(tags = ['advanced', 'simulator', 'basic', 'sg'])
158+
def test_deploy_vm_multiple(self):
159+
"""Test Multiple Deploy Virtual Machine
160+
161+
# Validate the following:
162+
# 1. deploy 2 virtual machines
163+
# 2. listVirtualMachines using 'ids' parameter returns accurate information
164+
"""
165+
self.virtual_machine = VirtualMachine.create(
166+
self.apiclient,
167+
self.testdata["virtual_machine"],
168+
accountid=self.account.name,
169+
zoneid=self.zone.id,
170+
domainid=self.account.domainid,
171+
serviceofferingid=self.service_offering.id,
172+
templateid=self.template.id
173+
)
174+
175+
self.virtual_machine2 = VirtualMachine.create(
176+
self.apiclient,
177+
self.testdata["virtual_machine2"],
178+
accountid=self.account.name,
179+
zoneid=self.zone.id,
180+
domainid=self.account.domainid,
181+
serviceofferingid=self.service_offering.id,
182+
templateid=self.template.id
183+
)
184+
185+
list_vms = VirtualMachine.list(self.apiclient, ids=[self.virtual_machine.id, self.virtual_machine2.id], listAll=True)
186+
self.debug(
187+
"Verify listVirtualMachines response for virtual machines: %s, %s" % (self.virtual_machine.id, self.virtual_machine2.id)
188+
)
189+
190+
self.assertEqual(
191+
isinstance(list_vms, list),
192+
True,
193+
"List VM response was not a valid list"
194+
)
195+
self.assertEqual(
196+
len(list_vms),
197+
2,
198+
"List VM response was empty, expected 2 VMs"
199+
)
200+
152201
def tearDown(self):
153202
try:
154203
cleanup_resources(self.apiclient, self.cleanup)
155204
except Exception as e:
156-
self.debug("Warning! Exception in tearDown: %s" % e)
205+
self.debug("Warning! Exception in tearDown: %s" % e)
206+

0 commit comments

Comments
 (0)