340 lines
9.2 KiB
JavaScript
340 lines
9.2 KiB
JavaScript
// Copyright 2021 99cloud
|
|
//
|
|
// 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 globalKeyPairStore from 'stores/nova/keypair';
|
|
import globalServerStore from 'stores/nova/instance';
|
|
import globalHypervisorStore from 'stores/nova/hypervisor';
|
|
import globalServerGroupStore from 'stores/nova/server-group';
|
|
import policyType from 'resources/server-group';
|
|
import Base from 'components/Form';
|
|
import { getPasswordOtherRule } from 'utils/validate';
|
|
import { hypervisorColumns, hypervisorFilters } from 'resources/hypervisor';
|
|
import { physicalNodeTypes } from 'resources/instance';
|
|
|
|
@inject('rootStore')
|
|
@observer
|
|
export default class SystemStep extends Base {
|
|
init() {
|
|
this.keyPairStore = globalKeyPairStore;
|
|
this.serverStore = globalServerStore;
|
|
this.hypervisorStore = globalHypervisorStore;
|
|
this.serverGroupStore = globalServerGroupStore;
|
|
this.getKeypairs();
|
|
this.hasAdminRole && this.getHypervisors();
|
|
this.getServerGroups();
|
|
}
|
|
|
|
get title() {
|
|
return 'SystemStep';
|
|
}
|
|
|
|
get name() {
|
|
return 'SystemStep';
|
|
}
|
|
|
|
get keypairs() {
|
|
return (this.keyPairStore.list.data || []).map((it) => ({
|
|
...it,
|
|
key: it.name,
|
|
id: it.name,
|
|
}));
|
|
}
|
|
|
|
get hypervisors() {
|
|
return (this.hypervisorStore.list.data || []).map((it) => ({
|
|
...it,
|
|
key: it.id,
|
|
name: it.hypervisor_hostname,
|
|
}));
|
|
}
|
|
|
|
get serverGroups() {
|
|
return (this.serverGroupStore.list.data || [])
|
|
.filter((it) => {
|
|
const { servergroup } = this.locationParams;
|
|
return servergroup ? it.id === servergroup : true;
|
|
})
|
|
.map((it) => ({
|
|
...it,
|
|
key: it.id,
|
|
}));
|
|
}
|
|
|
|
get inputHelp() {
|
|
const { input = '' } = this.state;
|
|
const maxCount = 1000;
|
|
return t(
|
|
'Entered: {length, plural, =1 {one character} other {# characters} }(maximum {maxCount} characters)',
|
|
{ length: input.length, maxCount }
|
|
);
|
|
}
|
|
|
|
get sourceInfo() {
|
|
const { context = {} } = this.props;
|
|
const {
|
|
source = {},
|
|
image = {},
|
|
bootableVolume = {},
|
|
instanceSnapshot = {},
|
|
} = context;
|
|
if (source.value === 'image') {
|
|
const { selectedRows = [] } = image;
|
|
return selectedRows.length && selectedRows[0];
|
|
}
|
|
if (source.value === 'bootableVolume') {
|
|
const { selectedRows = [] } = bootableVolume;
|
|
// create instace from instance list
|
|
const originData =
|
|
(selectedRows.length && selectedRows[0].origin_data) || {};
|
|
// create instace from volume list
|
|
const volumeImageMetadata =
|
|
selectedRows.length && selectedRows[0].volume_image_metadata;
|
|
return originData.volume_image_metadata || volumeImageMetadata;
|
|
}
|
|
if (source.value === 'instanceSnapshot') {
|
|
const { selectedRows = [] } = instanceSnapshot;
|
|
return selectedRows.length && selectedRows[0];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
get isWindowsImage() {
|
|
return this.sourceInfo && this.sourceInfo.os_distro === 'windows';
|
|
}
|
|
|
|
get defaultValue() {
|
|
const { servergroup } = this.locationParams;
|
|
const { context = {} } = this.props;
|
|
const data = {
|
|
loginType:
|
|
context.loginType ||
|
|
(this.isWindowsImage ? this.loginTypes[1] : this.loginTypes[0]),
|
|
more: false,
|
|
physicalNodeType: physicalNodeTypes[0],
|
|
userData: '',
|
|
};
|
|
if (servergroup) {
|
|
data.serverGroup = {
|
|
selectedRowKeys: [servergroup],
|
|
selectedRows: this.serverGroups.filter((it) => it.id === servergroup),
|
|
};
|
|
}
|
|
return data;
|
|
}
|
|
|
|
get loginTypes() {
|
|
return [
|
|
{
|
|
label: t('Keypair'),
|
|
value: 'keypair',
|
|
disabled: this.isWindowsImage,
|
|
},
|
|
{
|
|
label: t('Password'),
|
|
value: 'password',
|
|
},
|
|
];
|
|
}
|
|
|
|
allowed = () => Promise.resolve();
|
|
|
|
getKeypairs() {
|
|
this.keyPairStore.fetchList();
|
|
}
|
|
|
|
getHypervisors() {
|
|
this.hypervisorStore.fetchList();
|
|
}
|
|
|
|
async getServerGroups() {
|
|
await this.serverGroupStore.fetchList();
|
|
this.updateDefaultValue();
|
|
}
|
|
|
|
get nameForStateUpdate() {
|
|
return [
|
|
'loginType',
|
|
'password',
|
|
'confirmPassword',
|
|
'more',
|
|
'physicalNodeType',
|
|
];
|
|
}
|
|
|
|
get loginUserName() {
|
|
return this.sourceInfo && this.sourceInfo.os_admin_user;
|
|
}
|
|
|
|
get formItems() {
|
|
const { loginType, more = false, physicalNodeType } = this.state;
|
|
const isPassword = loginType === this.loginTypes[1].value;
|
|
const isManually = physicalNodeType === physicalNodeTypes[1].value;
|
|
|
|
return [
|
|
{
|
|
name: 'name',
|
|
label: t('Name'),
|
|
type: 'input-name',
|
|
placeholder: t('Please input name'),
|
|
required: true,
|
|
isInstance: true,
|
|
},
|
|
{
|
|
name: 'loginType',
|
|
label: t('Login Type'),
|
|
type: 'radio',
|
|
options: this.loginTypes,
|
|
isWrappedValue: true,
|
|
},
|
|
{
|
|
name: 'username',
|
|
label: t('Login Name'),
|
|
content: this.loginUserName || '-',
|
|
extra: this.loginUserName
|
|
? ''
|
|
: t(
|
|
"The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown."
|
|
),
|
|
tip: t(
|
|
'Whether the Login Name can be used is up to the feasible configuration of cloud-init or cloudbase-init service in the image.'
|
|
),
|
|
},
|
|
{
|
|
name: 'keypair',
|
|
label: t('Keypair'),
|
|
type: 'select-table',
|
|
datas: this.keypairs,
|
|
isMulti: false,
|
|
required: !isPassword,
|
|
hidden: isPassword,
|
|
tip: t(
|
|
'The SSH key is a way to remotely log in to the instance. The cloud platform only helps to keep the public key. Please keep your private key properly.'
|
|
),
|
|
filterParams: [
|
|
{
|
|
label: t('Name'),
|
|
name: 'name',
|
|
},
|
|
],
|
|
columns: [
|
|
{
|
|
title: t('Name'),
|
|
dataIndex: 'name',
|
|
},
|
|
{
|
|
title: t('Fingerprint'),
|
|
dataIndex: 'fingerprint',
|
|
},
|
|
],
|
|
selectedLabel: t('Keypair'),
|
|
},
|
|
{
|
|
name: 'password',
|
|
label: t('Login Password'),
|
|
type: 'input-password',
|
|
required: isPassword,
|
|
hidden: !isPassword,
|
|
otherRule: getPasswordOtherRule('password', 'instance'),
|
|
},
|
|
{
|
|
name: 'confirmPassword',
|
|
label: t('Confirm Password'),
|
|
type: 'input-password',
|
|
required: isPassword,
|
|
hidden: !isPassword,
|
|
otherRule: getPasswordOtherRule('confirmPassword', 'instance'),
|
|
},
|
|
{
|
|
type: 'divider',
|
|
},
|
|
{
|
|
name: 'more',
|
|
label: t('Advanced Options'),
|
|
type: 'more',
|
|
},
|
|
{
|
|
name: 'physicalNodeType',
|
|
label: t('Physical Node'),
|
|
type: 'radio',
|
|
hidden: !more || !this.hasAdminRole,
|
|
options: physicalNodeTypes,
|
|
isWrappedValue: true,
|
|
},
|
|
{
|
|
name: 'physicalNode',
|
|
label: ' ',
|
|
type: 'select-table',
|
|
hidden: !this.hasAdminRole || !more || !isManually,
|
|
required: isManually,
|
|
datas: this.hypervisors,
|
|
extra: t(
|
|
'You can manually specify a physical node to create an instance.'
|
|
),
|
|
columns: hypervisorColumns,
|
|
filterParams: hypervisorFilters,
|
|
},
|
|
{
|
|
name: 'serverGroup',
|
|
label: t('Server Group'),
|
|
type: 'select-table',
|
|
hidden: !more,
|
|
datas: this.serverGroups,
|
|
extra: t(
|
|
'Using server groups, you can create cloud hosts on the same/different physical nodes as much as possible to meet the affinity/non-affinity requirements of business applications.'
|
|
),
|
|
columns: [
|
|
{
|
|
title: t('Name'),
|
|
dataIndex: 'name',
|
|
},
|
|
{
|
|
title: t('Member Count'),
|
|
dataIndex: 'members',
|
|
render: (value) => value.length,
|
|
},
|
|
{
|
|
title: t('Policy'),
|
|
dataIndex: 'policy',
|
|
render: (value) => policyType[value] || '-',
|
|
},
|
|
],
|
|
filterParams: [
|
|
{
|
|
label: t('Name'),
|
|
name: 'name',
|
|
},
|
|
{
|
|
label: t('Policy'),
|
|
name: 'policy',
|
|
options: Object.keys(policyType).map((key) => ({
|
|
key,
|
|
label: policyType[key],
|
|
})),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'userData',
|
|
label: t('User Data'),
|
|
type: 'textarea-from-file',
|
|
hidden: !more,
|
|
extra: t(
|
|
'The user needs to ensure that the input is a shell script that can run completely and normally.'
|
|
),
|
|
},
|
|
];
|
|
}
|
|
}
|