Skip to content

Commit d8158fe

Browse files
author
rashmidixit
committed
CLOUDSTACK-9718: Revamp the dropdown showing lists of hosts available for migration in a Zone
Reviewed-By: Rashmi Dixit Problem: All the hosts suitable for VM Migration are not shown in the UI. This could confuse the user as the target host might never be shown in the UI. Root Cause: The API (findHostsForMigration) always returned page 1 results which would be always <= default.page.size global parameter. Therefore, in case of large no. of hosts where the result can map to multiple pages, this issue would arise. Solution: 1. Replace drop-down with listView widget. 2. Allow lazy-loading of records on listView's scroll. 3. Show additional parameters (CPU/Memory used) to assist admin in decision making. 4. Provide 'Search by host name' to limit the results. Added change where if there are no hosts found, an empty row with message will appear.
1 parent 5c0979f commit d8158fe

File tree

11 files changed

+299
-101
lines changed

11 files changed

+299
-101
lines changed

api/src/com/cloud/server/ManagementService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ public interface ManagementService {
401401
* @return Ternary<List<? extends Host>, List<? extends Host>, Map<Host, Boolean>> List of all Hosts to which a VM
402402
* can be migrated, list of Hosts with enough capacity and hosts requiring storage motion for migration.
403403
*/
404-
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize);
404+
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize, String keyword);
405405

