Skip to content

Commit b770d27

Browse files
committed
Improve Vmware VMs retrieval
1 parent 55c8138 commit b770d27

9 files changed

Lines changed: 355 additions & 28 deletions

File tree

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
import com.cloud.dc.VsphereStoragePolicy;
2323
import com.cloud.exception.DiscoveryException;
2424
import com.cloud.exception.ResourceInUseException;
25+
import com.cloud.hypervisor.vmware.mo.HostMO;
2526
import com.cloud.storage.StoragePool;
2627
import com.cloud.utils.component.PluggableService;
2728
import com.cloud.utils.exception.CloudRuntimeException;
2829
import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd;
2930
import org.apache.cloudstack.api.command.admin.zone.ImportVsphereStoragePoliciesCmd;
31+
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcHostsCmd;
3032
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd;
3133
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd;
3234
import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePoliciesCmd;
@@ -54,4 +56,6 @@ public interface VmwareDatacenterService extends PluggableService {
5456
List<StoragePool> listVsphereStoragePolicyCompatibleStoragePools(ListVsphereStoragePolicyCompatiblePoolsCmd cmd);
5557

5658
List<UnmanagedInstanceTO> listVMsInDatacenter(ListVmwareDcVmsCmd cmd);
59+
60+
List<HostMO> listHostsInDatacenter(ListVmwareDcHostsCmd cmd);
5761
}

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,12 @@
4343
import javax.naming.ConfigurationException;
4444
import javax.persistence.EntityExistsException;
4545

46+
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
4647
import com.cloud.hypervisor.vmware.util.VmwareClient;
4748
import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd;
4849
import org.apache.cloudstack.api.command.admin.zone.ImportVsphereStoragePoliciesCmd;
50+
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcHostsCmd;
51+
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcItems;
4952
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd;
5053
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd;
5154
import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePoliciesCmd;
@@ -1587,14 +1590,26 @@ public List<StoragePool> listVsphereStoragePolicyCompatibleStoragePools(ListVsph
15871590
return compatiblePools;
15881591
}
15891592

