Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2530,6 +2530,7 @@
"System is error, please try again later.": "System is error, please try again later.",
"TCP": "TCP",
"TCP Connections": "TCP Connections",
"The following volumes can not change type and need to be deselected: {names}": "The following volumes can not change type and need to be deselected: {names}",
"This instance has no recorded hotplug ceiling yet": "This instance has no recorded hotplug ceiling yet",
"This instance opts out of live resize": "This instance opts out of live resize",
"TLS Disabled": "TLS Disabled",
Expand Down Expand Up @@ -2842,6 +2843,7 @@
"VMDK - Hyper-V compatible image format": "VMDK - Hyper-V compatible image format",
"VNC": "VNC",
"VNIC Type": "VNIC Type",
"Volumes already using the selected type are skipped.": "Volumes already using the selected type are skipped.",
"VPN": "VPN",
"VPN EndPoint Groups": "VPN EndPoint Groups",
"VPN Gateways": "VPN Gateways",
Expand Down
2 changes: 2 additions & 0 deletions src/locales/ko-kr.json
Original file line number Diff line number Diff line change
Expand Up @@ -2528,6 +2528,7 @@
"System is error, please try again later.": "",
"TCP": "",
"TCP Connections": "",
"The following volumes can not change type and need to be deselected: {names}": "다음 볼륨은 유형을 변경할 수 없으므로 선택을 해제하세요: {names}",
"This instance has no recorded hotplug ceiling yet": "이 인스턴스에는 아직 기록된 핫플러그 상한이 없습니다",
"This instance opts out of live resize": "이 인스턴스는 라이브 크기 조정을 사용하지 않습니다",
"TLS Disabled": "",
Expand Down Expand Up @@ -2840,6 +2841,7 @@
"VMDK - Hyper-V compatible image format": "VMDK - Hyper-V 호환 이미지 포맷",
"VNC": "VNC",
"VNIC Type": "VNIC 타입",
"Volumes already using the selected type are skipped.": "이미 선택한 유형을 사용 중인 볼륨은 건너뜁니다.",
"VPN": "VPN",
"VPN EndPoint Groups": "VPN 엔드포인트 그룹",
"VPN Gateways": "VPN 게이트웨이",
Expand Down
2 changes: 2 additions & 0 deletions src/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -2529,6 +2529,7 @@
"System is error, please try again later.": "Система в состоянии ошибки, пожалуйста, попробуйте позже.",
"TCP": "TCP",
"TCP Connections": "TCP-соединения",
"The following volumes can not change type and need to be deselected: {names}": "Следующие диски не могут изменить тип, снимите с них выделение: {names}",
"This instance has no recorded hotplug ceiling yet": "У этого инстанса ещё нет записанного предела горячего подключения",
"This instance opts out of live resize": "Для этого инстанса живое изменение размера отключено",
"TLS Disabled": "TLS отключен",
Expand Down Expand Up @@ -2841,6 +2842,7 @@
"VMDK - Hyper-V compatible image format": "VMDK - Формат образа, совместимый с Hyper-V",
"VNC": "VNC",
"VNIC Type": "Тип VNIC",
"Volumes already using the selected type are skipped.": "Диски, уже использующие выбранный тип, пропускаются.",
"VPN": "VPN",
"VPN EndPoint Groups": "Группы конечных точек VPN",
"VPN Gateways": "Шлюзы VPN",
Expand Down
2 changes: 2 additions & 0 deletions src/locales/zh-hans.json
Original file line number Diff line number Diff line change
Expand Up @@ -2529,6 +2529,7 @@
"System is error, please try again later.": "系统出错,请稍后再试。",
"TCP": "TCP",
"TCP Connections": "TCP连接数",
"The following volumes can not change type and need to be deselected: {names}": "以下云硬盘无法修改类型,请取消选择:{names}",
"This instance has no recorded hotplug ceiling yet": "此虚拟机尚未记录热插拔上限",
"This instance opts out of live resize": "该云主机已禁用热修改配置",
"TLS Disabled": "TLS禁用",
Expand Down Expand Up @@ -2841,6 +2842,7 @@
"VMDK - Hyper-V compatible image format": "VMDK - Hyper-V 兼容的图像格式",
"VNC": "",
"VNIC Type": "VNIC类型",
"Volumes already using the selected type are skipped.": "已经是所选类型的云硬盘将被跳过。",
"VPN": "VPN",
"VPN EndPoint Groups": "VPN端点组",
"VPN Gateways": "VPN网关",
Expand Down
2 changes: 2 additions & 0 deletions src/locales/zh-hant.json
Original file line number Diff line number Diff line change
Expand Up @@ -2529,6 +2529,7 @@
"System is error, please try again later.": "系統發生錯誤,請稍後再試。",
"TCP": "TCP",
"TCP Connections": "TCP 連線數",
"The following volumes can not change type and need to be deselected: {names}": "以下雲硬碟無法變更類型,請取消選取:{names}",
"This instance has no recorded hotplug ceiling yet": "此虛擬機尚未記錄熱插拔上限",
"This instance opts out of live resize": "此虛擬機已停用即時變更規格",
"TLS Disabled": "已停用 TLS",
Expand Down Expand Up @@ -2841,6 +2842,7 @@
"VMDK - Hyper-V compatible image format": "VMDK - Hyper-V 相容的映像檔格式",
"VNC": "VNC",
"VNIC Type": "VNIC 類型",
"Volumes already using the selected type are skipped.": "已經是所選類型的雲硬碟將被略過。",
"VPN": "VPN",
"VPN EndPoint Groups": "VPN 端點群組",
"VPN Gateways": "VPN 閘道",
Expand Down
129 changes: 112 additions & 17 deletions src/pages/storage/containers/Volume/actions/ChangeType.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import React from 'react';
import { inject, observer } from 'mobx-react';
import { isArray, uniq } from 'lodash';
import { ModalAction } from 'containers/Action';
import { allSettled } from 'utils';
import globalVolumeStore from 'stores/cinder/volume';
import globalVolumeTypeStore from 'stores/cinder/volume-type';
import { isAvailableOrInUse, isOsDisk } from 'resources/cinder/volume';
import { isAvailableOrInUse } from 'resources/cinder/volume';

