feature: Support quota in magnum service
1.Show quota info when create cluster 2.Support quota setting of magnum cluster when manage project quota Change-Id: I90d1bc3c2bcb2aa95d728c245dd1b742d3fe6ae1
This commit is contained in:
parent
719e26ebaa
commit
7a4d17ee19
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Support Quota of Magnum cluster
|
||||||
|
|
||||||
|
1. Show quota info when create cluster
|
||||||
|
|
||||||
|
2. Support quota setting of magnum cluster when manage project quota
|
@ -37,6 +37,22 @@ export class MagnumClient extends Base {
|
|||||||
key: 'clustertemplates',
|
key: 'clustertemplates',
|
||||||
responseKey: 'clustertemplate',
|
responseKey: 'clustertemplate',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'quotas',
|
||||||
|
subResources: [
|
||||||
|
{
|
||||||
|
name: 'cluster',
|
||||||
|
key: 'Cluster',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
extendOperations: [
|
||||||
|
{
|
||||||
|
name: 'updateQuota',
|
||||||
|
key: 'Cluster',
|
||||||
|
method: 'patch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -918,14 +918,14 @@ const renderMenu = (t) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/container-infra/clusters-admin',
|
path: '/container-infra/clusters-admin',
|
||||||
name: t('Cluster Instance'),
|
name: t('Clusters'),
|
||||||
key: 'containerInfraClustersAdmin',
|
key: 'containerInfraClustersAdmin',
|
||||||
endpoints: 'magnum',
|
endpoints: 'magnum',
|
||||||
level: 1,
|
level: 1,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: /^\/container-infra\/clusters-admin\/detail\/.[^/]+$/,
|
path: /^\/container-infra\/clusters-admin\/detail\/.[^/]+$/,
|
||||||
name: t('Cluster Instance Detail'),
|
name: t('Cluster Detail'),
|
||||||
key: 'containerInfraClusterDetailAdmin',
|
key: 'containerInfraClusterDetailAdmin',
|
||||||
level: 2,
|
level: 2,
|
||||||
routePath: '/container-infra/clusters-admin/detail/:id',
|
routePath: '/container-infra/clusters-admin/detail/:id',
|
||||||
|
@ -285,7 +285,6 @@
|
|||||||
"CPU Usages (Core)": "CPU Usages (Core)",
|
"CPU Usages (Core)": "CPU Usages (Core)",
|
||||||
"CPU value is { cpu }, NUMA CPU value is { totalCpu }, need to be equal. ": "CPU value is { cpu }, NUMA CPU value is { totalCpu }, need to be equal. ",
|
"CPU value is { cpu }, NUMA CPU value is { totalCpu }, need to be equal. ": "CPU value is { cpu }, NUMA CPU value is { totalCpu }, need to be equal. ",
|
||||||
"CPU(Core)": "CPU(Core)",
|
"CPU(Core)": "CPU(Core)",
|
||||||
"CPUs": "CPUs",
|
|
||||||
"CREATE COMPLETE": "CREATE COMPLETE",
|
"CREATE COMPLETE": "CREATE COMPLETE",
|
||||||
"CREATE FAILED": "CREATE FAILED",
|
"CREATE FAILED": "CREATE FAILED",
|
||||||
"CREATE IN PROGRESS": "CREATE IN PROGRESS",
|
"CREATE IN PROGRESS": "CREATE IN PROGRESS",
|
||||||
@ -361,8 +360,6 @@
|
|||||||
"Cluster Detail": "Cluster Detail",
|
"Cluster Detail": "Cluster Detail",
|
||||||
"Cluster Distro": "Cluster Distro",
|
"Cluster Distro": "Cluster Distro",
|
||||||
"Cluster Info": "Cluster Info",
|
"Cluster Info": "Cluster Info",
|
||||||
"Cluster Instance": "Cluster Instance",
|
|
||||||
"Cluster Instance Detail": "Cluster Instance Detail",
|
|
||||||
"Cluster Management": "Cluster Management",
|
"Cluster Management": "Cluster Management",
|
||||||
"Cluster Name": "Cluster Name",
|
"Cluster Name": "Cluster Name",
|
||||||
"Cluster Network": "Cluster Network",
|
"Cluster Network": "Cluster Network",
|
||||||
@ -372,6 +369,7 @@
|
|||||||
"Cluster Templates": "Cluster Templates",
|
"Cluster Templates": "Cluster Templates",
|
||||||
"Cluster Type": "Cluster Type",
|
"Cluster Type": "Cluster Type",
|
||||||
"Clusters": "Clusters",
|
"Clusters": "Clusters",
|
||||||
|
"Clusters Management": "Clusters Management",
|
||||||
"Cocos (Keeling) Islands": "Cocos (Keeling) Islands",
|
"Cocos (Keeling) Islands": "Cocos (Keeling) Islands",
|
||||||
"Code": "Code",
|
"Code": "Code",
|
||||||
"Cold Migrate": "Cold Migrate",
|
"Cold Migrate": "Cold Migrate",
|
||||||
@ -442,9 +440,11 @@
|
|||||||
"Container Stopping": "Container Stopping",
|
"Container Stopping": "Container Stopping",
|
||||||
"Container Version": "Container Version",
|
"Container Version": "Container Version",
|
||||||
"Containers": "Containers",
|
"Containers": "Containers",
|
||||||
|
"Containers CPU": "Containers CPU",
|
||||||
"Containers Disk (GiB)": "Containers Disk (GiB)",
|
"Containers Disk (GiB)": "Containers Disk (GiB)",
|
||||||
"Containers Info": "Containers Info",
|
"Containers Info": "Containers Info",
|
||||||
"Containers Management": "Containers Management",
|
"Containers Management": "Containers Management",
|
||||||
|
"Containers Memory (MiB)": "Containers Memory (MiB)",
|
||||||
"Content": "Content",
|
"Content": "Content",
|
||||||
"Content Type": "Content Type",
|
"Content Type": "Content Type",
|
||||||
"Control Location": "Control Location",
|
"Control Location": "Control Location",
|
||||||
@ -635,8 +635,8 @@
|
|||||||
"Delete Bandwidth Ingress Rules": "Delete Bandwidth Ingress Rules",
|
"Delete Bandwidth Ingress Rules": "Delete Bandwidth Ingress Rules",
|
||||||
"Delete Capsule": "Delete Capsule",
|
"Delete Capsule": "Delete Capsule",
|
||||||
"Delete Certificate": "Delete Certificate",
|
"Delete Certificate": "Delete Certificate",
|
||||||
"Delete Clusters": "Delete Clusters",
|
"Delete Cluster": "Delete Cluster",
|
||||||
"Delete Clusters Templates": "Delete Clusters Templates",
|
"Delete Cluster Template": "Delete Cluster Template",
|
||||||
"Delete Complete": "Delete Complete",
|
"Delete Complete": "Delete Complete",
|
||||||
"Delete Configuration": "Delete Configuration",
|
"Delete Configuration": "Delete Configuration",
|
||||||
"Delete Container": "Delete Container",
|
"Delete Container": "Delete Container",
|
||||||
@ -686,7 +686,6 @@
|
|||||||
"Delete Share Type": "Delete Share Type",
|
"Delete Share Type": "Delete Share Type",
|
||||||
"Delete Static Route": "Delete Static Route",
|
"Delete Static Route": "Delete Static Route",
|
||||||
"Delete Subnet": "Delete Subnet",
|
"Delete Subnet": "Delete Subnet",
|
||||||
"Delete Template": "Delete Template",
|
|
||||||
"Delete User": "Delete User",
|
"Delete User": "Delete User",
|
||||||
"Delete VPN": "Delete VPN",
|
"Delete VPN": "Delete VPN",
|
||||||
"Delete VPN EndPoint Groups": "Delete VPN EndPoint Groups",
|
"Delete VPN EndPoint Groups": "Delete VPN EndPoint Groups",
|
||||||
@ -2326,6 +2325,7 @@
|
|||||||
"The ip of external members can be any, including the public network ip.": "The ip of external members can be any, including the public network ip.",
|
"The ip of external members can be any, including the public network ip.": "The ip of external members can be any, including the public network ip.",
|
||||||
"The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.": "The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.",
|
"The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.": "The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.",
|
||||||
"The kill signal to send": "The kill signal to send",
|
"The kill signal to send": "The kill signal to send",
|
||||||
|
"The limit of cluster instance greater than or equal to 1.": "The limit of cluster instance greater than or equal to 1.",
|
||||||
"The maximum batch size is {size}, that is, the size of the port range cannot exceed {size}.": "The maximum batch size is {size}, that is, the size of the port range cannot exceed {size}.",
|
"The maximum batch size is {size}, that is, the size of the port range cannot exceed {size}.": "The maximum batch size is {size}, that is, the size of the port range cannot exceed {size}.",
|
||||||
"The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.": "The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.",
|
"The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.": "The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.",
|
||||||
"The min size is {size} GiB": "The min size is {size} GiB",
|
"The min size is {size} GiB": "The min size is {size} GiB",
|
||||||
|
@ -285,7 +285,6 @@
|
|||||||
"CPU Usages (Core)": "CPU用量 (核)",
|
"CPU Usages (Core)": "CPU用量 (核)",
|
||||||
"CPU value is { cpu }, NUMA CPU value is { totalCpu }, need to be equal. ": "CPU核数是 { cpu },NUMA节点的CPU核数是{ totalCpu },需要一致。",
|
"CPU value is { cpu }, NUMA CPU value is { totalCpu }, need to be equal. ": "CPU核数是 { cpu },NUMA节点的CPU核数是{ totalCpu },需要一致。",
|
||||||
"CPU(Core)": "CPU(核数)",
|
"CPU(Core)": "CPU(核数)",
|
||||||
"CPUs": "CPU",
|
|
||||||
"CREATE COMPLETE": "创建完成",
|
"CREATE COMPLETE": "创建完成",
|
||||||
"CREATE FAILED": "创建失败",
|
"CREATE FAILED": "创建失败",
|
||||||
"CREATE IN PROGRESS": "创建中",
|
"CREATE IN PROGRESS": "创建中",
|
||||||
@ -361,8 +360,6 @@
|
|||||||
"Cluster Detail": "集群详情",
|
"Cluster Detail": "集群详情",
|
||||||
"Cluster Distro": "集群发行版",
|
"Cluster Distro": "集群发行版",
|
||||||
"Cluster Info": "集群信息",
|
"Cluster Info": "集群信息",
|
||||||
"Cluster Instance": "集群实例",
|
|
||||||
"Cluster Instance Detail": "集群实例详情",
|
|
||||||
"Cluster Management": "集群管理",
|
"Cluster Management": "集群管理",
|
||||||
"Cluster Name": "集群名称",
|
"Cluster Name": "集群名称",
|
||||||
"Cluster Network": "集群网络",
|
"Cluster Network": "集群网络",
|
||||||
@ -372,6 +369,7 @@
|
|||||||
"Cluster Templates": "集群模板",
|
"Cluster Templates": "集群模板",
|
||||||
"Cluster Type": "集群类型",
|
"Cluster Type": "集群类型",
|
||||||
"Clusters": "集群",
|
"Clusters": "集群",
|
||||||
|
"Clusters Management": "集群管理",
|
||||||
"Cocos (Keeling) Islands": "科科斯群岛",
|
"Cocos (Keeling) Islands": "科科斯群岛",
|
||||||
"Code": "编码",
|
"Code": "编码",
|
||||||
"Cold Migrate": "冷迁移",
|
"Cold Migrate": "冷迁移",
|
||||||
@ -442,9 +440,11 @@
|
|||||||
"Container Stopping": "容器关闭中",
|
"Container Stopping": "容器关闭中",
|
||||||
"Container Version": "容器版本",
|
"Container Version": "容器版本",
|
||||||
"Containers": "容器",
|
"Containers": "容器",
|
||||||
|
"Containers CPU": "容器 CPU",
|
||||||
"Containers Disk (GiB)": "容器硬盘 (GiB)",
|
"Containers Disk (GiB)": "容器硬盘 (GiB)",
|
||||||
"Containers Info": "容器信息",
|
"Containers Info": "容器信息",
|
||||||
"Containers Management": "容器管理",
|
"Containers Management": "容器管理",
|
||||||
|
"Containers Memory (MiB)": "容器内存 (MiB)",
|
||||||
"Content": "内容",
|
"Content": "内容",
|
||||||
"Content Type": "内容类型",
|
"Content Type": "内容类型",
|
||||||
"Control Location": "控制端",
|
"Control Location": "控制端",
|
||||||
@ -635,8 +635,8 @@
|
|||||||
"Delete Bandwidth Ingress Rules": "删除带宽入方向限制",
|
"Delete Bandwidth Ingress Rules": "删除带宽入方向限制",
|
||||||
"Delete Capsule": "删除集合",
|
"Delete Capsule": "删除集合",
|
||||||
"Delete Certificate": "删除证书",
|
"Delete Certificate": "删除证书",
|
||||||
"Delete Clusters": "删除集群",
|
"Delete Cluster": "删除集群",
|
||||||
"Delete Clusters Templates": "删除集群模板",
|
"Delete Cluster Template": "删除集群模板",
|
||||||
"Delete Complete": "删除完成",
|
"Delete Complete": "删除完成",
|
||||||
"Delete Configuration": "删除配置",
|
"Delete Configuration": "删除配置",
|
||||||
"Delete Container": "删除容器",
|
"Delete Container": "删除容器",
|
||||||
@ -686,7 +686,6 @@
|
|||||||
"Delete Share Type": "删除共享类型",
|
"Delete Share Type": "删除共享类型",
|
||||||
"Delete Static Route": "删除静态路由",
|
"Delete Static Route": "删除静态路由",
|
||||||
"Delete Subnet": "删除子网",
|
"Delete Subnet": "删除子网",
|
||||||
"Delete Template": "删除模板",
|
|
||||||
"Delete User": "删除用户",
|
"Delete User": "删除用户",
|
||||||
"Delete VPN": "删除VPN",
|
"Delete VPN": "删除VPN",
|
||||||
"Delete VPN EndPoint Groups": "删除VPN端点组",
|
"Delete VPN EndPoint Groups": "删除VPN端点组",
|
||||||
@ -2326,6 +2325,7 @@
|
|||||||
"The ip of external members can be any, including the public network ip.": "外部成员的IP可以是任何IP,包括公网IP。",
|
"The ip of external members can be any, including the public network ip.": "外部成员的IP可以是任何IP,包括公网IP。",
|
||||||
"The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.": "密钥对允许您SSH到您新创建的实例。 您可以选择一个已存在的密钥对、导入一个密钥对或生成一个新的密钥对。",
|
"The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.": "密钥对允许您SSH到您新创建的实例。 您可以选择一个已存在的密钥对、导入一个密钥对或生成一个新的密钥对。",
|
||||||
"The kill signal to send": "要发送的终止信号",
|
"The kill signal to send": "要发送的终止信号",
|
||||||
|
"The limit of cluster instance greater than or equal to 1.": "集群实例的配额必须大于或者等于1。",
|
||||||
"The maximum batch size is {size}, that is, the size of the port range cannot exceed {size}.": "批量的上限为{size}个,即端口范围大小不可超过{size}。",
|
"The maximum batch size is {size}, that is, the size of the port range cannot exceed {size}.": "批量的上限为{size}个,即端口范围大小不可超过{size}。",
|
||||||
"The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.": "地址片段的最大传输单位。IPv4最小68,IPv6最小1280。",
|
"The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.": "地址片段的最大传输单位。IPv4最小68,IPv6最小1280。",
|
||||||
"The min size is {size} GiB": "最小内存为 {size} GiB",
|
"The min size is {size} GiB": "最小内存为 {size} GiB",
|
||||||
|
@ -112,12 +112,23 @@ export const zunQuotaCard = {
|
|||||||
text: t('Containers'),
|
text: t('Containers'),
|
||||||
key: 'zun_containers',
|
key: 'zun_containers',
|
||||||
},
|
},
|
||||||
{ text: t('CPUs'), key: 'zun_cpu' },
|
{ text: t('Containers CPU'), key: 'zun_cpu' },
|
||||||
{ text: t('Memory (MiB)'), key: 'zun_memory' },
|
{ text: t('Containers Memory (MiB)'), key: 'zun_memory' },
|
||||||
{ text: t('Containers Disk (GiB)'), key: 'zun_disk' },
|
{ text: t('Containers Disk (GiB)'), key: 'zun_disk' },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const magnumQuotaCard = {
|
||||||
|
text: t('Clusters Management'),
|
||||||
|
type: 'magnum',
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
text: t('Clusters'),
|
||||||
|
key: 'magnum_cluster',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
export const troveQuotaCard = {
|
export const troveQuotaCard = {
|
||||||
text: t('Database'),
|
text: t('Database'),
|
||||||
type: 'trove',
|
type: 'trove',
|
||||||
@ -210,6 +221,10 @@ export class QuotaOverview extends Component {
|
|||||||
return globalRootStore.checkEndpoint('zun');
|
return globalRootStore.checkEndpoint('zun');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get enableMagnum() {
|
||||||
|
return globalRootStore.checkEndpoint('magnum');
|
||||||
|
}
|
||||||
|
|
||||||
get enableTrove() {
|
get enableTrove() {
|
||||||
return (
|
return (
|
||||||
globalRootStore.checkEndpoint('trove') && globalRootStore.hasAdminOnlyRole
|
globalRootStore.checkEndpoint('trove') && globalRootStore.hasAdminOnlyRole
|
||||||
@ -237,6 +252,9 @@ export class QuotaOverview extends Component {
|
|||||||
if (this.enableZun) {
|
if (this.enableZun) {
|
||||||
newList.push(zunQuotaCard);
|
newList.push(zunQuotaCard);
|
||||||
}
|
}
|
||||||
|
if (this.enableMagnum) {
|
||||||
|
newList.push(magnumQuotaCard);
|
||||||
|
}
|
||||||
if (this.enableTrove) {
|
if (this.enableTrove) {
|
||||||
newList.push(troveQuotaCard);
|
newList.push(troveQuotaCard);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ export class StepCreate extends StepAction {
|
|||||||
});
|
});
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.projectStore.fetchProjectNovaQuota(),
|
this.projectStore.fetchProjectNovaQuota(),
|
||||||
this.projectStore.fetchProjectCinderQuota(),
|
this.enableCinder ? this.projectStore.fetchProjectCinderQuota() : null,
|
||||||
]);
|
]);
|
||||||
this.setState({
|
this.setState({
|
||||||
quotaLoading: false,
|
quotaLoading: false,
|
||||||
|
@ -19,11 +19,11 @@ export default class Delete extends ConfirmAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
return t('Delete Template');
|
return t('Delete Cluster Template');
|
||||||
}
|
}
|
||||||
|
|
||||||
get actionName() {
|
get actionName() {
|
||||||
return t('Delete Clusters Templates');
|
return t('Delete Cluster Template');
|
||||||
}
|
}
|
||||||
|
|
||||||
get isDanger() {
|
get isDanger() {
|
||||||
|
@ -21,11 +21,11 @@ export default class DeleteClusters extends ConfirmAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
return t('Delete Clusters');
|
return t('Delete Cluster');
|
||||||
}
|
}
|
||||||
|
|
||||||
get actionName() {
|
get actionName() {
|
||||||
return t('Delete Clusters');
|
return t('Delete Cluster');
|
||||||
}
|
}
|
||||||
|
|
||||||
get buttonText() {
|
get buttonText() {
|
||||||
|
@ -113,6 +113,11 @@ export class StepNodeSpec extends Base {
|
|||||||
type: 'input-int',
|
type: 'input-int',
|
||||||
min: 1,
|
min: 1,
|
||||||
required: true,
|
required: true,
|
||||||
|
onChange: (value) => {
|
||||||
|
this.updateContext({
|
||||||
|
master_count: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'masterFlavor',
|
name: 'masterFlavor',
|
||||||
@ -131,6 +136,11 @@ export class StepNodeSpec extends Base {
|
|||||||
type: 'input-int',
|
type: 'input-int',
|
||||||
min: 1,
|
min: 1,
|
||||||
required: true,
|
required: true,
|
||||||
|
onChange: (value) => {
|
||||||
|
this.updateContext({
|
||||||
|
node_count: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'flavor',
|
name: 'flavor',
|
||||||
|
@ -11,8 +11,12 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { inject, observer } from 'mobx-react';
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import { toJS } from 'mobx';
|
||||||
import { StepAction } from 'src/containers/Action';
|
import { StepAction } from 'src/containers/Action';
|
||||||
import globalClustersStore from 'src/stores/magnum/clusters';
|
import globalClustersStore from 'src/stores/magnum/clusters';
|
||||||
|
import globalProjectStore from 'stores/keystone/project';
|
||||||
|
import { getGiBValue } from 'utils';
|
||||||
|
import { message as $message } from 'antd';
|
||||||
import StepInfo from './StepInfo';
|
import StepInfo from './StepInfo';
|
||||||
import StepNodeSpec from './StepNodeSpec';
|
import StepNodeSpec from './StepNodeSpec';
|
||||||
import StepNetworks from './StepNetworks';
|
import StepNetworks from './StepNetworks';
|
||||||
@ -22,6 +26,10 @@ import StepLabel from './StepLabel';
|
|||||||
export class StepCreate extends StepAction {
|
export class StepCreate extends StepAction {
|
||||||
init() {
|
init() {
|
||||||
this.store = globalClustersStore;
|
this.store = globalClustersStore;
|
||||||
|
this.projectStore = globalProjectStore;
|
||||||
|
this.state.quotaLoading = true;
|
||||||
|
this.getQuota();
|
||||||
|
this.errorMsg = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static id = 'create-cluster';
|
static id = 'create-cluster';
|
||||||
@ -37,7 +45,7 @@ export class StepCreate extends StepAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return t('Create Instance');
|
return t('Create Cluster');
|
||||||
}
|
}
|
||||||
|
|
||||||
get listUrl() {
|
get listUrl() {
|
||||||
@ -73,6 +81,170 @@ export class StepCreate extends StepAction {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get enableCinder() {
|
||||||
|
return this.props.rootStore.checkEndpoint('cinder');
|
||||||
|
}
|
||||||
|
|
||||||
|
get showQuota() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getQuota() {
|
||||||
|
this.setState({
|
||||||
|
quotaLoading: true,
|
||||||
|
});
|
||||||
|
await Promise.all([
|
||||||
|
this.projectStore.fetchProjectNovaQuota(),
|
||||||
|
this.projectStore.fetchProjectMagnumQuota(),
|
||||||
|
this.enableCinder ? this.projectStore.fetchProjectCinderQuota() : null,
|
||||||
|
]);
|
||||||
|
this.setState({
|
||||||
|
quotaLoading: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get disableNext() {
|
||||||
|
return !!this.errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
get disableSubmit() {
|
||||||
|
return !!this.errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
get quotaInfo() {
|
||||||
|
const { quotaLoading } = this.state;
|
||||||
|
if (quotaLoading) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const quotaError = this.checkQuotaInput();
|
||||||
|
|
||||||
|
const { magnum_cluster = {} } = toJS(this.projectStore.magnumQuota) || {};
|
||||||
|
const clusterQuotaInfo = {
|
||||||
|
...magnum_cluster,
|
||||||
|
add: quotaError ? 0 : 1,
|
||||||
|
name: 'cluster',
|
||||||
|
title: t('Clusters'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const {
|
||||||
|
instances = {},
|
||||||
|
cores = {},
|
||||||
|
ram = {},
|
||||||
|
} = toJS(this.projectStore.novaQuota) || {};
|
||||||
|
const instanceQuotaInfo = {
|
||||||
|
...instances,
|
||||||
|
add: quotaError ? 0 : 1,
|
||||||
|
name: 'instance',
|
||||||
|
title: t('Instance'),
|
||||||
|
type: 'line',
|
||||||
|
};
|
||||||
|
|
||||||
|
const { newCPU, newRam } = this.getFlavorInput();
|
||||||
|
const cpuQuotaInfo = {
|
||||||
|
...cores,
|
||||||
|
add: quotaError ? 0 : newCPU,
|
||||||
|
name: 'cpu',
|
||||||
|
title: t('CPU'),
|
||||||
|
type: 'line',
|
||||||
|
};
|
||||||
|
|
||||||
|
const ramQuotaInfo = {
|
||||||
|
...ram,
|
||||||
|
add: quotaError ? 0 : newRam,
|
||||||
|
name: 'ram',
|
||||||
|
title: t('Memory (GiB)'),
|
||||||
|
type: 'line',
|
||||||
|
};
|
||||||
|
|
||||||
|
const quotaInfo = [
|
||||||
|
clusterQuotaInfo,
|
||||||
|
instanceQuotaInfo,
|
||||||
|
cpuQuotaInfo,
|
||||||
|
ramQuotaInfo,
|
||||||
|
];
|
||||||
|
|
||||||
|
return quotaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkInstanceQuota() {
|
||||||
|
const { quotaLoading } = this.state;
|
||||||
|
if (quotaLoading) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const { instances = {} } = this.projectStore.novaQuota || {};
|
||||||
|
const { left = 0 } = instances;
|
||||||
|
if (left === 0) {
|
||||||
|
return this.getQuotaMessage(1, instances, t('Instance'));
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
getFlavorInput() {
|
||||||
|
const { data = {} } = this.state;
|
||||||
|
const {
|
||||||
|
flavor: { selectedRows = [] } = {},
|
||||||
|
node_count = 1,
|
||||||
|
masterFlavor: { selectedRows: selectedRowsMaster = [] } = {},
|
||||||
|
master_count = 1,
|
||||||
|
} = data;
|
||||||
|
const { vcpus = 0, ram = 0 } = selectedRows[0] || {};
|
||||||
|
const ramGiB = getGiBValue(ram);
|
||||||
|
const { vcpus: vcpusMaster = 0, ram: ramMaster = 0 } =
|
||||||
|
selectedRowsMaster[0] || {};
|
||||||
|
const ramGiBMaster = getGiBValue(ramMaster);
|
||||||
|
const newCPU = vcpus * node_count + vcpusMaster * master_count;
|
||||||
|
const newRam = ramGiB * node_count + ramGiBMaster * master_count;
|
||||||
|
return {
|
||||||
|
newCPU,
|
||||||
|
newRam,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
checkFlavorQuota() {
|
||||||
|
const { newCPU, newRam } = this.getFlavorInput();
|
||||||
|
const { cores = {}, ram = {} } = this.projectStore.novaQuota || {};
|
||||||
|
const { left = 0 } = cores || {};
|
||||||
|
const { left: leftRam = 0 } = ram || {};
|
||||||
|
if (left !== -1 && left < newCPU) {
|
||||||
|
return this.getQuotaMessage(newCPU, cores, t('CPU'));
|
||||||
|
}
|
||||||
|
if (leftRam !== -1 && leftRam < newRam) {
|
||||||
|
return this.getQuotaMessage(newRam, ram, t('Memory'));
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
checkQuotaInput() {
|
||||||
|
const instanceMsg = this.checkInstanceQuota();
|
||||||
|
const flavorMsg = this.checkFlavorQuota();
|
||||||
|
const error = instanceMsg || flavorMsg;
|
||||||
|
if (!error) {
|
||||||
|
this.status = 'success';
|
||||||
|
this.errorMsg = '';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
this.status = 'error';
|
||||||
|
if (this.errorMsg !== error) {
|
||||||
|
$message.error(error);
|
||||||
|
}
|
||||||
|
this.errorMsg = error;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
getQuotaMessage(value, quota, name) {
|
||||||
|
const { left = 0 } = quota || {};
|
||||||
|
if (left === -1) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (value > left) {
|
||||||
|
return t(
|
||||||
|
'Insufficient {name} quota to create resources(left { quota }, input { input }).',
|
||||||
|
{ name, quota: left, input: value }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
onSubmit = (values) => {
|
onSubmit = (values) => {
|
||||||
const {
|
const {
|
||||||
additionalLabels,
|
additionalLabels,
|
||||||
|
@ -123,7 +123,7 @@ export class StepCreate extends StepAction {
|
|||||||
...cpu,
|
...cpu,
|
||||||
add: canAdd ? cpuCount : 0,
|
add: canAdd ? cpuCount : 0,
|
||||||
name: 'cpu',
|
name: 'cpu',
|
||||||
title: t('CPU'),
|
title: t('Containers CPU'),
|
||||||
type: 'line',
|
type: 'line',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ export class StepCreate extends StepAction {
|
|||||||
...memory,
|
...memory,
|
||||||
add: canAdd ? memoryCount : 0,
|
add: canAdd ? memoryCount : 0,
|
||||||
name: 'memory',
|
name: 'memory',
|
||||||
title: t('Memory (MiB)'),
|
title: t('Containers Memory (MiB)'),
|
||||||
type: 'line',
|
type: 'line',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ export class StepCreate extends StepAction {
|
|||||||
...disk,
|
...disk,
|
||||||
add: canAdd ? diskCount : 0,
|
add: canAdd ? diskCount : 0,
|
||||||
name: 'disk',
|
name: 'disk',
|
||||||
title: t('Disk (GiB)'),
|
title: t('Containers Disk (GiB)'),
|
||||||
type: 'line',
|
type: 'line',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import { inject, observer } from 'mobx-react';
|
import { inject, observer } from 'mobx-react';
|
||||||
import globalProjectStore, { ProjectStore } from 'stores/keystone/project';
|
import globalProjectStore, { ProjectStore } from 'stores/keystone/project';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Spin } from 'antd';
|
||||||
import { ModalAction } from 'containers/Action';
|
import { ModalAction } from 'containers/Action';
|
||||||
import { VolumeTypeStore } from 'stores/cinder/volume-type';
|
import { VolumeTypeStore } from 'stores/cinder/volume-type';
|
||||||
import {
|
import {
|
||||||
@ -23,6 +24,7 @@ import {
|
|||||||
shareQuotaCard,
|
shareQuotaCard,
|
||||||
zunQuotaCard,
|
zunQuotaCard,
|
||||||
troveQuotaCard,
|
troveQuotaCard,
|
||||||
|
magnumQuotaCard,
|
||||||
} from 'pages/base/containers/Overview/components/QuotaOverview';
|
} from 'pages/base/containers/Overview/components/QuotaOverview';
|
||||||
|
|
||||||
export class ManageQuota extends ModalAction {
|
export class ManageQuota extends ModalAction {
|
||||||
@ -53,6 +55,10 @@ export class ManageQuota extends ModalAction {
|
|||||||
return this.props.rootStore.checkEndpoint('zun');
|
return this.props.rootStore.checkEndpoint('zun');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get enableMagnum() {
|
||||||
|
return this.props.rootStore.checkEndpoint('magnum');
|
||||||
|
}
|
||||||
|
|
||||||
get enableTrove() {
|
get enableTrove() {
|
||||||
return (
|
return (
|
||||||
this.props.rootStore.checkEndpoint('trove') &&
|
this.props.rootStore.checkEndpoint('trove') &&
|
||||||
@ -150,6 +156,9 @@ export class ManageQuota extends ModalAction {
|
|||||||
if (this.enableZun) {
|
if (this.enableZun) {
|
||||||
newQuotaCardList.push(zunQuotaCard);
|
newQuotaCardList.push(zunQuotaCard);
|
||||||
}
|
}
|
||||||
|
if (this.enableMagnum) {
|
||||||
|
newQuotaCardList.push(magnumQuotaCard);
|
||||||
|
}
|
||||||
if (this.enableTrove) {
|
if (this.enableTrove) {
|
||||||
newQuotaCardList.push(troveQuotaCard);
|
newQuotaCardList.push(troveQuotaCard);
|
||||||
}
|
}
|
||||||
@ -197,7 +206,27 @@ export class ManageQuota extends ModalAction {
|
|||||||
return [labelItem, ...items];
|
return [labelItem, ...items];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMagnumFormItems() {
|
||||||
|
const formItems = this.getFormItemsByCards('magnum');
|
||||||
|
return formItems.map((it) => {
|
||||||
|
if (it.name === 'magnum_cluster') {
|
||||||
|
it.min = 1;
|
||||||
|
it.tip = t('The limit of cluster instance greater than or equal to 1.');
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
get formItems() {
|
get formItems() {
|
||||||
|
if (this.projectStore.quotaLoading) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'loading',
|
||||||
|
label: '',
|
||||||
|
component: <Spin />,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
const computeFormItems = this.getComputeFormItems();
|
const computeFormItems = this.getComputeFormItems();
|
||||||
const networkFormItems = this.getFormItemsByCards('networks');
|
const networkFormItems = this.getFormItemsByCards('networks');
|
||||||
const form = [...computeFormItems, ...networkFormItems];
|
const form = [...computeFormItems, ...networkFormItems];
|
||||||
@ -207,6 +236,9 @@ export class ManageQuota extends ModalAction {
|
|||||||
if (this.enableZun) {
|
if (this.enableZun) {
|
||||||
form.push(...this.getFormItemsByCards('zun'));
|
form.push(...this.getFormItemsByCards('zun'));
|
||||||
}
|
}
|
||||||
|
if (this.enableMagnum) {
|
||||||
|
form.push(...this.getMagnumFormItems());
|
||||||
|
}
|
||||||
if (this.enableTrove) {
|
if (this.enableTrove) {
|
||||||
form.push(...this.getFormItemsByCards('trove'));
|
form.push(...this.getFormItemsByCards('trove'));
|
||||||
}
|
}
|
||||||
@ -236,11 +268,13 @@ export class ManageQuota extends ModalAction {
|
|||||||
volumeTypes,
|
volumeTypes,
|
||||||
share,
|
share,
|
||||||
zun,
|
zun,
|
||||||
|
magnum,
|
||||||
...others
|
...others
|
||||||
} = values;
|
} = values;
|
||||||
return {
|
return {
|
||||||
project_id,
|
project_id,
|
||||||
data: others,
|
data: others,
|
||||||
|
current_quota: this.projectStore.quota,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,12 +39,18 @@ export class ProjectStore extends Base {
|
|||||||
@observable
|
@observable
|
||||||
zunQuota = {};
|
zunQuota = {};
|
||||||
|
|
||||||
|
@observable
|
||||||
|
magnumQuota = {};
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
troveQuota = {};
|
troveQuota = {};
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
groupRoleList = [];
|
groupRoleList = [];
|
||||||
|
|
||||||
|
@observable
|
||||||
|
quotaLoading = false;
|
||||||
|
|
||||||
get client() {
|
get client() {
|
||||||
return client.keystone.projects;
|
return client.keystone.projects;
|
||||||
}
|
}
|
||||||
@ -85,6 +91,10 @@ export class ProjectStore extends Base {
|
|||||||
return client.zun.quotas;
|
return client.zun.quotas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get magnumQuotaClient() {
|
||||||
|
return client.magnum.quotas.cluster;
|
||||||
|
}
|
||||||
|
|
||||||
get troveQuotaClient() {
|
get troveQuotaClient() {
|
||||||
return client.trove.quotas;
|
return client.trove.quotas;
|
||||||
}
|
}
|
||||||
@ -220,6 +230,10 @@ export class ProjectStore extends Base {
|
|||||||
return globalRootStore.checkEndpoint('zun');
|
return globalRootStore.checkEndpoint('zun');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get enableMagnum() {
|
||||||
|
return globalRootStore.checkEndpoint('magnum');
|
||||||
|
}
|
||||||
|
|
||||||
get enableTrove() {
|
get enableTrove() {
|
||||||
return (
|
return (
|
||||||
globalRootStore.checkEndpoint('trove') && globalRootStore.hasAdminOnlyRole
|
globalRootStore.checkEndpoint('trove') && globalRootStore.hasAdminOnlyRole
|
||||||
@ -260,6 +274,7 @@ export class ProjectStore extends Base {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
async fetchProjectQuota({ project_id, withKeyPair = false }) {
|
async fetchProjectQuota({ project_id, withKeyPair = false }) {
|
||||||
|
this.quotaLoading = true;
|
||||||
const promiseArr = [
|
const promiseArr = [
|
||||||
this.novaQuotaClient.detail(project_id),
|
this.novaQuotaClient.detail(project_id),
|
||||||
this.neutronQuotaClient.details(project_id),
|
this.neutronQuotaClient.details(project_id),
|
||||||
@ -279,6 +294,10 @@ export class ProjectStore extends Base {
|
|||||||
})
|
})
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
promiseArr.push(
|
||||||
|
this.enableMagnum ? this.magnumQuotaClient.list(project_id) : null,
|
||||||
|
this.enableMagnum ? client.magnum.clusters.list() : null
|
||||||
|
);
|
||||||
promiseArr.push(
|
promiseArr.push(
|
||||||
this.enableTrove ? this.troveQuotaClient.show(project_id) : null
|
this.enableTrove ? this.troveQuotaClient.show(project_id) : null
|
||||||
);
|
);
|
||||||
@ -289,6 +308,8 @@ export class ProjectStore extends Base {
|
|||||||
cinderResult,
|
cinderResult,
|
||||||
shareResult,
|
shareResult,
|
||||||
zunResult,
|
zunResult,
|
||||||
|
magnumResult,
|
||||||
|
magnumInstanceResult,
|
||||||
troveResult,
|
troveResult,
|
||||||
keyPairResult,
|
keyPairResult,
|
||||||
] = await Promise.all(promiseArr);
|
] = await Promise.all(promiseArr);
|
||||||
@ -298,6 +319,8 @@ export class ProjectStore extends Base {
|
|||||||
const { quota: neutronQuota } = neutronResult;
|
const { quota: neutronQuota } = neutronResult;
|
||||||
const { quota_set: shareQuota = {} } = shareResult || {};
|
const { quota_set: shareQuota = {} } = shareResult || {};
|
||||||
const zunQuota = zunResult || {};
|
const zunQuota = zunResult || {};
|
||||||
|
const { hard_limit, id: clusterQuotaId } = magnumResult || {};
|
||||||
|
const { clusters = [] } = magnumInstanceResult || {};
|
||||||
const { quotas: troveQuota = [] } = troveResult || {};
|
const { quotas: troveQuota = [] } = troveResult || {};
|
||||||
this.updateNovaQuota(novaQuota);
|
this.updateNovaQuota(novaQuota);
|
||||||
const renameShareQuota = Object.keys(shareQuota).reduce((pre, cur) => {
|
const renameShareQuota = Object.keys(shareQuota).reduce((pre, cur) => {
|
||||||
@ -310,6 +333,13 @@ export class ProjectStore extends Base {
|
|||||||
pre[key] = zunQuota[cur];
|
pre[key] = zunQuota[cur];
|
||||||
return pre;
|
return pre;
|
||||||
}, {});
|
}, {});
|
||||||
|
const magnumQuota = {
|
||||||
|
magnum_cluster: {
|
||||||
|
limit: hard_limit,
|
||||||
|
in_use: clusters.length,
|
||||||
|
},
|
||||||
|
magnum_cluster_id: clusterQuotaId,
|
||||||
|
};
|
||||||
const renameTroveQuota = troveQuota.reduce((pre, cur) => {
|
const renameTroveQuota = troveQuota.reduce((pre, cur) => {
|
||||||
const key = `trove_${cur.resource}`;
|
const key = `trove_${cur.resource}`;
|
||||||
pre[key] = cur;
|
pre[key] = cur;
|
||||||
@ -321,6 +351,7 @@ export class ProjectStore extends Base {
|
|||||||
...neutronQuota,
|
...neutronQuota,
|
||||||
...renameShareQuota,
|
...renameShareQuota,
|
||||||
...renameZunQuota,
|
...renameZunQuota,
|
||||||
|
...magnumQuota,
|
||||||
...renameTroveQuota,
|
...renameTroveQuota,
|
||||||
};
|
};
|
||||||
if (withKeyPair) {
|
if (withKeyPair) {
|
||||||
@ -330,6 +361,7 @@ export class ProjectStore extends Base {
|
|||||||
}
|
}
|
||||||
const newQuota = this.updateQuotaData(quota);
|
const newQuota = this.updateQuotaData(quota);
|
||||||
this.quota = newQuota;
|
this.quota = newQuota;
|
||||||
|
this.quotaLoading = false;
|
||||||
return newQuota;
|
return newQuota;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,6 +478,19 @@ export class ProjectStore extends Base {
|
|||||||
return zunReqBody;
|
return zunReqBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMagnumQuotaBody(data, project_id) {
|
||||||
|
if (!this.enableMagnum) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const { magnum_cluster } = data;
|
||||||
|
const magnumReqBody = this.omitNil({
|
||||||
|
project_id,
|
||||||
|
resource: 'Cluster',
|
||||||
|
hard_limit: magnum_cluster,
|
||||||
|
});
|
||||||
|
return magnumReqBody;
|
||||||
|
}
|
||||||
|
|
||||||
getTroveQuotaBody(data) {
|
getTroveQuotaBody(data) {
|
||||||
if (!this.enableTrove) {
|
if (!this.enableTrove) {
|
||||||
return {};
|
return {};
|
||||||
@ -460,12 +505,13 @@ export class ProjectStore extends Base {
|
|||||||
return troveReqBody;
|
return troveReqBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateQuota(project_id, data) {
|
async updateQuota(project_id, data, current_quota) {
|
||||||
const novaReqBody = this.getNovaQuotaBody(data);
|
const novaReqBody = this.getNovaQuotaBody(data);
|
||||||
const cinderReqBody = this.getCinderQuotaBody(data);
|
const cinderReqBody = this.getCinderQuotaBody(data);
|
||||||
const neutronReqBody = this.getNeutronQuotaBody(data);
|
const neutronReqBody = this.getNeutronQuotaBody(data);
|
||||||
const shareReqBody = this.getShareQuotaBody(data);
|
const shareReqBody = this.getShareQuotaBody(data);
|
||||||
const zunReqBody = this.getZunQuotaBody(data);
|
const zunReqBody = this.getZunQuotaBody(data);
|
||||||
|
const magnumReqBody = this.getMagnumQuotaBody(data, project_id);
|
||||||
const troveReqBody = this.getTroveQuotaBody(data);
|
const troveReqBody = this.getTroveQuotaBody(data);
|
||||||
const reqs = [];
|
const reqs = [];
|
||||||
if (!isEmpty(novaReqBody.quota_set)) {
|
if (!isEmpty(novaReqBody.quota_set)) {
|
||||||
@ -483,6 +529,15 @@ export class ProjectStore extends Base {
|
|||||||
if (!isEmpty(zunReqBody)) {
|
if (!isEmpty(zunReqBody)) {
|
||||||
reqs.push(client.zun.quotas.update(project_id, zunReqBody));
|
reqs.push(client.zun.quotas.update(project_id, zunReqBody));
|
||||||
}
|
}
|
||||||
|
if (!isEmpty(magnumReqBody)) {
|
||||||
|
// if magnum_cluster_id is existed, it means the quota has been initialized
|
||||||
|
const { magnum_cluster_id } = current_quota || {};
|
||||||
|
if (magnum_cluster_id) {
|
||||||
|
reqs.push(client.magnum.quotas.updateQuota(project_id, magnumReqBody));
|
||||||
|
} else {
|
||||||
|
reqs.push(client.magnum.quotas.create(magnumReqBody));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!isEmpty(troveReqBody)) {
|
if (!isEmpty(troveReqBody)) {
|
||||||
reqs.push(client.trove.quotas.update(project_id, troveReqBody));
|
reqs.push(client.trove.quotas.update(project_id, troveReqBody));
|
||||||
}
|
}
|
||||||
@ -491,9 +546,9 @@ export class ProjectStore extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async updateProjectQuota({ project_id, data }) {
|
async updateProjectQuota({ project_id, data, current_quota }) {
|
||||||
this.isSubmitting = true;
|
this.isSubmitting = true;
|
||||||
const result = await this.updateQuota(project_id, data);
|
const result = await this.updateQuota(project_id, data, current_quota);
|
||||||
this.isSubmitting = false;
|
this.isSubmitting = false;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -625,6 +680,24 @@ export class ProjectStore extends Base {
|
|||||||
return zunQuota;
|
return zunQuota;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async fetchProjectMagnumQuota(projectId) {
|
||||||
|
const [quotas, clustersRes] = await Promise.all([
|
||||||
|
this.magnumQuotaClient.list(projectId || this.currentProjectId),
|
||||||
|
client.magnum.clusters.list(),
|
||||||
|
]);
|
||||||
|
const { hard_limit } = this.updateQuotaData(quotas);
|
||||||
|
const { clusters = [] } = clustersRes || {};
|
||||||
|
const magnumQuota = this.updateQuotaData({
|
||||||
|
magnum_cluster: {
|
||||||
|
limit: hard_limit,
|
||||||
|
in_use: clusters.length,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.magnumQuota = magnumQuota;
|
||||||
|
return magnumQuota;
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async fetchProjectTroveQuota(projectId) {
|
async fetchProjectTroveQuota(projectId) {
|
||||||
const { quotas = [] } = await this.troveQuotaClient.show(
|
const { quotas = [] } = await this.troveQuotaClient.show(
|
||||||
|
Loading…
Reference in New Issue
Block a user