fix: fix the magnum service

1. check cluster quota immediately when create page mounted
2. fix template coverage to instance information
3. fix detail fetch to show image name,flavor name...

Closes-Bug: #1999756
Change-Id: I586689d508cb838562ba4a0bef574a4e696e57c0
This commit is contained in:
xusongfu 2022-12-15 18:23:57 +08:00
parent f384bd4b73
commit a307f457e4
16 changed files with 614 additions and 169 deletions

View File

@ -915,7 +915,6 @@
"External IP(V4)": "External IP(V4)",
"External IP(V6)": "External IP(V6)",
"External Network": "External Network",
"External Network ID": "External Network ID",
"External Network Info": "External Network Info",
"External Networks": "External Networks",
"External Port": "External Port",
@ -945,9 +944,7 @@
"Fixed IP Address": "Fixed IP Address",
"Fixed IPs": "Fixed IPs",
"Fixed Network": "Fixed Network",
"Fixed Network ID": "Fixed Network ID",
"Fixed Subnet": "Fixed Subnet",
"Fixed Subnet ID": "Fixed Subnet ID",
"Flavor": "Flavor",
"Flavor Detail": "Flavor Detail",
"Flavor Info": "Flavor Info",
@ -1425,7 +1422,7 @@
"Martinique": "Martinique",
"Master Count": "Master Count",
"Master Node Addresses": "Master Node Addresses",
"Master Node Flavor ID": "Master Node Flavor ID",
"Master Node Flavor": "Master Node Flavor",
"Master Node LB Enabled": "Master Node LB Enabled",
"Mauritania": "Mauritania",
"Mauritius": "Mauritius",
@ -1565,7 +1562,7 @@
"Node Addresses": "Node Addresses",
"Node Count": "Node Count",
"Node Driver": "Node Driver",
"Node Flavor ID": "Node Flavor ID",
"Node Flavor": "Node Flavor",
"Node ID/Name": "Node ID/Name",
"Node Info": "Node Info",
"Node Name": "Node Name",
@ -2505,7 +2502,6 @@
"Usage Type": "Usage Type",
"Usb Controller": "Usb Controller",
"Use Type": "Use Type",
"Use an Existing Network": "Use an Existing Network",
"Used": "Used",
"Used IPs": "Used IPs",
"Used by tunnel(s): {names}. ID(s): {ids}": "Used by tunnel(s): {names}. ID(s): {ids}",

View File

@ -915,7 +915,6 @@
"External IP(V4)": "外网IP(V4)",
"External IP(V6)": "外网IP(V6)",
"External Network": "外部网络",
"External Network ID": "外部网络ID",
"External Network Info": "外部网络信息",
"External Networks": "外部网络",
"External Port": "源端口",
@ -945,9 +944,7 @@
"Fixed IP Address": "内网IP地址",
"Fixed IPs": "内网IP",
"Fixed Network": "内网",
"Fixed Network ID": "内网ID",
"Fixed Subnet": "内网子网",
"Fixed Subnet ID": "内网子网ID",
"Flavor": "云主机类型",
"Flavor Detail": "云主机类型详情",
"Flavor Info": "配置信息",
@ -1425,7 +1422,7 @@
"Martinique": "马提尼克岛",
"Master Count": "主数量",
"Master Node Addresses": "主节点地址",
"Master Node Flavor ID": "主节点类型ID",
"Master Node Flavor": "主节点类型",
"Master Node LB Enabled": "启用主节点负载均衡",
"Mauritania": "毛里塔尼亚",
"Mauritius": "毛里求斯",
@ -1565,7 +1562,7 @@
"Node Addresses": "节点地址",
"Node Count": "节点数量",
"Node Driver": "节点驱动",
"Node Flavor ID": "节点类型ID",
"Node Flavor": "节点类型",
"Node ID/Name": "节点ID/名称",
"Node Info": "节点信息",
"Node Name": "节点名称",
@ -2505,7 +2502,6 @@
"Usage Type": "使用类型",
"Usb Controller": "USB控制器",
"Use Type": "使用类型",
"Use an Existing Network": "使用现有网络",
"Used": "已使用",
"Used IPs": "已用IP",
"Used by tunnel(s): {names}. ID(s): {ids}": "被隧道使用中:{names}。 ID{ids}",

View File

