feature: Support upgrade cluster and show quota info when resize cluster
1. Add upgrade cluster action 2. Show quota info when resize cluster Change-Id: I58b33ebd669c91ed0ed6b27caf5c048aa262b042
This commit is contained in:
parent
5a45f54df3
commit
d5d14d7637
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Support upgrade cluster and show quota info when resize cluster
|
||||
|
||||
1. Add upgrade cluster action
|
||||
|
||||
2. Show quota info when resize cluster
|
@ -30,6 +30,11 @@ export class MagnumClient extends Base {
|
||||
key: 'actions/resize',
|
||||
method: 'post',
|
||||
},
|
||||
{
|
||||
name: 'upgrade',
|
||||
key: 'actions/upgrade',
|
||||
method: 'post',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -323,6 +323,7 @@
|
||||
"Change Type": "Change Type",
|
||||
"Change password": "Change password",
|
||||
"Change type": "Change type",
|
||||
"Changed Node Count": "Changed Node Count",
|
||||
"Channel": "Channel",
|
||||
"Chassis ID": "Chassis ID",
|
||||
"Check Can Live Migrate Destination": "Check Can Live Migrate Destination",
|
||||
@ -558,6 +559,8 @@
|
||||
"Current Flavor": "Current Flavor",
|
||||
"Current Host": "Current Host",
|
||||
"Current Interface": "Current Interface",
|
||||
"Current Master Node Count": "Current Master Node Count",
|
||||
"Current Node Count": "Current Node Count",
|
||||
"Current Password": "Current Password",
|
||||
"Current Path: ": "Current Path: ",
|
||||
"Current Project": "Current Project",
|
||||
@ -1580,6 +1583,7 @@
|
||||
"Node Name": "Node Name",
|
||||
"Node Spec": "Node Spec",
|
||||
"Nodes": "Nodes",
|
||||
"Nodes To Remove": "Nodes To Remove",
|
||||
"Norfolk Island": "Norfolk Island",
|
||||
"Normal": "Normal",
|
||||
"North Korea": "North Korea",
|
||||
@ -2309,6 +2313,7 @@
|
||||
"The amphora instance is required for load balancing service setup and is not recommended": "The amphora instance is required for load balancing service setup and is not recommended",
|
||||
"The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.": "The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.",
|
||||
"The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.": "The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.",
|
||||
"The changed node count can not be equal to the current value": "The changed node count can not be equal to the current value",
|
||||
"The command to execute": "The command to execute",
|
||||
"The container memory size in MiB": "The container memory size in MiB",
|
||||
"The container runtime tool to create container with": "The container runtime tool to create container with",
|
||||
@ -2514,6 +2519,7 @@
|
||||
"Updated At": "Updated At",
|
||||
"Updating": "Updating",
|
||||
"Updating Password": "Updating Password",
|
||||
"Upgrade Cluster": "Upgrade Cluster",
|
||||
"Upload File": "Upload File",
|
||||
"Upload Type": "Upload Type",
|
||||
"Upload progress": "Upload progress",
|
||||
|
@ -323,6 +323,7 @@
|
||||
"Change Type": "修改类型",
|
||||
"Change password": "修改密码",
|
||||
"Change type": "修改类型",
|
||||
"Changed Node Count": "修改后节点数量",
|
||||
"Channel": "信道",
|
||||
"Chassis ID": "机架ID",
|
||||
"Check Can Live Migrate Destination": "检查可以热迁移目标",
|
||||
@ -558,6 +559,8 @@
|
||||
"Current Flavor": "当前配置",
|
||||
"Current Host": "当前主机",
|
||||
"Current Interface": "当前接口",
|
||||
"Current Master Node Count": "当前主节点数量",
|
||||
"Current Node Count": "当前节点数量",
|
||||
"Current Password": "原密码",
|
||||
"Current Path: ": "当前路径:",
|
||||
"Current Project": "当前项目",
|
||||
@ -1580,6 +1583,7 @@
|
||||
"Node Name": "节点名称",
|
||||
"Node Spec": "节点规格",
|
||||
"Nodes": "节点",
|
||||
"Nodes To Remove": "指定要缩减的节点",
|
||||
"Norfolk Island": "诺福克岛",
|
||||
"Normal": "正常",
|
||||
"North Korea": "朝鲜",
|
||||
@ -1963,7 +1967,7 @@
|
||||
"Reset To Initial Value": "重置为初始值",
|
||||
"Reset failed, please retry": "重置失败,请重试",
|
||||
"Resize": "修改配置",
|
||||
"Resize Cluster": "调整集群大小",
|
||||
"Resize Cluster": "集群伸缩",
|
||||
"Resize Instance": "修改配置",
|
||||
"Resize Volume": "扩容硬盘",
|
||||
"Resized": "已修改配置",
|
||||
@ -2309,6 +2313,7 @@
|
||||
"The amphora instance is required for load balancing service setup and is not recommended": "amphora 相关的云主机为负载均衡服务搭建所需,不建议选择",
|
||||
"The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.": "绑定的浮动IP、网卡、云硬盘等资源将自动解绑。",
|
||||
"The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.": "证书包含证书的公钥和签名等信息,证书扩展名为”pem”或”crt”,您可直接输入证书内容或上传证书文件。",
|
||||
"The changed node count can not be equal to the current value": "变更后的节点数量不可以等于当前节点数量",
|
||||
"The command to execute": "要执行的命令",
|
||||
"The container memory size in MiB": "以 MiB 为单位的容器内存大小",
|
||||
"The container runtime tool to create container with": "用于创建容器的容器运行时工具",
|
||||
@ -2514,6 +2519,7 @@
|
||||
"Updated At": "更新于",
|
||||
"Updating": "更新中",
|
||||
"Updating Password": "更新密码中",
|
||||
"Upgrade Cluster": "升级集群",
|
||||
"Upload File": "上传文件",
|
||||
"Upload Type": "上传方式",
|
||||
"Upload progress": "上传进度",
|
||||
|
@ -11,12 +11,17 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import { toJS } from 'mobx';
|
||||
import { ModalAction } from 'src/containers/Action';
|
||||
import globalClustersStore from 'stores/magnum/clusters';
|
||||
import globalProjectStore from 'stores/keystone/project';
|
||||
|
||||
export class Resize extends ModalAction {
|
||||
init() {
|
||||
this.store = globalClustersStore;
|
||||
this.projectStore = globalProjectStore;
|
||||
this.state.quotaLoading = true;
|
||||
this.getQuota();
|
||||
}
|
||||
|
||||
static id = 'resize-cluster';
|
||||
@ -25,37 +30,158 @@ export class Resize extends ModalAction {
|
||||
|
||||
policy = 'cluster:resize';
|
||||
|
||||
static allowed() {
|
||||
return Promise.resolve(true);
|
||||
static get modalSize() {
|
||||
return 'middle';
|
||||
}
|
||||
|
||||
getModalSize() {
|
||||
return 'middle';
|
||||
}
|
||||
|
||||
static allowed(item) {
|
||||
const { status } = item;
|
||||
return Promise.resolve(status.includes('COMPLETE'));
|
||||
}
|
||||
|
||||
get name() {
|
||||
return t('Resize Cluster');
|
||||
}
|
||||
|
||||
static buttonText = t('Resize');
|
||||
get maxSize() {
|
||||
const { node_count = 0 } = this.item;
|
||||
|
||||
get defaultValue() {
|
||||
const { node_count } = this.item;
|
||||
const { instances: { left = 0 } = {} } =
|
||||
toJS(this.projectStore.novaQuota) || {};
|
||||
if (left === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return left + node_count;
|
||||
}
|
||||
|
||||
get showQuota() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async getQuota() {
|
||||
this.setState({
|
||||
quotaLoading: true,
|
||||
});
|
||||
await this.projectStore.fetchProjectNovaQuota();
|
||||
this.setState({
|
||||
quotaLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
get quotaInfo() {
|
||||
const { quotaLoading } = this.state;
|
||||
if (quotaLoading) {
|
||||
return [];
|
||||
}
|
||||
const { newNodes } = this.getNodesInput();
|
||||
const { instances = {} } = toJS(this.projectStore.novaQuota) || {};
|
||||
const { left } = instances;
|
||||
const instanceQuotaInfo = {
|
||||
...instances,
|
||||
add: left === 0 ? 0 : newNodes,
|
||||
name: 'instance',
|
||||
title: t('Instance'),
|
||||
};
|
||||
|
||||
const quotaInfo = [instanceQuotaInfo];
|
||||
|
||||
return quotaInfo;
|
||||
}
|
||||
|
||||
getNodesInput() {
|
||||
const { node_count = 0 } = this.item;
|
||||
const { changed_node_count = 0 } = this.state;
|
||||
const newNodes = changed_node_count - node_count;
|
||||
return {
|
||||
node_count: node_count || 1,
|
||||
newNodes: newNodes > 0 ? newNodes : 0,
|
||||
};
|
||||
}
|
||||
|
||||
get defaultValue() {
|
||||
const { node_count = 0, master_count = 0 } = this.item;
|
||||
|
||||
return {
|
||||
current_master_node_count: master_count,
|
||||
current_node_count: node_count,
|
||||
changed_node_count: node_count + 1,
|
||||
};
|
||||
}
|
||||
|
||||
get nameForStateUpdate() {
|
||||
return ['changed_node_count'];
|
||||
}
|
||||
|
||||
get nodeAddressOptions() {
|
||||
const { node_addresses = [] } = this.item;
|
||||
return node_addresses.map((it) => ({
|
||||
label: it,
|
||||
value: it,
|
||||
}));
|
||||
}
|
||||
|
||||
get formItems() {
|
||||
const { changed_node_count } = this.state;
|
||||
const { node_count = 0 } = this.item;
|
||||
|
||||
return [
|
||||
{
|
||||
name: 'node_count',
|
||||
label: t('Node Count'),
|
||||
name: 'current_master_node_count',
|
||||
label: t('Current Master Node Count'),
|
||||
type: 'label',
|
||||
},
|
||||
{
|
||||
name: 'current_node_count',
|
||||
label: t('Current Node Count'),
|
||||
type: 'label',
|
||||
},
|
||||
{
|
||||
name: 'changed_node_count',
|
||||
label: t('Changed Node Count'),
|
||||
type: 'input-int',
|
||||
min: 1,
|
||||
max: this.maxSize,
|
||||
required: true,
|
||||
validator: (rule, value) => {
|
||||
if (value === node_count) {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
t(
|
||||
'The changed node count can not be equal to the current value'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'nodes_to_remove',
|
||||
label: t('Nodes To Remove'),
|
||||
type: 'select',
|
||||
mode: 'multiple',
|
||||
options: this.nodeAddressOptions,
|
||||
display: changed_node_count < node_count,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
onSubmit = (data) => {
|
||||
this.store.resize({ id: this.item.id }, data);
|
||||
onSubmit = (values) => {
|
||||
const { changed_node_count, nodes_to_remove } = values;
|
||||
|
||||
const body = {
|
||||
node_count: changed_node_count,
|
||||
nodes_to_remove: [],
|
||||
};
|
||||
if (nodes_to_remove && nodes_to_remove.length) {
|
||||
body.nodes_to_remove = nodes_to_remove;
|
||||
}
|
||||
|
||||
this.store.resize({ id: this.item.id }, body);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,80 @@
|
||||
// Licensed 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.
|
||||
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import { ModalAction } from 'containers/Action';
|
||||
import { ClustersStore } from 'stores/magnum/clusters';
|
||||
import { ClusterTemplatesStore } from 'stores/magnum/clusterTemplates';
|
||||
import { getBaseTemplateColumns } from 'resources/magnum/template';
|
||||
|
||||
export class Upgrade extends ModalAction {
|
||||
static id = 'upgrade-cluster';
|
||||
|
||||
static title = t('Upgrade Cluster');
|
||||
|
||||
static policy = 'cluster:upgrade';
|
||||
|
||||
static allowed = () => Promise.resolve(true);
|
||||
|
||||
static get modalSize() {
|
||||
return 'large';
|
||||
}
|
||||
|
||||
getModalSize() {
|
||||
return 'large';
|
||||
}
|
||||
|
||||
init() {
|
||||
this.store = new ClustersStore();
|
||||
this.templateStore = new ClusterTemplatesStore();
|
||||
this.getClustertemplates();
|
||||
}
|
||||
|
||||
async getClustertemplates() {
|
||||
await this.templateStore.fetchList();
|
||||
}
|
||||
|
||||
get clusterTemplates() {
|
||||
return this.templateStore.list.data || [];
|
||||
}
|
||||
|
||||
get formItems() {
|
||||
return [
|
||||
{
|
||||
name: 'clusterTemplate',
|
||||
label: t('Cluster Template'),
|
||||
type: 'select-table',
|
||||
data: this.clusterTemplates,
|
||||
isLoading: this.templateStore.list.isLoading,
|
||||
required: true,
|
||||
filterParams: [
|
||||
{
|
||||
label: t('Name'),
|
||||
name: 'name',
|
||||
},
|
||||
],
|
||||
columns: getBaseTemplateColumns(this),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
onSubmit = (values) => {
|
||||
const { clusterTemplate } = values;
|
||||
const { selectedRowKeys = [] } = clusterTemplate;
|
||||
const data = {
|
||||
cluster_template: selectedRowKeys[0],
|
||||
};
|
||||
return this.store.upgrade({ id: this.item.id }, data);
|
||||
};
|
||||
}
|
||||
|
||||
export default inject('rootStore')(observer(Upgrade));
|
@ -41,6 +41,13 @@ export class Clusters extends Base {
|
||||
return false;
|
||||
}
|
||||
|
||||
updateFetchParams = (params) => {
|
||||
return {
|
||||
...params,
|
||||
shouldFetchProject: this.isAdminPage,
|
||||
};
|
||||
};
|
||||
|
||||
get actionConfigs() {
|
||||
if (this.isAdminPage) {
|
||||
return actionConfigs.actionConfigsAdmin;
|
||||
|
@ -61,6 +61,10 @@ export class ClustersStore extends Base {
|
||||
return this.client.resize(id, newbody);
|
||||
}
|
||||
|
||||
async upgrade({ id }, body) {
|
||||
return this.client.upgrade(id, body);
|
||||
}
|
||||
|
||||
async listDidFetch(items, _, filters) {
|
||||
if (!items.length) return items;
|
||||
const { shouldFetchProject } = filters;
|
||||
|
Loading…
x
Reference in New Issue
Block a user