406406
/**
407407
* List storage pools for live migrating of a volume. The API returns list of all pools in the cluster to which the

api/src/org/apache/cloudstack/api/command/admin/host/FindHostsForMigrationCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public void execute() {
7676
Map<Host, Boolean> hostsRequiringStorageMotion;
7777

7878
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> hostsForMigration =
79-
_mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
79+
_mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal(), this.getKeyword());
8080
result = hostsForMigration.first();
8181
List<? extends Host> hostsWithCapacity = hostsForMigration.second();
8282
hostsRequiringStorageMotion = hostsForMigration.third();

api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ protected ListResponse<HostResponse> getHostResponses() {
209209
} else {
210210
Pair<List<? extends Host>, Integer> result;
211211
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> hostsForMigration =
212-
_mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
212+
_mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal(), null);
213213
result = hostsForMigration.first();
214214
List<? extends Host> hostsWithCapacity = hostsForMigration.second();
215215
List<HostResponse> hostResponses = new ArrayList<HostResponse>();

server/src/com/cloud/server/ManagementServerImpl.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,10 @@ public Pair<List<? extends Host>, Integer> searchForServers(final ListHostsCmd c
11121112
}
11131113

11141114
@Override
1115-
public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(final Long vmId, final Long startIndex, final Long pageSize) {
1115+
public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>>
1116+
listHostsForMigrationOfVM(final Long vmId,
1117+
final Long startIndex,
1118+
final Long pageSize, final String keyword) {
11161119
final Account caller = getCaller();
11171120
if (!_accountMgr.isRootAdmin(caller.getId())) {
11181121
if (s_logger.isDebugEnabled()) {
@@ -1200,9 +1203,8 @@ public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Ho
12001203
List<HostVO> allHosts = null;
12011204
final Map<Host, Boolean> requiresStorageMotion = new HashMap<Host, Boolean>();
12021205
DataCenterDeployment plan = null;
1203-
12041206
if (canMigrateWithStorage) {
1205-
allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, srcHost.getDataCenterId(), null, null, null, null, null, null,
1207+
allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, srcHost.getDataCenterId(), null, null, null, keyword, null, null,
12061208
srcHost.getHypervisorType(), srcHost.getHypervisorVersion());
12071209
allHosts = allHostsPair.first();
12081210
allHosts.remove(srcHost);
@@ -1239,7 +1241,7 @@ public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Ho
12391241
if (s_logger.isDebugEnabled()) {
12401242
s_logger.debug("Searching for all hosts in cluster " + cluster + " for migrating VM " + vm);
12411243
}
1242-
allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, null, null, cluster, null, null, null, null, null, null);
1244+
allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, null, null, cluster, null, keyword, null, null, null, null);
12431245
// Filter out the current host.
12441246
allHosts = allHostsPair.first();
12451247
allHosts.remove(srcHost);

ui/css/cloudstack3.css

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,27 @@ div.list-view td.state.transition span {
14251425
background-position: 1px -432px;
14261426
}
14271427

1428+
div.list-view td.state.suitable span {
1429+
background: url(../images/icons.png) no-repeat scroll 1px -224px;
1430+
color: #008000;
1431+
height: 18px;
1432+
}
1433+
1434+
div.list-view td.state.suitable-storage-migration-required span {
1435+
width: 200px;
1436+
}
1437+
1438+
div.list-view td.state.notsuitable span {
1439+
background: url(../images/icons.png) no-repeat scroll 1px -190px;
1440+
color: #B90606;
1441+
height: 19px;
1442+
width: 100px;
1443+
}
1444+
1445+
div.list-view td.state.notsuitable-storage-migration-required span {
1446+
width: 220px !important;
1447+
}
1448+
14281449
.horizontal-overflow tbody td, .horizontal-overflow thead th {
14291450
min-width: 40px;
14301451
padding: 10px 10px 5px 0px;
@@ -13232,3 +13253,21 @@ ul.ui-autocomplete.ui-menu {
1323213253
font-size: 13px;
1323313254
padding: 5px;
1323413255
}
13256+
13257+
.multi-edit-add-list .ui-button.migrateok,
13258+
.multi-edit-add-list .ui-button.migratecancel {
13259+
top: -5px !important;
13260+
}
13261+
13262+
.migrate-vm-available-host-list div.text-search {
13263+
right: 30px;
13264+
}
13265+
13266+
.migrate-vm-available-host-list div.ui-widget-content {
13267+
display: block !important;
13268+
}
13269+
13270+
.list-view-select table th.availableHostSuitability,
13271+
.list-view-select table td.availableHostSuitability {
13272+
max-width: 250px;
13273+
}

ui/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,6 +1852,7 @@ <h3><translate key="label.set.up.zone.type"/></h3>
18521852
<script type="text/javascript" src="scripts/instanceWizard.js"></script>
18531853
<script type="text/javascript" src="scripts/affinity.js"></script>
18541854
<script type="text/javascript" src="scripts/ui-custom/affinity.js"></script>
1855+
<script type="text/javascript" src="scripts/ui-custom/migrate.js"></script>
18551856
<script type="text/javascript" src="scripts/instances.js"></script>
18561857
<script type="text/javascript" src="scripts/events.js"></script>
18571858
<script type="text/javascript" src="scripts/regions.js"></script>

ui/l10n/en.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
14661466
"label.select.a.template":"Select a template",
14671467
"label.select.a.zone":"Select a zone",
14681468
"label.select.instance":"Select instance",
1469+
"label.select.host":"Select host",
14691470
"label.select.instance.to.attach.volume.to":"Select instance to attach volume to",
14701471
"label.select.iso.or.template":"Select ISO or template",
14711472
"label.select.offering":"Select offering",
@@ -1526,6 +1527,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
15261527
"label.start.vlan":"Start VLAN",
15271528
"label.start.vxlan":"Start VXLAN",
15281529
"label.state":"State",
1530+
"label.suitability": "Suitability",
15291531
"label.static.nat":"Static NAT",
15301532
"label.static.nat.enabled":"Static NAT Enabled",
15311533
"label.static.nat.to":"Static NAT to",
@@ -2114,6 +2116,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
21142116
"message.lock.account":"Please confirm that you want to lock this account. By locking the account, all users for this account will no longer be able to manage their cloud resources. Existing resources can still be accessed.",
21152117
"message.migrate.instance.confirm":"Please confirm the host you wish to migrate the virtual instance to.",
21162118
"message.migrate.instance.to.host":"Please confirm that you want to migrate instance to another host.",
2119+
"message.migrate.instance.select.host":"Please select a host for migration",
21172120
"message.migrate.instance.to.ps":"Please confirm that you want to migrate instance to another primary storage.",
21182121
"message.migrate.router.confirm":"Please confirm the host you wish to migrate the router to:",
21192122
"message.migrate.systemvm.confirm":"Please confirm the host you wish to migrate the system VM to:",
@@ -2123,7 +2126,8 @@ var dictionary = {"ICMP.code":"ICMP Code",
21232126
"message.network.remote.access.vpn.configuration":"Remote Access VPN configuration has been generated, but it failed to apply. Please check connectivity of the network element, then re-try.",
21242127
"message.new.user":"Specify the following to add a new user to the account",
21252128
"message.no.affinity.groups":"You do not have any affinity groups. Please continue to the next step.",
2126-
"message.no.host.available":"No Hosts are available for Migration",
2129+
"message.no.host.available":"No hosts are available for migration",
2130+
"message.no.more.hosts.available":"No more hosts are available for migration",
21272131
"message.no.network.support":"Your selected hypervisor, vSphere, does not have any additional network features. Please continue to step 5.",
21282132
"message.no.network.support.configuration.not.true":"You do not have any zone that has security group enabled. Thus, no additional network features. Please continue to step 5.",
21292133
"message.no.projects":"You do not have any projects.<br/>Please create a new one from the projects section.",

ui/l10n/ja_JP.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,7 @@ var dictionary = {
14681468
"label.select.a.zone": "ゾーンの選択",
14691469
"label.select.instance": "インスタンスの選択",
14701470
"label.select.instance.to.attach.volume.to": "ボリュームをアタッチするインスタンスを選択してください",
1471+
"label.select.host":"ホストの選択",
14711472
"label.select.iso.or.template": "ISO またはテンプレートの選択",
14721473
"label.select.offering": "オファリングの選択",
14731474
"label.select.project": "プロジェクトの選択",
@@ -1527,6 +1528,7 @@ var dictionary = {
15271528
"label.start.vlan": "開始 VLAN",
15281529
"label.start.vxlan": "開始 VXLAN",
15291530
"label.state": "状態",
1531+
"label.suitability": "適合",
15301532
"label.static.nat": "静的 NAT",
15311533
"label.static.nat.enabled": "静的 NAT 有効",
15321534
"label.static.nat.to": "静的 NAT の設定先:",
@@ -2115,6 +2117,7 @@ var dictionary = {
21152117
"message.lock.account": "このアカウントをロックしてもよろしいですか? このアカウントのすべてのユーザーがクラウド リソースを管理できなくなります。その後も既存のリソースにはアクセスできます。",
21162118
"message.migrate.instance.confirm": "仮想インスタンスの移行先は次のホストでよろしいですか?",
21172119
"message.migrate.instance.to.host": "別のホストにインスタンスを移行してもよろしいですか?",
2120+
"message.migrate.instance.select.host": "マイグレーション行うホストを選択。",
21182121
"message.migrate.instance.to.ps": "別のプライマリ ストレージにインスタンスを移行してもよろしいですか?",
21192122
"message.migrate.router.confirm": "ルーターの移行先は次のホストでよろしいですか?",
21202123
"message.migrate.systemvm.confirm": "システム VM の移行先は次のホストでよろしいですか?",
@@ -2125,6 +2128,7 @@ var dictionary = {
21252128
"message.new.user": "アカウントに新しいユーザーを追加するために、次の情報を指定してください。",
21262129
"message.no.affinity.groups": "アフィニティ グループがありません。次の手順に進んでください。",
21272130
"message.no.host.available": "移行に使用できるホストはありません",
2131+
"message.no.more.hosts.available": "マイグレーション可能なホストがありません。",
21282132
"message.no.network.support": "ハイパーバイザーとして vSphere を選択しましたが、このハイパーバイザーに追加のネットワーク機能はありません。手順 5. に進んでください。",
21292133
"message.no.network.support.configuration.not.true": "セキュリティ グループが有効なゾーンが無いため、追加のネットワーク機能はありません。手順 5. に進んでください。",
21302134
"message.no.projects": "プロジェクトがありません。<br/>プロジェクト セクションから新しいプロジェクトを作成してください。",

ui/l10n/zh_CN.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,7 @@ var dictionary = {
14681468
"label.select.a.zone": "选择一个资源域",
14691469
"label.select.instance": "选择实例",
14701470
"label.select.instance.to.attach.volume.to": "选择要将卷附加到的实例",
1471+
"label.select.host": "选择主机",
14711472
"label.select.iso.or.template": "选择 ISO 或模板",
14721473
"label.select.offering": "选择方案",
14731474
"label.select.project": "选择项目",
@@ -1527,6 +1528,7 @@ var dictionary = {
15271528
"label.start.vlan": "起始 VLAN",
15281529
"label.start.vxlan": "起始 VXLAN",
15291530
"label.state": "状态",
1531+
"label.suitability": "适应性",
15301532
"label.static.nat": "静态 NAT",
15311533
"label.static.nat.enabled": "已启用静态 NAT",
15321534
"label.static.nat.to": "静态 NAT 目标",
@@ -2115,6 +2117,7 @@ var dictionary = {
21152117
"message.lock.account": "请确认您确实要锁定此帐户。通过锁定此帐户,此帐户的所有用户将不再能够管理各自的云资源,但仍然可以访问现有资源。",
21162118
"message.migrate.instance.confirm": "请确认要将虚拟实例迁移到的主机。",
21172119
"message.migrate.instance.to.host": "请确认您确实要将实例迁移到其他主机。",
2120+
"message.migrate.instance.select.host": "选择用于迁移的主机",
21182121
"message.migrate.instance.to.ps": "请确认您确实要将实例迁移到其他主存储。",
21192122
"message.migrate.router.confirm": "请确认您要将路由器迁移到的主机:",
21202123
"message.migrate.systemvm.confirm": "请确认您要将系统 VM 迁移到的主机:",
@@ -2125,6 +2128,7 @@ var dictionary = {
21252128
"message.new.user": "请指定以下信息以向帐户中添加一个新用户",
21262129
"message.no.affinity.groups": "您没有任何关联性组。请继续执行下一步操作。",
21272130
"message.no.host.available": "没有可用于迁移的主机",
2131+
"message.no.more.hosts.available": "没有可用于迁移的主机",
21282132
"message.no.network.support": "您选择的虚拟机管理程序 vSphere 没有任何其他网络功能。请继续执行步骤 5。",
21292133
"message.no.network.support.configuration.not.true": "您的所有资源域都未启用安全组,因此无其他网络功能。请继续执行步骤 5。",
21302134
"message.no.projects": "您没有任何项目。<br/>请从“项目”部分中创建一个新项目。",

0 commit comments

Comments
 (0)