@ -68,17 +68,35 @@ export class BaseDetail extends Base {
}
get networkCard() {
const { external_network_id, fixed_network } = this.detailData || {};
const {
external_network_id,
externalNetwork: { name: externalName } = {},
fixed_network,
fixedNetwork: { name: fixedName } = {},
fixed_subnet,
fixedSubnet: { name: subName } = {},
} = this.detailData || {};
const externalNetworkUrl = external_network_id
? this.getLinkRender('networkDetail', external_network_id, {
id: external_network_id,
})
? this.getLinkRender(
'networkDetail',
externalName || external_network_id,
{
id: external_network_id,
}
)
: '-';
const fixedNetworkUrl = fixed_network
? this.getLinkRender('networkDetail', fixed_network, {
? this.getLinkRender('networkDetail', fixedName || fixed_network, {
id: fixed_network,
})
: '-';
const subnetUrl =
fixed_network && fixed_subnet
? this.getLinkRender('subnetDetail', subName || fixed_subnet, {
networkId: fixed_network,
id: fixed_subnet,
})
: '-';
const options = [
{
@ -98,16 +116,16 @@ export class BaseDetail extends Base {
dataIndex: 'no_proxy',
},
{
label: t('External Network ID'),
label: t('External Network'),
content: externalNetworkUrl,
},
{
label: t('Fixed Network ID'),
label: t('Fixed Network'),
content: fixedNetworkUrl,
},
{
label: t('Fixed Subnet ID'),
dataIndex: 'fixed_subnet',
label: t('Fixed Subnet'),
content: subnetUrl,
},
{
label: t('DNS'),
@ -132,10 +150,18 @@ export class BaseDetail extends Base {
}
get specCard() {
const { image_id, keypair_id, flavor_id, master_flavor_id, selfKeypair } =
this.detailData;
const {
image_id,
image: { name: imageName } = {},
keypair_id,
flavor_id,
flavor: { name: flavorName } = {},
master_flavor_id,
masterFlavor: { name: masterFlavorName } = {},
selfKeypair,
} = this.detailData;
const imageUrl = image_id
? this.getLinkRender('imageDetail', image_id, {
? this.getLinkRender('imageDetail', imageName || image_id, {
id: image_id,
})
: '-';
@ -148,20 +174,24 @@ export class BaseDetail extends Base {
: keypair_id || '-';
const flavorUrl = flavor_id
? this.getLinkRender('flavorDetail', flavor_id, {
? this.getLinkRender('flavorDetail', flavorName || flavor_id, {
id: flavor_id,
})
: '-';
const masterFlavorUrl = master_flavor_id
? this.getLinkRender('flavorDetail', master_flavor_id, {
id: master_flavor_id,
})
? this.getLinkRender(
'flavorDetail',
masterFlavorName || master_flavor_id,
{
id: master_flavor_id,
}
)
: '-';
const options = [
{
label: t('Image ID'),
label: t('Image'),
content: imageUrl,
},
{
@ -170,11 +200,11 @@ export class BaseDetail extends Base {
hidden: this.isAdminPage,
},
{
label: t('Node Flavor ID'),
label: t('Node Flavor'),
content: flavorUrl,
},
{
label: t('Master Node Flavor ID'),
label: t('Master Node Flavor'),
content: masterFlavorUrl,
},
{

View File

@ -18,7 +18,7 @@ import { inject, observer } from 'mobx-react';
import { NetworkStore } from 'src/stores/neutron/network';
import { SubnetStore } from 'src/stores/neutron/subnet';
import { getLinkRender } from 'utils/route-map';
import { networkColumns } from 'resources/neutron/network';
import { networkColumns, subnetColumns } from 'resources/neutron/network';
export class StepNetwork extends Base {
async init() {
@ -87,8 +87,11 @@ export class StepNetwork extends Base {
https_proxy,
no_proxy,
external_network_id,
externalNetwork,
fixed_network,
fixedNetwork,
fixed_subnet,
fixedSubnet,
dns_nameserver,
master_lb_enabled,
floating_ip_enabled,
@ -101,21 +104,22 @@ export class StepNetwork extends Base {
no_proxy,
externalNetwork: {
selectedRowKeys: [external_network_id],
selectedRows: [externalNetwork],
},
fixed_network,
fixed_subnet,
dns_nameserver,
master_lb_enabled,
floating_ip_enabled,
};
if (fixed_network) {
values.fixedNetwork = this.props.context.fixedNetwork || {
values.fixedNetwork = {
selectedRowKeys: [fixed_network],
selectedRows: [fixedNetwork],
};
}
if (fixed_subnet) {
values.fixedSubnet = {
selectedRowKeys: [fixed_subnet],
selectedRows: [fixedSubnet],
};
}
}
@ -201,7 +205,10 @@ export class StepNetwork extends Base {
this.updateContext({
fixedNetwork: value,
});
this.updateFormValue('fixedSubnet', null);
this.updateFormValue('fixedSubnet', {
selectedRowKeys: [],
selectedRows: [],
});
},
},
{
@ -215,29 +222,7 @@ export class StepNetwork extends Base {
name: 'name',
},
],
columns: [
{
title: t('Name'),
dataIndex: 'name',
},
{
title: t('CIDR'),
dataIndex: 'cidr',
},
{
title: t('Gateway IP'),
dataIndex: 'gateway_ip',
},
{
title: t('IP Version'),
dataIndex: 'ip_version',
},
{
title: t('Created At'),
dataIndex: 'created_at',
valueRender: 'toLocalTime',
},
],
columns: subnetColumns,
},
{
name: 'dns_nameserver',

View File

@ -12,21 +12,23 @@
// 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 { toJS } from 'mobx';
import Base from 'components/Form';
import { ImageStore } from 'stores/glance/image';
import globalKeypairStore from 'stores/nova/keypair';
import FlavorSelectTable from 'pages/compute/containers/Instance/components/FlavorSelectTable';
import { FlavorStore } from 'src/stores/nova/flavor';
import { getImageColumns } from 'resources/glance/image';
import { getKeyPairHeader } from 'resources/nova/keypair';
import { getBaseSimpleFlavorColumns } from 'resources/magnum/template';
export class StepNodeSpec extends Base {
init() {
this.imageStore = new ImageStore();
this.keyPairStore = globalKeypairStore;
this.getImageList();
this.getKeypairs();
this.flavorStore = new FlavorStore();
this.masterFlavorStore = new FlavorStore();
this.getAllInitFunctions();
}
get title() {
@ -45,19 +47,44 @@ export class StepNodeSpec extends Base {
return !!this.props.extra;
}
async getImageList() {
await this.imageStore.fetchList({ all_projects: this.hasAdminRole });
async getAllInitFunctions() {
await Promise.all([
this.getImageList(),
this.getKeypairs(),
this.getFlavors(),
this.getMasterFlavors(),
]);
this.updateDefaultValue();
}
async getKeypairs() {
await this.keyPairStore.fetchList();
getImageList() {
return this.imageStore.fetchList({ all_projects: this.hasAdminRole });
}
getKeypairs() {
return this.keyPairStore.fetchList();
}
get keypairs() {
return this.keyPairStore.list.data || [];
}
getFlavors() {
return this.flavorStore.fetchList();
}
getMasterFlavors() {
return this.masterFlavorStore.fetchList();
}
get flavors() {
return toJS(this.flavorStore.list.data) || [];
}
get masterFlavors() {
return toJS(this.masterFlavorStore.list.data) || [];
}
get acceptedImageOs() {
const { context: { coe = '' } = {} } = this.props;
let acceptedOs = [];
@ -93,26 +120,6 @@ export class StepNodeSpec extends Base {
return acceptedVolumeDriver;
}
getFlavorComponent() {
return <FlavorSelectTable onChange={this.onFlavorChange} />;
}
onFlavorChange = (value) => {
this.updateContext({
flavor: value,
});
};
getMasterFlavorComponent() {
return <FlavorSelectTable onChange={this.onMasterFlavorChange} />;
}
onMasterFlavorChange = (value) => {
this.updateContext({
masterFlavor: value,
});
};
get defaultValue() {
let values = {};
@ -134,10 +141,18 @@ export class StepNodeSpec extends Base {
docker_volume_size,
};
if (flavor_id) {
values.flavor = { selectedRowKeys: [flavor_id] };
values.flavor = {
selectedRowKeys: [flavor_id],
selectedRows: this.flavors.filter((it) => it.id === flavor_id),
};
}
if (master_flavor_id) {
values.masterFlavor = { selectedRowKeys: [master_flavor_id] };
values.masterFlavor = {
selectedRowKeys: [master_flavor_id],
selectedRows: this.masterFlavors.filter(
(it) => it.id === master_flavor_id
),
};
}
if (image_id) {
values.images = { selectedRowKeys: [image_id] };
@ -209,13 +224,29 @@ export class StepNodeSpec extends Base {
name: 'flavor',
label: t('Flavor of Nodes'),
type: 'select-table',
component: this.getFlavorComponent(),
data: this.flavors,
columns: getBaseSimpleFlavorColumns(this),
isLoading: this.flavorStore.list.isLoading,
filterParams: [
{
label: t('Name'),
name: 'name',
},
],
},
{
name: 'masterFlavor',
label: t('Flavor of Master Nodes'),
type: 'select-table',
component: this.getMasterFlavorComponent(),
data: this.masterFlavors,
columns: getBaseSimpleFlavorColumns(this),
isLoading: this.masterFlavorStore.list.isLoading,
filterParams: [
{
label: t('Name'),
name: 'name',
},
],
},
{
name: 'volume_driver',

View File

@ -117,21 +117,14 @@ export class StepCreate extends StepAction {
...rest,
labels: requestLabels,
external_network_id: externalNetwork.selectedRowKeys[0],
fixed_network: fixedNetwork ? fixedNetwork.selectedRowKeys[0] : null,
fixed_subnet: fixedSubnet ? fixedSubnet.selectedRowKeys[0] : null,
fixed_network: (fixedNetwork && fixedNetwork.selectedRowKeys[0]) || null,
fixed_subnet: (fixedSubnet && fixedSubnet.selectedRowKeys[0]) || null,
flavor_id: (flavor && flavor.selectedRowKeys[0]) || null,
master_flavor_id:
(masterFlavor && masterFlavor.selectedRowKeys[0]) || null,
image_id: (images && images.selectedRowKeys[0]) || null,
keypair_id: (keypair && keypair.selectedRowKeys[0]) || null,
};
if (flavor) {
body.flavor_id = flavor.selectedRowKeys[0];
}
if (masterFlavor) {
body.master_flavor_id = masterFlavor.selectedRowKeys[0];
}
if (images) {
body.image_id = images.selectedRowKeys[0];
}
if (keypair) {
body.keypair_id = keypair.selectedRowKeys[0];
}
if (this.isEdit) {
return this.store.update({ id: this.params.id }, body);
}

View File

@ -19,7 +19,6 @@ import actionConfigs from './actions';
export class ClusterTemplates extends Base {
init() {
this.store = globalClusterTemplateStore;
this.downloadStore = globalClusterTemplateStore;
}
get name() {

View File

@ -19,14 +19,14 @@ import React from 'react';
export class BaseDetail extends Base {
get leftCards() {
return [this.baseInfoCard, this.miscellaneousCard];
return [this.templateCard, this.networkCard, this.miscellaneousCard];
}
get rightCards() {
return [this.nodesCard, this.labelCard, this.stackCard];
}
get baseInfoCard() {
get templateCard() {
const { template = {} } = this.detailData;
const templateUrl = template
? this.getLinkRender(
@ -65,19 +65,45 @@ export class BaseDetail extends Base {
};
}
get miscellaneousCard() {
const { master_flavor_id, flavor_id, keypair } = this.detailData;
const masterFlavorUrl = master_flavor_id
? this.getLinkRender('flavorDetail', master_flavor_id, {
id: master_flavor_id,
get networkCard() {
const {
fixed_network,
fixedNetwork: { name: fixedName } = {},
fixed_subnet,
fixedSubnet: { name: subName } = {},
} = this.detailData || {};
const fixedNetworkUrl = fixed_network
? this.getLinkRender('networkDetail', fixedName || fixed_network, {
id: fixed_network,
})
: '-';
const subnetUrl =
fixed_network && fixed_subnet
? this.getLinkRender('subnetDetail', subName || fixed_subnet, {
networkId: fixed_network,
id: fixed_subnet,
})
: '-';
const flavorUrl = flavor_id
? this.getLinkRender('flavorDetail', flavor_id, {
id: flavor_id,
})
: '-';
const options = [
{
label: t('Fixed Network'),
content: fixedNetworkUrl,
},
{
label: t('Fixed Subnet'),
content: subnetUrl,
},
];
return {
title: t('Network'),
options,
};
}
get miscellaneousCard() {
const { keypair } = this.detailData;
const keypairUrl = keypair
? this.getLinkRender('keypairDetail', keypair, {
@ -111,14 +137,6 @@ export class BaseDetail extends Base {
label: t('Docker Volume Size (GiB)'),
dataIndex: 'docker_volume_size',
},
{
label: t('Master Node Flavor ID'),
content: masterFlavorUrl,
},
{
label: t('Node Flavor ID'),
content: flavorUrl,
},
{
label: t('COE Version'),
dataIndex: 'coe_version',
@ -132,15 +150,48 @@ export class BaseDetail extends Base {
return {
title: t('Miscellaneous'),
options,
labelCol: 12,
contentCol: 12,
};
}
get nodesCard() {
const {
master_flavor_id,
masterFlavor: { name: masterFlavorName } = {},
flavor_id,
flavor: { name: flavorName } = {},
} = this.detailData;
const masterFlavorUrl = master_flavor_id
? this.getLinkRender(
'flavorDetail',
masterFlavorName || master_flavor_id,
{
id: master_flavor_id,
}
)
: '-';
const flavorUrl = flavor_id
? this.getLinkRender('flavorDetail', flavorName || flavor_id, {
id: flavor_id,
})
: '-';
const options = [
{
label: t('Master Node Flavor'),
content: masterFlavorUrl,
},
{
label: t('Master Count'),
dataIndex: 'master_count',
},
{
label: t('Node Flavor'),
content: flavorUrl,
},
{
label: t('Node Count'),
dataIndex: 'node_count',

View File

@ -12,11 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import React from 'react';
import Base from 'components/Form';
import { toJS } from 'mobx';
import { inject, observer } from 'mobx-react';
import { defaultTip } from 'resources/magnum/cluster';
import { NetworkStore } from 'stores/neutron/network';
import { SubnetStore } from 'src/stores/neutron/subnet';
import { networkColumns, subnetColumns } from 'resources/neutron/network';
import { getLinkRender } from 'utils/route-map';
export class StepNetworks extends Base {
init() {
this.networkStore = new NetworkStore();
this.subnetStore = new SubnetStore();
this.getAllInitFunctions();
}
get title() {
return t('Cluster Network');
}
@ -27,9 +39,62 @@ export class StepNetworks extends Base {
allowed = () => Promise.resolve();
async getAllInitFunctions() {
const {
context: { clusterTemplate = {} },
} = this.props;
const { selectedRows = [] } = clusterTemplate;
const { fixed_network, fixed_subnet } = selectedRows[0] || {};
await Promise.all([
fixed_network
? this.networkStore.fetchDetail({ id: fixed_network })
: null,
fixed_subnet ? this.subnetStore.fetchDetail({ id: fixed_subnet }) : null,
this.subnetStore.fetchList(),
]);
this.updateDefaultValue();
}
get network() {
return toJS(this.networkStore.detail) || {};
}
get subnet() {
return toJS(this.subnetStore.detail) || {};
}
get subnetList() {
const {
context: {
clusterTemplate: { selectedRows: templateRows = [] } = {},
fixedNetwork: { selectedRowKeys: contextKeys = [] } = {},
},
} = this.props;
const { fixed_network } = templateRows[0] || {};
const key = contextKeys[0] || fixed_network;
return (this.subnetStore.list.data || []).filter(
(it) => key === it.network_id
);
}
get defaultValue() {
const {
context: { clusterTemplate = {}, fixedNetwork, fixedSubnet } = {},
} = this.props;
const { selectedRows = [] } = clusterTemplate;
const { fixed_network, fixed_subnet } = selectedRows[0] || {};
return {
newNetwork: true,
fixedNetwork: fixedNetwork || {
selectedRowKeys: fixed_network ? [fixed_network] : [],
selectedRows: fixed_network ? [this.network] : [],
},
fixedSubnet: fixedSubnet || {
selectedRowKeys: fixed_subnet ? [fixed_subnet] : [],
selectedRows: fixed_subnet ? [this.subnet] : [],
},
};
}
@ -40,6 +105,21 @@ export class StepNetworks extends Base {
get formItems() {
const { newNetwork } = this.state;
const {
context: { clusterTemplate = {}, fixedNetwork, fixedSubnet } = {},
} = this.props;
const { selectedRows = [] } = clusterTemplate;
const { fixed_network, fixed_subnet } = selectedRows[0] || {};
const initFixedNetwork = fixedNetwork || {
selectedRowKeys: fixed_network ? [fixed_network] : [],
selectedRows: fixed_network ? [this.network] : [],
};
const initSubnet = fixedSubnet || {
selectedRowKeys: fixed_subnet ? [fixed_subnet] : [],
selectedRows: fixed_subnet ? [this.subnet] : [],
};
return [
{
name: 'master_lb_enabled',
@ -55,10 +135,59 @@ export class StepNetworks extends Base {
content: t('Create New Network'),
},
{
name: 'fixed_network',
label: t('Use an Existing Network'),
type: 'network-select-table',
name: 'fixedNetwork',
label: t('Fixed Network'),
type: 'select-table',
hidden: newNetwork,
backendPageStore: this.networkStore,
extraParams: {
'router:external': false,
project_id: this.currentProjectId,
},
loading: this.networkStore.list.isLoading,
header: (
<div>
{t(' You can go to the console to ')}
{getLinkRender({
key: 'network',
value: `${t('create a new network/subnet')} > `,
})}
</div>
),
filterParams: [
{
label: t('Name'),
name: 'name',
},
],
columns: networkColumns(this),
onChange: (value) => {
this.updateContext({
fixedNetwork: value,
});
this.updateContext({
fixedSubnet: {
selectedRowKeys: [],
selectedRows: [],
},
});
},
initValue: initFixedNetwork,
},
{
name: 'fixedSubnet',
label: t('Fixed Subnet'),
type: 'select-table',
hidden: newNetwork,
data: this.subnetList,
filterParams: [
{
label: t('Name'),
name: 'name',
},
],
columns: subnetColumns,
initValue: initSubnet,
},
{
type: 'divider',

View File

@ -12,18 +12,21 @@
// 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 { toJS } from 'mobx';
import Base from 'components/Form';
import FlavorSelectTable from 'src/pages/compute/containers/Instance/components/FlavorSelectTable';
import globalKeypairStore from 'stores/nova/keypair';
import { FlavorStore } from 'src/stores/nova/flavor';
import { defaultTip } from 'resources/magnum/cluster';
import { getKeyPairHeader } from 'resources/nova/keypair';
import { getBaseSimpleFlavorColumns } from 'resources/magnum/template';
export class StepNodeSpec extends Base {
init() {
this.keyPairStore = globalKeypairStore;
this.getKeypairs();
this.flavorStore = new FlavorStore();
this.masterFlavorStore = new FlavorStore();
this.getAllInitFunctions();
}
get title() {
@ -36,58 +39,90 @@ export class StepNodeSpec extends Base {
allowed = () => Promise.resolve();
async getKeypairs() {
await this.keyPairStore.fetchList();
async getAllInitFunctions() {
await Promise.all([
this.getKeypairs(),
this.getFlavors(),
this.getMasterFlavors(),
]);
this.updateDefaultValue();
}
getKeypairs() {
return this.keyPairStore.fetchList();
}
get keypairs() {
return this.keyPairStore.list.data || [];
}
getFlavorComponent() {
return <FlavorSelectTable onChange={this.onFlavorChange} />;
getFlavors() {
return this.flavorStore.fetchList();
}
onFlavorChange = (value) => {
this.updateContext({
flavor: value,
});
};
getMasterFlavorComponent() {
return <FlavorSelectTable onChange={this.onMasterFlavorChange} />;
getMasterFlavors() {
return this.masterFlavorStore.fetchList();
}
onMasterFlavorChange = (value) => {
this.updateContext({
masterFlavor: value,
});
};
get flavors() {
return toJS(this.flavorStore.list.data) || [];
}
get masterFlavors() {
return toJS(this.masterFlavorStore.list.data) || [];
}
get defaultValue() {
const { context: { clusterTemplate = {} } = {} } = this.props;
const {
context: { clusterTemplate = {}, keypair, masterFlavor, flavor } = {},
} = this.props;
const { selectedRows = [] } = clusterTemplate;
const { master_flavor_id, flavor_id } = selectedRows[0] || {};
const { master_flavor_id, flavor_id, keypair_id, selfKeypair } =
selectedRows[0] || {};
return {
master_count: 1,
node_count: 1,
masterFlavor: {
selectedRowKeys: [master_flavor_id],
masterFlavor: masterFlavor || {
selectedRowKeys: master_flavor_id ? [master_flavor_id] : [],
selectedRows: this.masterFlavors.filter(
(it) => it.id === master_flavor_id
),
},
flavor: flavor || {
selectedRowKeys: flavor_id ? [flavor_id] : [],
selectedRows: this.flavors.filter((it) => it.id === flavor_id),
},
keypair: keypair || {
selectedRowKeys: keypair_id && selfKeypair ? [keypair_id] : [],
selectedRows: this.keypairs.filter((it) => it.id === keypair_id),
},
flavor: { selectedRowKeys: [flavor_id] },
};
}
get formItems() {
const { context: { clusterTemplate = {}, keypair } = {} } = this.props;
const {
context: { clusterTemplate = {}, keypair, masterFlavor, flavor } = {},
} = this.props;
const { selectedRows = [] } = clusterTemplate;
const { master_flavor_id, flavor_id, keypair_id, selfKeypair } =
selectedRows[0] || {};
const { initKeyPair = keypair } = this.state;
const templateHasSelfKeypair = keypair_id && selfKeypair;
const templateInitKeypair = {
selectedRowKeys: [keypair_id],
selectedRowKeys: keypair_id && selfKeypair ? [keypair_id] : [],
selectedRows: this.keypairs.filter((it) => it.id === keypair_id),
};
const initFlavor = flavor || {
selectedRowKeys: flavor_id ? [flavor_id] : [],
selectedRows: this.flavors.filter((it) => it.id === flavor_id),
};
const initMasterFlavor = masterFlavor || {
selectedRowKeys: master_flavor_id ? [master_flavor_id] : [],
selectedRows: this.masterFlavors.filter(
(it) => it.id === master_flavor_id
),
};
return [
@ -95,7 +130,7 @@ export class StepNodeSpec extends Base {
name: 'keypair',
label: t('Keypair'),
type: 'select-table',
required: !templateHasSelfKeypair,
required: true,
data: this.keypairs,
initValue:
initKeyPair || (templateHasSelfKeypair && templateInitKeypair),
@ -137,9 +172,23 @@ export class StepNodeSpec extends Base {
name: 'masterFlavor',
label: t('Flavor of Master Nodes'),
type: 'select-table',
component: this.getMasterFlavorComponent(),
required: !master_flavor_id,
required: true,
tip: defaultTip,
data: this.masterFlavors,
initValue: initMasterFlavor,
columns: getBaseSimpleFlavorColumns(this),
isLoading: this.masterFlavorStore.list.isLoading,
filterParams: [
{
label: t('Name'),
name: 'name',
},
],
onChange: (value) => {
this.updateContext({
masterFlavor: value,
});
},
},
{
type: 'divider',
@ -160,9 +209,23 @@ export class StepNodeSpec extends Base {
name: 'flavor',
label: t('Flavor of Nodes'),
type: 'select-table',
component: this.getFlavorComponent(),
required: !flavor_id,
required: true,
tip: defaultTip,
data: this.flavors,
initValue: initFlavor,
columns: getBaseSimpleFlavorColumns(this),
isLoading: this.flavorStore.list.isLoading,
filterParams: [
{
label: t('Name'),
name: 'name',
},
],
onChange: (value) => {
this.updateContext({
flavor: value,
});
},
},
];
}

View File

@ -171,6 +171,19 @@ export class StepCreate extends StepAction {
return quotaInfo;
}
checkClusterQuota() {
const { quotaLoading } = this.state;
if (quotaLoading) {
return '';
}
const { magnum_cluster = {} } = toJS(this.projectStore.magnumQuota) || {};
const { left = 0 } = magnum_cluster;
if (left === 0) {
return this.getQuotaMessage(1, magnum_cluster, t('Clusters'));
}
return '';
}
checkInstanceQuota() {
const { quotaLoading } = this.state;
if (quotaLoading) {
@ -235,9 +248,10 @@ export class StepCreate extends StepAction {
}
checkQuotaInput() {
const clusterMsg = this.checkClusterQuota();
const instanceMsg = this.checkInstanceQuota();
const flavorMsg = this.checkFlavorQuota();
const error = instanceMsg || flavorMsg;
const error = clusterMsg || instanceMsg || flavorMsg;
if (!error) {
this.status = 'success';
this.errorMsg = '';
@ -273,7 +287,8 @@ export class StepCreate extends StepAction {
auto_healing_enabled,
auto_scaling_enabled,
newNetwork,
fixed_network,
fixedNetwork,
fixedSubnet,
flavor,
masterFlavor,
...rest
@ -311,11 +326,16 @@ export class StepCreate extends StepAction {
data.flavor_id = flavor.selectedRowKeys[0];
}
if (!newNetwork && fixed_network) {
const { selectedRowKeys = [] } = fixed_network;
if (!newNetwork && fixedNetwork) {
const { selectedRowKeys = [] } = fixedNetwork;
data.fixed_network = selectedRowKeys[0];
}
if (!newNetwork && fixedSubnet) {
const { selectedRowKeys = [] } = fixedSubnet;
data.fixed_subnet = selectedRowKeys[0];
}
return this.store.create(data);
};
}

View File

@ -22,7 +22,6 @@ import actionConfigs from './actions';
export class Clusters extends Base {
init() {
this.store = globalClustersStore;
this.downloadStore = globalClustersStore;
}
get name() {

View File

@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { flavorArchitectures, flavorCategoryList } from 'resources/nova/flavor';
import { formatSize } from 'utils';
export const getBaseTemplateColumns = (self) => [
{
title: t('ID/Name'),
@ -41,3 +44,32 @@ export const getBaseTemplateColumns = (self) => [
},
},
];
export const getBaseSimpleFlavorColumns = (self) => [
{
title: t('ID/Name'),
dataIndex: 'name',
routeName: self ? self.getRouteName('flavorDetail') : '',
},
{
title: t('Architecture'),
dataIndex: 'architecture',
valueMap: flavorArchitectures,
},
{
title: t('Category'),
dataIndex: 'category',
render: (value) => flavorCategoryList[value] || value || '-',
},
{
title: t('CPU'),
dataIndex: 'vcpus',
isHideable: true,
},
{
title: t('Memory'),
dataIndex: 'ram',
isHideable: true,
render: (ram) => formatSize(ram, 2),
},
];

View File

@ -111,3 +111,27 @@ export const isExternalNetwork = (network) => !!network['router:external'];
export const subnetIpv6Tip = t(
'Default is slaac, for details, see https://docs.openstack.org/neutron/latest/admin/config-ipv6.html'
);
export const subnetColumns = [
{
title: t('Name'),
dataIndex: 'name',
},
{
title: t('CIDR'),
dataIndex: 'cidr',
},
{
title: t('Gateway IP'),
dataIndex: 'gateway_ip',
},
{
title: t('IP Version'),
dataIndex: 'ip_version',
},
{
title: t('Created At'),
dataIndex: 'created_at',
valueRender: 'toLocalTime',
},
];

View File

@ -22,6 +22,22 @@ export class ClusterTemplatesStore extends Base {
return client.magnum.clusterTemplates;
}
get flavorClient() {
return client.nova.flavors;
}
get networkClient() {
return client.neutron.networks;
}
get subnetClient() {
return client.neutron.subnets;
}
get imageClient() {
return client.glance.images;
}
@action
async create(newbody) {
return this.submitting(this.client.create(newbody));
@ -75,11 +91,48 @@ export class ClusterTemplatesStore extends Base {
}
async detailDidFetch(item) {
const { keypairs = [] } = (await client.nova.keypairs.list()) || {};
const [kp = {}, fr = {}, mfr = {}, ext = {}, fx = {}, sub = {}, img] =
await Promise.all([
client.nova.keypairs.list(),
item.flavor_id ? this.flavorClient.show(item.flavor_id) : {},
item.master_flavor_id
? this.flavorClient.show(item.master_flavor_id)
: {},
item.external_network_id
? this.networkClient.show(item.external_network_id)
: {},
item.fixed_network ? this.networkClient.show(item.fixed_network) : {},
item.fixed_subnet ? this.subnetClient.show(item.fixed_subnet) : {},
item.image_id ? this.imageClient.show(item.image_id) : {},
]);
const { keypairs = [] } = kp;
const { flavor } = fr;
const { flavor: masterFlavor } = mfr;
const { network } = ext;
const { network: fixedNetwork } = fx;
const { subnet: fixedSubnet } = sub;
const keypair = keypairs.find((k) => k?.keypair?.name === item.keypair_id);
if (keypair) {
item.selfKeypair = true;
}
if (flavor) {
item.flavor = flavor;
}
if (masterFlavor) {
item.masterFlavor = masterFlavor;
}
if (network) {
item.externalNetwork = network;
}
if (fixedNetwork) {
item.fixedNetwork = fixedNetwork;
}
if (fixedSubnet) {
item.fixedSubnet = fixedSubnet;
}
if (img) {
item.image = img;
}
return item;
}
}

View File

@ -25,6 +25,18 @@ export class ClustersStore extends Base {
return client.magnum.clusterTemplates;
}
get flavorClient() {
return client.nova.flavors;
}
get networkClient() {
return client.neutron.networks;
}
get subnetClient() {
return client.neutron.subnets;
}
get listWithDetail() {
return true;
}
@ -45,9 +57,41 @@ export class ClustersStore extends Base {
}
async detailDidFetch(item) {
const { cluster_template_id } = item || {};
const template = await this.templateClient.show(cluster_template_id);
const template =
(await this.templateClient.show(item.cluster_template_id)) || {};
item.template = template;
const {
flavor_id: templateFlavorId,
master_flavor_id: templateMasterFlavorId,
fixed_network: templateFixedNetworkId,
fixed_subnet: templateSubnetId,
} = template;
const flavorId = item.flavor_id || templateFlavorId;
const masterFlavorId = item.master_flavor_id || templateMasterFlavorId;
const fixedNetworkId = item.fixed_network || templateFixedNetworkId;
const fixedSubnetId = item.fixed_subnet || templateSubnetId;
const [fr = {}, mfr = {}, fx = {}, sub = {}] = await Promise.all([
flavorId ? this.flavorClient.show(flavorId) : {},
masterFlavorId ? this.flavorClient.show(masterFlavorId) : {},
fixedNetworkId ? this.networkClient.show(fixedNetworkId) : {},
fixedSubnetId ? this.subnetClient.show(fixedSubnetId) : {},
]);
const { flavor } = fr;
const { flavor: masterFlavor } = mfr;
const { network: fixedNetwork } = fx;
const { subnet: fixedSubnet } = sub;
if (flavor) {
item.flavor = flavor;
}
if (masterFlavor) {
item.masterFlavor = masterFlavor;
}
if (fixedNetwork) {
item.fixedNetwork = fixedNetwork;
}
if (fixedSubnet) {
item.fixedSubnet = fixedSubnet;
}
return item;
}