1590-
@Override
1591-
public List<UnmanagedInstanceTO> listVMsInDatacenter(ListVmwareDcVmsCmd cmd) {
1593+
private static class VcenterData {
1594+
public final String vcenter;
1595+
public final String datacenterName;
1596+
public final String username;
1597+
public final String password;
1598+
1599+
public VcenterData(String vcenter, String datacenterName, String username, String password) {
1600+
this.vcenter = vcenter;
1601+
this.datacenterName = datacenterName;
1602+
this.username = username;
1603+
this.password = password;
1604+
}
1605+
}
1606+
1607+
private VcenterData getVcenterData(ListVmwareDcItems cmd) {
15921608
String vcenter = cmd.getVcenter();
15931609
String datacenterName = cmd.getDatacenterName();
15941610
String username = cmd.getUsername();
15951611
String password = cmd.getPassword();
15961612
Long existingVcenterId = cmd.getExistingVcenterId();
1597-
String keyword = cmd.getKeyword();
15981613

15991614
if ((existingVcenterId == null && StringUtils.isBlank(vcenter)) ||
16001615
(existingVcenterId != null && StringUtils.isNotBlank(vcenter))) {
@@ -1615,26 +1630,75 @@ public List<UnmanagedInstanceTO> listVMsInDatacenter(ListVmwareDcVmsCmd cmd) {
16151630
username = vmwareDc.getUser();
16161631
password = vmwareDc.getPassword();
16171632
}
1633+
VcenterData vmwaredc = new VcenterData(vcenter, datacenterName, username, password);
1634+
return vmwaredc;
1635+
}
1636+
1637+
private VmwareContext getVmwareContext(String vcenter, String username, String password) throws Exception {
1638+
s_logger.debug(String.format("Connecting to the VMware vCenter %s", vcenter));
1639+
String serviceUrl = String.format("https://%s/sdk/vimService", vcenter);
1640+
VmwareClient vimClient = new VmwareClient(vcenter);
1641+
vimClient.connect(serviceUrl, username, password);
1642+
return new VmwareContext(vimClient, vcenter);
1643+
}
1644+
1645+
@Override
1646+
public List<UnmanagedInstanceTO> listVMsInDatacenter(ListVmwareDcVmsCmd cmd) {
1647+
VcenterData vmwareDC = getVcenterData(cmd);
1648+
String vcenter = vmwareDC.vcenter;
1649+
String username = vmwareDC.username;
1650+
String password = vmwareDC.password;
1651+
String datacenterName = vmwareDC.datacenterName;
1652+
String keyword = cmd.getKeyword();
1653+
String esxiHostName = cmd.getHostName();
16181654

16191655
try {
1620-
s_logger.debug(String.format("Connecting to the VMware datacenter %s at vCenter %s to retrieve VMs",
1621-
datacenterName, vcenter));
1622-
String serviceUrl = String.format("https://%s/sdk/vimService", vcenter);
1623-
VmwareClient vimClient = new VmwareClient(vcenter);
1624-
vimClient.connect(serviceUrl, username, password);
1625-
VmwareContext context = new VmwareContext(vimClient, vcenter);
1626-
1627-
DatacenterMO dcMo = new DatacenterMO(context, datacenterName);
1628-
ManagedObjectReference dcMor = dcMo.getMor();
1629-
if (dcMor == null) {
1630-
String msg = String.format("Unable to find VMware datacenter %s in vCenter %s",
1631-
datacenterName, vcenter);
1632-
s_logger.error(msg);
1633-
throw new InvalidParameterValueException(msg);
1656+
VmwareContext context = getVmwareContext(vcenter, username, password);
1657+
DatacenterMO dcMo = getDatacenterMO(context, vcenter, datacenterName);
1658+
1659+
List<VirtualMachineMO> vms;
1660+
if (StringUtils.isNotBlank(esxiHostName)) {
1661+
// List VMs in a specific ESXi Host
1662+
HostMO hostMO = VmwareHelper.getHostMOFromHostName(context, esxiHostName);
1663+
vms = hostMO.listVmsOnHyperHostWithHypervisorName(null);
1664+
} else {
1665+
// Long lasting method, not recommended - retrieves all the VMs in a datacenter
1666+
vms = dcMo.getAllVmsOnDatacenter();
16341667
}
1635-
List<UnmanagedInstanceTO> instances = dcMo.getAllVmsOnDatacenter();
1668+
1669+
List<UnmanagedInstanceTO> instances = VmwareHelper.getUnmanagedInstancesList(vms);
16361670
return StringUtils.isBlank(keyword) ? instances :
16371671
instances.stream().filter(x -> x.getName().toLowerCase().contains(keyword.toLowerCase())).collect(Collectors.toList());
1672+
} catch (Exception e) {
1673+
String errorMsg = String.format("Error retrieving VMs from the VMware VC %s datacenter %s: %s",
1674+
vcenter, datacenterName, e.getMessage());
1675+
s_logger.error(errorMsg, e);
1676+
throw new CloudRuntimeException(errorMsg);
1677+
}
1678+
}
1679+
1680+
private static DatacenterMO getDatacenterMO(VmwareContext context, String vcenter, String datacenterName) throws Exception {
1681+
DatacenterMO dcMo = new DatacenterMO(context, datacenterName);
1682+
ManagedObjectReference dcMor = dcMo.getMor();
1683+
if (dcMor == null) {
1684+
String msg = String.format("Unable to find VMware datacenter %s in vCenter %s", datacenterName, vcenter);
1685+
s_logger.error(msg);
1686+
throw new InvalidParameterValueException(msg);
1687+
}
1688+
return dcMo;
1689+
}
1690+
1691+
@Override
1692+
public List<HostMO> listHostsInDatacenter(ListVmwareDcHostsCmd cmd) {
1693+
VcenterData vmwareDC = getVcenterData(cmd);
1694+
String vcenter = vmwareDC.vcenter;
1695+
String username = vmwareDC.username;
1696+
String password = vmwareDC.password;
1697+
String datacenterName = vmwareDC.datacenterName;
1698+
try {
1699+
VmwareContext context = getVmwareContext(vcenter, username, password);
1700+
DatacenterMO dcMo = getDatacenterMO(context, vcenter, datacenterName);
1701+
return dcMo.getAllHostsOnDatacenter();
16381702
} catch (Exception e) {
16391703
String errorMsg = String.format("Error retrieving stopped VMs from the VMware VC %s datacenter %s: %s",
16401704
vcenter, datacenterName, e.getMessage());
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.api.command.admin.zone;
18+
19+
import com.cloud.exception.ConcurrentOperationException;
20+
import com.cloud.exception.InsufficientCapacityException;
21+
import com.cloud.exception.NetworkRuleConflictException;
22+
import com.cloud.exception.ResourceAllocationException;
23+
import com.cloud.exception.ResourceUnavailableException;
24+
import com.cloud.hypervisor.Hypervisor;
25+
import com.cloud.hypervisor.vmware.VmwareDatacenterService;
26+
import com.cloud.hypervisor.vmware.mo.HostMO;
27+
import com.cloud.user.Account;
28+
29+
import org.apache.cloudstack.api.APICommand;
30+
import org.apache.cloudstack.api.ApiConstants;
31+
import org.apache.cloudstack.api.ApiErrorCode;
32+
import org.apache.cloudstack.api.BaseListCmd;
33+
import org.apache.cloudstack.api.Parameter;
34+
import org.apache.cloudstack.api.ServerApiException;
35+
import org.apache.cloudstack.api.response.HostResponse;
36+
import org.apache.cloudstack.api.response.ListResponse;
37+
import org.apache.cloudstack.api.response.VmwareDatacenterResponse;
38+
import org.apache.commons.collections.CollectionUtils;
39+
import org.apache.commons.lang3.StringUtils;
40+
41+
import javax.inject.Inject;
42+
import java.util.ArrayList;
43+
import java.util.List;
44+
45+
@APICommand(name = "listVmwareDcHosts", responseObject = HostResponse.class,
46+
description = "Lists the Hosts in a Vmware Datacenter",
47+
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
48+
public class ListVmwareDcHostsCmd extends BaseListCmd implements ListVmwareDcItems {
49+
50+
@Inject
51+
public VmwareDatacenterService _vmwareDatacenterService;
52+
53+
@Parameter(name = ApiConstants.EXISTING_VCENTER_ID,
54+
type = CommandType.UUID,
55+
entityType = VmwareDatacenterResponse.class,
56+
description = "UUID of a linked existing vCenter")
57+
private Long existingVcenterId;
58+
59+
@Parameter(name = ApiConstants.VCENTER,
60+
type = CommandType.STRING,
61+
description = "The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
62+
private String vcenter;
63+
64+
@Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING, description = "Name of Vmware datacenter.")
65+
private String datacenterName;
66+
67+
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "The Username required to connect to resource.")
68+
private String username;
69+
70+
@Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "The password for specified username.")
71+
private String password;
72+
73+
public String getVcenter() {
74+
return vcenter;
75+
}
76+
77+
public String getUsername() {
78+
return username;
79+
}
80+
81+
public String getPassword() {
82+
return password;
83+
}
84+
85+
public String getDatacenterName() {
86+
return datacenterName;
87+
}
88+
89+
public Long getExistingVcenterId() {
90+
return existingVcenterId;
91+
}
92+
93+
@Override
94+
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
95+
checkParameters();
96+
try {
97+
List<HostMO> hosts = _vmwareDatacenterService.listHostsInDatacenter(this);
98+
ListResponse<HostResponse> response = new ListResponse<>();
99+
List<HostResponse> baseResponseList = new ArrayList<>();
100+
if (CollectionUtils.isNotEmpty(hosts)) {
101+
for (HostMO vmwareHost : hosts) {
102+
HostResponse resp = createHostResponse(vmwareHost);
103+
baseResponseList.add(resp);
104+
}
105+
}
106+
response.setResponses(baseResponseList, baseResponseList.size());
107+
response.setResponseName(getCommandName());
108+
setResponseObject(response);
109+
} catch (Exception e) {
110+
String errorMsg = String.format("Error retrieving VMs from Vmware VC: %s", e.getMessage());
111+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg);
112+
}
113+
}
114+
115+
private HostResponse createHostResponse(HostMO hostInstance) throws Exception {
116+
HostResponse response = new HostResponse();
117+
response.setHypervisor(Hypervisor.HypervisorType.VMware.toString());
118+
response.setName(hostInstance.getHostName());
119+
response.setObjectName("host");
120+
return response;
121+
}
122+
123+
private void checkParameters() {
124+
if ((existingVcenterId == null && vcenter == null) || (existingVcenterId != null && vcenter != null)) {
125+
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
126+
"Please provide an existing vCenter ID or a vCenter IP/Name, parameters are mutually exclusive");
127+
}
128+
if (existingVcenterId == null && StringUtils.isAnyBlank(vcenter, datacenterName, username, password)) {
129+
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
130+
"Please set all the information for a vCenter IP/Name, datacenter, username and password");
131+
}
132+
}
133+
134+
@Override
135+
public long getEntityOwnerId() {
136+
return Account.ACCOUNT_ID_SYSTEM;
137+
}
138+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.api.command.admin.zone;
18+
19+
public interface ListVmwareDcItems {
20+
String getVcenter();
21+
22+
String getDatacenterName();
23+
24+
String getUsername();
25+
26+
String getPassword();
27+
28+
Long getExistingVcenterId();
29+
}

plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcVmsCmd.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
@APICommand(name = "listVmwareDcVms", responseObject = UnmanagedInstanceResponse.class,
4646
description = "Lists the VMs in a VMware Datacenter",
4747
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
48-
public class ListVmwareDcVmsCmd extends BaseListCmd {
48+
public class ListVmwareDcVmsCmd extends BaseListCmd implements ListVmwareDcItems {
4949

5050
@Inject
5151
public VmwareDatacenterService _vmwareDatacenterService;
@@ -64,6 +64,9 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
6464
@Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING, description = "Name of VMware datacenter.")
6565
private String datacenterName;
6666

67+
@Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, description = "Get only the VMs from the specified host.")
68+
private String hostName;
69+
6770
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "The Username required to connect to resource.")
6871
private String username;
6972

@@ -86,6 +89,10 @@ public String getDatacenterName() {
8689
return datacenterName;
8790
}
8891

92+
public String getHostName() {
93+
return hostName;
94+
}
95+
8996
public Long getExistingVcenterId() {
9097
return existingVcenterId;
9198
}

ui/src/views/tools/ManageInstances.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,7 @@ export default {
11841184
} else {
11851185
params.existingvcenterid = this.selectedVmwareVcenter.existingvcenterid
11861186
}
1187+
params.host = this.selectedVmwareVcenter.host
11871188
}
11881189
11891190
api(apiName, params).then(json => {

0 commit comments

Comments
 (0)