// Nova's swap_volume has no root-disk guard, so a boot volume retypes like any
// other in-use one. Status is the only gate.
const canChangeType = (item) => isAvailableOrInUse(item);

export class ChangeType extends ModalAction {
static id = 'change-type';
Expand All @@ -29,12 +36,63 @@ export class ChangeType extends ModalAction {

static policy = 'volume:retype';

static allowed = (item) =>
Promise.resolve(isAvailableOrInUse(item) && !isOsDisk(item));
static allowed = (item) => Promise.resolve(canChangeType(item));

// A batch button is enabled on any selection, so re-check each one here.
static disableSubmit = ({ items }) =>
isArray(items) && items.some((it) => !canChangeType(it));

get isBatch() {
const { items } = this.props;
return isArray(items) && items.length > 0;
}

get selectedVolumes() {
return this.isBatch ? this.props.items : [this.item];
}

get currentTypes() {
return uniq(
this.selectedVolumes.map((it) => it.volume_type).filter((it) => !!it)
);
}

// Mixed selections keep every type on offer, so some volumes may already be
// on the chosen one.
get skipsSameType() {
return this.currentTypes.length > 1;
}

get blockedVolumes() {
return this.selectedVolumes.filter((it) => !canChangeType(it));
}

get tips() {
return t(
'If the capacity of the disk is large, the type modify operation may take several hours. Please be cautious.'
const tips = [
t(
'If the capacity of the disk is large, the type modify operation may take several hours. Please be cautious.'
),
];
if (this.skipsSameType) {
tips.push(t('Volumes already using the selected type are skipped.'));
}
if (this.blockedVolumes.length) {
tips.push(
t(
'The following volumes can not change type and need to be deselected: {names}',
{ names: this.getNames(this.blockedVolumes) }
)
);
}
if (tips.length === 1) {
return tips[0];
}
return (
<>
{tips.map((it) => (
<div key={it}>{it}</div>
))}
</>
);
}

Expand All @@ -52,34 +110,65 @@ export class ChangeType extends ModalAction {
return true;
}

getNames = (volumes) => volumes.map((it) => it.name || it.id).join(', ');

get volumeTypes() {
const { volume_type } = this.item;
const { data = [] } = this.volumeTypeStore.list;
const list = data
.filter((it) => it.name !== volume_type)
.map((item) =>
// TODO: filter no current volume type
({ label: item.name, value: item.id })
);
return list;
const [onlyType] = this.currentTypes;
const excluded = this.currentTypes.length === 1 ? onlyType : null;
return data
.filter((it) => it.name !== excluded)
.map((item) => ({ label: item.name, value: item.id }));
}

// Volumes already on the target type would be refused by cinder.
getRetypeTargets(newType) {
const { data = [] } = this.volumeTypeStore.list;
const { name: targetName } = data.find((it) => it.id === newType) || {};
return this.selectedVolumes.filter(
(it) => canChangeType(it) && it.volume_type !== targetName
);
}

get instanceName() {
if (!this.isBatch) {
return this.item.name || this.itemId;
}
const { new_type } = this.values || {};
return this.getNames(this.getRetypeTargets(new_type));
}

get defaultValue() {
const { name, id, volume_type, size } = this.item;
const value = {
volume: `${name || id}(${volume_type} | ${size}GiB)`,
volume_type: (this.volumeTypes[0] || {}).value,
};
if (!this.isBatch) {
value.volume = `${name || id}(${volume_type} | ${size}GiB)`;
}
return value;
}

renderVolumes() {
return (
<div style={{ maxHeight: 160, overflowY: 'auto' }}>
{this.selectedVolumes.map((it) => (
<div key={it.id}>
{`${it.name || it.id}(${it.volume_type} | ${it.size}GiB)`}
</div>
))}
</div>
);
}

get formItems() {
return [
{
name: 'volume',
label: t('Volume'),
label: this.isBatch ? t('Volumes') : t('Volume'),
type: 'label',
iconType: 'volume',
content: this.isBatch ? this.renderVolumes() : undefined,
},
{
name: 'new_type',
Expand All @@ -92,13 +181,19 @@ export class ChangeType extends ModalAction {
}

onSubmit = (values) => {
const { id } = this.item;
const { new_type } = values;
const body = {
new_type,
migration_policy: 'on-demand',
};
return this.store.retype(id, body);
if (!this.isBatch) {
return this.store.retype(this.item.id, body);
}
return allSettled(
this.getRetypeTargets(new_type).map((it) =>
this.store.retype(it.id, body)
)
);
};
}

Expand Down
7 changes: 5 additions & 2 deletions src/pages/storage/containers/Volume/actions/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const actionConfigs = {
},
],
},
batchActions: [Delete],
batchActions: [ChangeType, Delete],
primaryActions: [Create, AcceptVolumeTransfer],
};

Expand Down Expand Up @@ -98,12 +98,15 @@ const adminConfig = {
{
action: UpdateStatus,
},
{
action: ChangeType,
},
{
action: Migrate,
},
],
},
batchActions: [Delete],
batchActions: [ChangeType, Delete],
primaryActions: [],
};

Expand Down
Loading