feat: Support network port_security_enabled

1. Update create instance with `port_security_enabled = false` network:
if one of selected networks is disable port security, disable select security group
2. Update create ironic with `port_security_enabled = false` network:
if one of selected networks is disable port security, disable select
security group
3. Update instance manage security group in instance detail page:
disable manage security group for disable security group interface
4. Update create network with port_security_enabled prop:
can change port_security_enabled prop value
5. Update edit network with port_security_enabled prop:
can change port_security_enabled prop value
6. Add port_security_enabled prop in network detail page:
show network port_security_enabled value

Change-Id: I2227a9cb84ed87b5d1eedaea206004498ef0fab9
This commit is contained in:
zhangjingwei 2021-07-14 13:24:20 +08:00 committed by Jingwei.Zhang
parent e504f7e3c6
commit 608d9ef5f4
12 changed files with 72 additions and 44 deletions

View File

@ -194,31 +194,34 @@ export default class SecurityGroup extends React.Component {
render() { render() {
const { interfaces, isLoading } = this.store.securityGroups; const { interfaces, isLoading } = this.store.securityGroups;
const { filterData, activeInterfaceId } = this.state; const { filterData, activeInterfaceId, activeInterface } = this.state;
const { port_security_enabled = false } = activeInterface || {};
return ( return (
<div className={classnames(styles.wrapper, this.className)}> <div className={classnames(styles.wrapper, this.className)}>
{interfaces && interfaces.length ? ( <Spin spinning={isLoading}>
<Spin spinning={isLoading}> <Radio.Group
<Radio.Group defaultValue={0}
defaultValue={0} size="large"
size="large" marginBottom="20"
marginBottom="20" onChange={this.onChange}
onChange={this.onChange} className={styles['radio-button']}
className={styles['radio-button']} >
> {interfaces
{toJS(interfaces).map((item, index) => ? toJS(interfaces).map((item, index) =>
this.renderRadio(item, index) this.renderRadio(item, index)
)} )
</Radio.Group> : null}
</Spin> </Radio.Group>
) : null} </Spin>
{!this.isAdminPage && ( {!this.isAdminPage && port_security_enabled && (
<div style={{ marginBottom: 20, marginTop: 20 }}> <div style={{ marginBottom: 20, marginTop: 20 }}>
<PrimaryActionButtons <PrimaryActionButtons
primaryActions={[ManageSecurityGroup]} primaryActions={[ManageSecurityGroup]}
onFinishAction={this.actionCallback} onFinishAction={this.actionCallback}
containerProps={{ containerProps={{
port: activeInterfaceId, port: activeInterfaceId,
portItem: activeInterface,
filterData, filterData,
}} }}
> >

View File

@ -63,11 +63,9 @@ export default class ConfirmStep extends Base {
getSecurityGroups() { getSecurityGroups() {
const { context } = this.props; const { context } = this.props;
const { securityGroup } = context; const { securityGroup: { selectedRows = [] } = {} } = context;
const { selectedRows } = securityGroup;
const values = selectedRows.map((it) => it.name); const values = selectedRows.map((it) => it.name);
return values; return values;
// return values.join(<br />);
} }
getLoginType() { getLoginType() {

View File

@ -159,6 +159,9 @@ export default class NetworkStep extends Base {
get formItems() { get formItems() {
const { networkSelectRows = [], subnets, initValue = [] } = this.state; const { networkSelectRows = [], subnets, initValue = [] } = this.state;
const showNetworks = networkSelectRows.length > 0; const showNetworks = networkSelectRows.length > 0;
const showSecurityGroups =
networkSelectRows.length &&
networkSelectRows.every((it) => it.port_security_enabled);
return [ return [
{ {
name: 'networkSelect', name: 'networkSelect',
@ -229,7 +232,8 @@ export default class NetworkStep extends Base {
), ),
backendPageStore: this.securityGroupStore, backendPageStore: this.securityGroupStore,
extraParams: { project_id: this.currentProjectId }, extraParams: { project_id: this.currentProjectId },
required: true, required: showSecurityGroups,
hidden: !showSecurityGroups,
isMulti: true, isMulti: true,
header: ( header: (
<div style={{ marginBottom: 8 }}> <div style={{ marginBottom: 8 }}>

View File

@ -264,8 +264,10 @@ export default class CreateIronic extends StepAction {
// // delete_on_termination: deleteType === 1, // // delete_on_termination: deleteType === 1,
// }; // };
let hasIp = false; let hasIp = false;
const { selectedRows: securityGroupSelectedRows = [] } =
securityGroup || {};
const server = { const server = {
security_groups: securityGroup.selectedRows.map((it) => ({ security_groups: securityGroupSelectedRows.map((it) => ({
name: it.id, name: it.id,
})), })),
name, name,

View File

@ -89,8 +89,7 @@ export default class ConfirmStep extends Base {
getSecurityGroups() { getSecurityGroups() {
const { context } = this.props; const { context } = this.props;
const { securityGroup } = context; const { securityGroup: { selectedRows = [] } = {} } = context;
const { selectedRows } = securityGroup;
const values = selectedRows.map((it) => it.name); const values = selectedRows.map((it) => it.name);
return values; return values;
// return values.join(<br />); // return values.join(<br />);

View File

@ -159,6 +159,9 @@ export default class NetworkStep extends Base {
get formItems() { get formItems() {
const { networkSelectRows = [], subnets, initValue = [] } = this.state; const { networkSelectRows = [], subnets, initValue = [] } = this.state;
const showNetworks = networkSelectRows.length > 0; const showNetworks = networkSelectRows.length > 0;
const showSecurityGroups =
networkSelectRows.length &&
networkSelectRows.every((it) => it.port_security_enabled);
return [ return [
{ {
name: 'networkSelect', name: 'networkSelect',
@ -229,7 +232,8 @@ export default class NetworkStep extends Base {
), ),
backendPageStore: this.securityGroupStore, backendPageStore: this.securityGroupStore,
extraParams: { project_id: this.currentProjectId }, extraParams: { project_id: this.currentProjectId },
required: true, hidden: !showSecurityGroups,
required: showSecurityGroups,
isMulti: true, isMulti: true,
header: ( header: (
<div style={{ marginBottom: 8 }}> <div style={{ marginBottom: 8 }}>

View File

@ -297,8 +297,10 @@ class StepCreate extends StepAction {
// rootVolume.disk_bus = 'ide'; // rootVolume.disk_bus = 'ide';
// dataVolumes[0].disk_bus = 'virtio'; // dataVolumes[0].disk_bus = 'virtio';
} }
const { selectedRows: securityGroupSelectedRows = [] } =
securityGroup || {};
const server = { const server = {
security_groups: securityGroup.selectedRows.map((it) => ({ security_groups: securityGroupSelectedRows.map((it) => ({
name: it.id, name: it.id,
})), })),
name, name,

View File

@ -62,6 +62,11 @@ export default class BaseDetail extends Base {
dataIndex: 'qos_policy_id', dataIndex: 'qos_policy_id',
render: (data) => data || '-', render: (data) => data || '-',
}, },
{
label: t('Port Security Enabled'),
dataIndex: 'port_security_enabled',
valueRender: 'yesNo',
},
]; ];
return { return {
title: t('Base Info'), title: t('Base Info'),

View File

@ -73,6 +73,7 @@ export default class CreateNetwork extends ModalAction {
ip_version: 'ipv4', ip_version: 'ipv4',
disable_gateway: false, disable_gateway: false,
more: false, more: false,
port_security_enabled: true,
}; };
} }
@ -91,6 +92,7 @@ export default class CreateNetwork extends ModalAction {
host_routes, host_routes,
description, description,
mtu, mtu,
port_security_enabled,
...rest ...rest
} = values; } = values;
@ -103,6 +105,7 @@ export default class CreateNetwork extends ModalAction {
description, description,
availability_zone_hints: [availableZone], availability_zone_hints: [availableZone],
mtu, mtu,
port_security_enabled,
}; };
const networkAdminPageData = { const networkAdminPageData = {
@ -303,6 +306,12 @@ export default class CreateNetwork extends ModalAction {
type: 'check', type: 'check',
hidden: !this.isSystemAdmin, hidden: !this.isSystemAdmin,
}, },
{
name: 'port_security_enabled',
label: t('Port Security Enabled'),
type: 'switch',
required: true,
},
// { // {
// name: 'admin_state_up', // name: 'admin_state_up',
// label: t('Enable Admin State'), // label: t('Enable Admin State'),

View File

@ -17,6 +17,7 @@ import { ModalAction } from 'containers/Action';
import globalNetworkStore from 'stores/neutron/network'; import globalNetworkStore from 'stores/neutron/network';
import checkPolicy, { checkPolicyRule } from 'resources/policy'; import checkPolicy, { checkPolicyRule } from 'resources/policy';
import globalRootStore from 'stores/root'; import globalRootStore from 'stores/root';
import { getYesNoList } from 'utils/index';
@inject('rootStore') @inject('rootStore')
@observer @observer
@ -49,8 +50,8 @@ export default class Edit extends ModalAction {
onSubmit = (values) => { onSubmit = (values) => {
const { item: { id } = {} } = this.props; const { item: { id } = {} } = this.props;
const { name, description, ...rest } = values; const { name, description, port_security_enabled, ...rest } = values;
const data = { name, description }; const data = { name, description, port_security_enabled };
if (this.isSystemAdmin) { if (this.isSystemAdmin) {
data.shared = rest.shared; data.shared = rest.shared;
} }
@ -85,18 +86,15 @@ export default class Edit extends ModalAction {
{ {
name: 'shared', name: 'shared',
label: t('Shared'), label: t('Shared'),
type: 'select', type: 'radio',
hidden: !this.isSystemAdmin, hidden: !this.isSystemAdmin,
options: [ options: getYesNoList(),
{ },
label: t('Yes'), {
value: true, name: 'port_security_enabled',
}, label: t('Port Security Enabled'),
{ type: 'switch',
label: t('No'), required: true,
value: false,
},
],
}, },
{ {
name: 'router:external', name: 'router:external',

View File

@ -74,9 +74,9 @@ export default class VirtualAdapterDetail extends Base {
dataIndex: 'network_id', dataIndex: 'network_id',
}, },
{ {
title: t('Port Security'), title: t('Port Security Enabled'),
dataIndex: 'port_security_enabled', dataIndex: 'port_security_enabled',
render: (data) => (data ? t('Open') : t('Close')), valueRender: 'yesNo',
}, },
{ {
title: t('Mac Address'), title: t('Mac Address'),
@ -98,12 +98,12 @@ export default class VirtualAdapterDetail extends Base {
}, },
{ {
title: t('Fixed IPs'), title: t('Fixed IPs'),
key: 'fixed ips', key: 'fixed_ips',
component: FixedIPs, component: FixedIPs,
}, },
{ {
title: t('Security Groups'), title: t('Security Groups'),
key: 'security groups', key: 'security_groups',
component: SecurityGroups, component: SecurityGroups,
}, },
{ {
@ -112,6 +112,10 @@ export default class VirtualAdapterDetail extends Base {
component: AllowedAddressPair, component: AllowedAddressPair,
}, },
]; ];
const { port_security_enabled } = this.detailData;
if (!port_security_enabled) {
return tabs.filter((it) => it.key !== 'security_groups');
}
return tabs; return tabs;
} }

View File

@ -35,7 +35,7 @@ export default class ManageSecurityGroup extends ModalAction {
static policy = 'update_port:port_security_enabled'; static policy = 'update_port:port_security_enabled';
static allowed = () => Promise.resolve(true); static allowed = (item) => Promise.resolve(item.port_security_enabled);
init() { init() {
this.securityGroupStore = new SecurityGroupStore(); this.securityGroupStore = new SecurityGroupStore();