feat: Support manila share server

1. Add share server in administrator
2. Add share server detail in administrator
3. Add share tab in share server detail
4. Add delete && batch delete share server
5. Remove access info from share detail base info tab
6. Add link to network/share/server in share instance page

Change-Id: Ifa1efb75aebb32a2928f7d7db07e228d41d0894b
This commit is contained in:
Jingwei.Zhang 2022-05-11 17:55:56 +08:00
parent bdd5a98ece
commit 3d8014c2d9
17 changed files with 433 additions and 50 deletions

View File

@ -173,6 +173,11 @@ export class ManilaClient extends Base {
key: 'quota-sets',
responseKey: 'quota_set',
},
{
name: 'shareServers',
key: 'share-servers',
responseKey: 'share_server',
},
];
}
}

View File

@ -469,6 +469,22 @@ const renderMenu = (t) => {
},
],
},
{
path: '/share/share-server-admin',
name: t('Share Server'),
key: 'shareServerAdmin',
level: 1,
endpoints: 'manilav2',
children: [
{
path: /^\/share\/share-server-admin\/detail\/.[^/]+$/,
name: t('Share Server Detail'),
key: 'shareServerDetailAdmin',
level: 2,
routePath: '/share/share-server-admin/detail/:id',
},
],
},
{
path: '/share/share-instance-admin',
name: t('Share Instance'),

View File

@ -581,6 +581,7 @@
"Delete Share Group Type": "Delete Share Group Type",
"Delete Share Metadata": "Delete Share Metadata",
"Delete Share Network": "Delete Share Network",
"Delete Share Server": "Delete Share Server",
"Delete Share Type": "Delete Share Type",
"Delete Snapshot": "Delete Snapshot",
"Delete Static Route": "Delete Static Route",
@ -1053,6 +1054,7 @@
"Instance Addr": "Instance Addr",
"Instance Architecture": "Instance Architecture",
"Instance Detail": "Instance Detail",
"Instance ID": "Instance ID",
"Instance IP": "Instance IP",
"Instance Info": "Instance Info",
"Instance Name": "Instance Name",
@ -1622,6 +1624,7 @@
"Provisioning Status": "Provisioning Status",
"Public": "Public",
"Public Access": "Public Access",
"Public Address": "Public Address",
"Public Image": "Public Image",
"Public Key": "Public Key",
"Published In": "Published In",
@ -1804,6 +1807,7 @@
"Server Group Member": "Server Group Member",
"Server Status": "Server Status",
"Service": "Service",
"Service Port ID": "Service Port ID",
"Service State": "Service State",
"Service Status": "Service Status",
"Service Status Updated": "Service Status Updated",
@ -1831,6 +1835,7 @@
"Share Protocol": "Share Protocol",
"Share Replica ID": "Share Replica ID",
"Share Server": "Share Server",
"Share Server Detail": "Share Server Detail",
"Share Type": "Share Type",
"Share Type Detail": "Share Type Detail",
"Share Type ID": "Share Type ID",
@ -2504,6 +2509,8 @@
"share instances": "share instances",
"share metadata": "share metadata",
"share network": "share network",
"share server": "share server",
"share servers": "share servers",
"share type": "share type",
"share types": "share types",
"shelve instance": "shelve instance",

View File

@ -581,6 +581,7 @@
"Delete Share Group Type": "删除共享组类型",
"Delete Share Metadata": "删除共享元数据",
"Delete Share Network": "删除共享网络",
"Delete Share Server": "删除共享服务器",
"Delete Share Type": "删除共享类型",
"Delete Snapshot": "删除快照",
"Delete Static Route": "删除静态路由",
@ -1053,6 +1054,7 @@
"Instance Addr": "所在主机",
"Instance Architecture": "云主机架构图",
"Instance Detail": "云主机详情",
"Instance ID": "实例ID",
"Instance IP": "云主机IP",
"Instance Info": "云主机信息",
"Instance Name": "云主机名称",
@ -1622,6 +1624,7 @@
"Provisioning Status": "配置状态",
"Public": "公有",
"Public Access": "公开访问",
"Public Address": "",
"Public Image": "公有镜像",
"Public Key": "公钥",
"Published In": "",
@ -1804,6 +1807,7 @@
"Server Group Member": "云主机组成员",
"Server Status": "",
"Service": "服务",
"Service Port ID": "服务端口ID",
"Service State": "服务状态",
"Service Status": "管理状态",
"Service Status Updated": "服务状态更新",
@ -1831,6 +1835,7 @@
"Share Protocol": "共享协议",
"Share Replica ID": "共享副本ID",
"Share Server": "共享服务器",
"Share Server Detail": "共享服务器详情",
"Share Type": "共享类型",
"Share Type Detail": "共享类型详情",
"Share Type ID": "共享类型ID",
@ -2504,6 +2509,8 @@
"share instances": "共享实例",
"share metadata": "共享元数据",
"share network": "共享网络",
"share server": "共享服务器",
"share servers": "共享服务器",
"share type": "共享类型",
"share types": "共享类型",
"shelve instance": "归档云主机",

View File

@ -16,7 +16,7 @@ import React from 'react';
import { inject, observer } from 'mobx-react';
import Base from 'containers/BaseDetail';
import { shareProtocol } from 'resources/manila/share';
import { getYesNo, toLocalTimeFilter } from 'utils/index';
import { getYesNo } from 'utils/index';
export class BaseDetail extends Base {
get leftCards() {
@ -32,7 +32,7 @@ export class BaseDetail extends Base {
}
get rightCards() {
return [this.exportLocationsCard, this.accessCard];
return [this.exportLocationsCard];
}
get baseInfoCard() {
@ -185,53 +185,6 @@ export class BaseDetail extends Base {
labelCol: 4,
};
}
get accessCard() {
const { accessList = [] } = this.detailData;
const access = accessList[0] || {};
const options = [
{
label: t('Access Type'),
dataIndex: 'access_type',
render: () => access.access_type,
},
{
label: t('Access To'),
dataIndex: 'access_to',
render: () => access.access_to,
},
{
label: t('Access Level'),
dataIndex: 'access_level',
render: () => access.access_level,
},
{
label: t('State'),
dataIndex: 'state',
render: () => access.state,
},
{
label: t('Access Key'),
dataIndex: 'access_key',
render: () => access.access_key,
},
{
label: t('Created At'),
dataIndex: 'created_at',
render: () => toLocalTimeFilter(access.created_at),
},
{
label: t('Updated At'),
dataIndex: 'updated_at',
render: () => toLocalTimeFilter(access.updated_at),
},
];
return {
title: t('Access Rule'),
options,
labelCol: 4,
};
}
}
export default inject('rootStore')(observer(BaseDetail));

View File

@ -51,6 +51,11 @@ export class Share extends Base {
return this.inDetailPage && pathname.includes('share-network');
}
get inShareServerDetailPage() {
const { pathname } = this.props.location;
return this.inDetailPage && pathname.includes('share-server');
}
updateFetchParamsByPage = (params) => {
const { id, ...rest } = params;
const newParams = { ...rest };
@ -63,6 +68,9 @@ export class Share extends Base {
if (this.inShareNetworkDetailPage) {
newParams.share_network_id = id;
}
if (this.inShareServerDetailPage) {
newParams.share_server_id = id;
}
return newParams;
};

View File

@ -40,6 +40,7 @@ export class ShareInstance extends Base {
dataIndex: 'id',
routeName: 'shareInstanceDetailAdmin',
isLink: true,
withoutName: true,
},
{
title: t('Host'),
@ -58,14 +59,26 @@ export class ShareInstance extends Base {
{
title: t('Share Network'),
dataIndex: 'share_network_id',
isLink: true,
routeName: this.getRouteName('shareNetworkDetail'),
idKey: 'share_network_id',
withoutName: true,
},
{
title: t('Share Server'),
dataIndex: 'share_server_id',
isLink: true,
routeName: this.getRouteName('shareServerDetail'),
idKey: 'share_server_id',
withoutName: true,
},
{
title: t('Share Id'),
dataIndex: 'share_id',
isLink: true,
routeName: this.getRouteName('shareDetail'),
idKey: 'share_id',
withoutName: true,
},
];
}

View File

@ -0,0 +1,99 @@
// 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 Base from 'containers/BaseDetail';
export class BaseDetail extends Base {
get leftCards() {
return [this.baseInfoCard];
}
get rightCards() {
return [this.detailCard];
}
get baseInfoCard() {
const options = [
{
label: t('Host'),
dataIndex: 'host',
},
{
label: t('Share Network'),
dataIndex: 'share_network_name',
render: (value, record) => {
if (!value) {
return '-';
}
const { share_network_id } = record;
const link = this.getLinkRender('shareNetworkDetail', value, {
id: share_network_id,
});
return link;
},
},
];
return {
title: t('Base Info'),
options,
};
}
get detailCard() {
const options = [
{
label: t('Instance ID'),
dataIndex: 'backend_details.instance_id',
},
{
label: t('IP'),
dataIndex: 'backend_details.ip',
},
{
label: t('Public Address'),
dataIndex: 'backend_details.public_address',
},
{
label: t('Username'),
dataIndex: 'backend_details.username',
},
{
label: t('Password'),
dataIndex: 'backend_details.password',
},
{
label: t('Router ID'),
dataIndex: 'backend_details.router_id',
},
{
label: t('Subnet ID'),
dataIndex: 'backend_details.subnet_id',
},
{
label: t('Service Port ID'),
dataIndex: 'backend_details.service_port_id',
},
];
return {
title: t('Detail Info'),
options,
labelCol: 4,
};
}
}
export default inject('rootStore')(observer(BaseDetail));

View File

@ -0,0 +1,84 @@
// 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 { ShareServerStore } from 'stores/manila/share-server';
import Base from 'containers/TabDetail';
import { shareServerStatus } from 'resources/manila/share-server';
import Share from 'pages/share/containers/Share';
import BaseDetail from './BaseDetail';
import actionConfigs from '../actions';
export class Detail extends Base {
get name() {
return t('share server');
}
get policy() {
return 'manila:share_server:show';
}
get listUrl() {
return this.getRoutePath('shareServer');
}
get actionConfigs() {
return actionConfigs;
}
get detailInfos() {
return [
{
title: t('Host'),
dataIndex: 'host',
},
{
title: t('Status'),
dataIndex: 'status',
render: (value) => shareServerStatus[value] || value,
},
{
title: t('Created'),
dataIndex: 'created_at',
valueRender: 'toLocalTime',
},
{
title: t('Updated'),
dataIndex: 'updated_at',
valueRender: 'toLocalTime',
},
];
}
get tabs() {
return [
{
title: t('Base Info'),
key: 'baseInfo',
component: BaseDetail,
},
{
title: t('Share'),
key: 'share',
component: Share,
},
];
}
init() {
this.store = new ShareServerStore();
}
}
export default inject('rootStore')(observer(Detail));

View File

@ -0,0 +1,42 @@
// 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 { ConfirmAction } from 'containers/Action';
import globalShareServerStore from 'stores/manila/share-server';
export default class Delete extends ConfirmAction {
get id() {
return 'delete';
}
get title() {
return t('Delete Share Server');
}
get buttonType() {
return 'danger';
}
get buttonText() {
return t('Delete');
}
get actionName() {
return t('Delete Share Server');
}
policy = 'manila:share_server:delete';
onSubmit = (data) => globalShareServerStore.delete(data);
}

View File

@ -0,0 +1,26 @@
// 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 Delete from './Delete';
const actionConfigs = {
rowActions: {
firstAction: Delete,
moreActions: [],
},
primaryActions: [],
batchActions: [Delete],
};
export default actionConfigs;

View File

@ -0,0 +1,71 @@
// 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 { observer, inject } from 'mobx-react';
import Base from 'containers/List';
import globalShareServerStore from 'stores/manila/share-server';
import { shareServerStatus } from 'resources/manila/share-server';
import actionConfigs from './actions';
export class ShareServer extends Base {
init() {
this.store = globalShareServerStore;
}
get policy() {
return 'manila:share_server:index';
}
get name() {
return t('share servers');
}
get actionConfigs() {
return actionConfigs;
}
getColumns = () => [
{
title: t('ID'),
dataIndex: 'id',
routeName: 'shareServerDetailAdmin',
isLink: true,
withoutName: true,
},
{
title: t('Host'),
dataIndex: 'host',
isHideable: true,
},
{
title: t('Project ID/Name'),
dataIndex: 'project_name',
isHideable: true,
},
{
title: t('Status'),
dataIndex: 'status',
render: (value) => shareServerStatus[value] || value,
},
{
title: t('Share Network'),
dataIndex: 'share_network_name',
isLink: true,
routeName: this.getRouteName('shareNetworkDetail'),
idKey: 'share_network_id',
},
];
}
export default inject('rootStore')(observer(ShareServer));

View File

@ -27,6 +27,8 @@ import ShareGroupDetail from '../containers/ShareGroup/Detail';
import Share from '../containers/Share';
import ShareDetail from '../containers/Share/Detail';
import ShareCreate from '../containers/Share/actions/Create';
import ShareServer from '../containers/ShareServer';
import ShareServerDetail from '../containers/ShareServer/Detail';
const PATH = '/share';
export default [
@ -125,6 +127,16 @@ export default [
component: ShareDetail,
exact: true,
},
{
path: `${PATH}/share-server-admin`,
component: ShareServer,
exact: true,
},
{
path: `${PATH}/share-server-admin/detail/:id`,
component: ShareServerDetail,
exact: true,
},
{ path: '*', component: E404 },
],
},

View File

@ -0,0 +1,6 @@
export const shareServerStatus = {
active: t('Active'),
error: t('Error'),
creating: t('Creating'),
deleting: t('Deleting'),
};

View File

@ -58,4 +58,5 @@ export const shareAccessRuleState = {
queued_to_apply: t('Queued To Apply'),
queued_to_deny: t('Queued To Deny'),
denying: t('Denying'),
applying: t('Applying'),
};

View File

@ -0,0 +1,32 @@
// 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 client from 'client';
import Base from 'stores/base';
export class ShareServerStore extends Base {
get client() {
return client.manila.shareServers;
}
get paramsFunc() {
return (params) => {
const { all_projects, ...rest } = params;
return rest;
};
}
}
const globalShareServerStore = new ShareServerStore();
export default globalShareServerStore;

View File

@ -197,6 +197,7 @@ export const getNameRenderByRouter = (render, column, rowKey) => {
routeParamsKey = 'id',
routeQuery = {},
routeParamsFunc,
withoutName = false,
} = column;
return (value, record) => {
const nameValue = value || get(record, dataIndex) || '-';
@ -217,7 +218,7 @@ export const getNameRenderByRouter = (render, column, rowKey) => {
return (
<div>
<div>{link}</div>
<div>{nameValue}</div>
{!withoutName && <div>{nameValue}</div>}
</div>
);
};