skyline-console/src/resources/floatingip.js

259 lines
7.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 globalPortStore from 'stores/neutron/port';
import globalNetworkStore from 'stores/neutron/network';
import { ipValidate } from 'utils/validate';
import globalFloatingIpsStore from 'stores/neutron/floatingIp';
const { isIPv4 } = ipValidate;
export const floatingIpStatus = {
AVAILABLE: t('Available'),
PENDING: t('Pending'),
ACTIVE: t('Active'),
ERROR: t('Error'),
DOWN: t('Down'),
};
export const resourceType = {
compute: t('Instance'),
Octavia: t('Load Balancer'),
'network:router_gateway': t('Router'),
database: t('Database Instance'),
null: '-',
};
export const transitionStatuses = ['PENDING'];
/**
* 通过port和router信息构建subnet_id => router_id的映射关系
* @param portsWithFixedIPs
* @param routerIdWithExternalNetworkInfo
* @param shouldHaveExternalGateway
* @returns {[]}
*/
export function getSubnetToRouter(
portsWithFixedIPs,
routerIdWithExternalNetworkInfo,
shouldHaveExternalGateway = true
) {
const canReachSubnetIdsWithRouterId = [];
// 将有子网的信息保存下来建立router_id => subnet_id的映射
portsWithFixedIPs.forEach((type) => {
type.forEach((port) => {
const router = routerIdWithExternalNetworkInfo.find((r) => {
if (shouldHaveExternalGateway && !r.external_gateway_info) {
return false;
}
return r.id === port.device_id;
});
if (router && router.id === port.device_id) {
port.fixed_ips.forEach((item) => {
canReachSubnetIdsWithRouterId.push({
subnet_id: item.subnet_id,
router_id: port.device_id,
});
});
}
});
});
return canReachSubnetIdsWithRouterId;
}
export async function getPortsWithFixedIPs() {
const deviceOwnerList = [
'network:router_interface_distributed',
'network:router_interface',
'network:ha_router_replicated_interface',
];
const portsWithFixedIPs = await Promise.all(
deviceOwnerList.map((item) =>
globalPortStore.pureFetchList({
device_owner: item,
fields: ['fixed_ips', 'device_id'],
})
)
);
return portsWithFixedIPs;
}
/**
* [{
* port_id || id: xxx,
* mac_addr || mac_address: xxx,
* net_id || network_id: xxx,
* fixed_ips: [{
* subnet_id: xxx,
* fixed_ip_address: xxx,
* }]
* }]
* @param interfaces
* @returns {Promise<*[]>}
*/
export async function getInterfaceWithReason(interfaces) {
const [newInterfaces, networkPromises, floatingIPPromises] =
await saveAndBuildPromisesFromInterfaces(interfaces);
const interfacesWithReason =
await getReasonForExternalNetworkPortOrAlreadyBindFip(
newInterfaces,
networkPromises,
floatingIPPromises
);
return interfacesWithReason;
}
export async function saveAndBuildPromisesFromInterfaces(interfaces) {
const networkPromises = [];
const floatingIPPromises = [];
const instanceIPs = [];
interfaces.forEach((i) => {
const port_id = i.port_id || i.id;
const mac_address = i.mac_addr || i.mac_address || '';
const network_id = i.net_id || i.network_id;
// 保存interface的子网信息
i.fixed_ips.forEach((fixed_ip) => {
instanceIPs.push({
// params before '||' used for build self, after is used for list by backend
port_id,
fixed_ip_address: fixed_ip.ip_address,
mac_address,
subnet_id: fixed_ip.subnet_id,
network_id,
});
networkPromises.push(globalNetworkStore.fetchDetail({ id: network_id }));
isIPv4(fixed_ip.ip_address)
? floatingIPPromises.push(
globalFloatingIpsStore.pureFetchList({
fixed_ip_address: fixed_ip.ip_address,
})
)
: floatingIPPromises.push(Promise.resolve([]));
});
});
return [instanceIPs, networkPromises, floatingIPPromises];
}
export async function getReasonForExternalNetworkPortOrAlreadyBindFip(
interfaces,
networkPromises,
floatingIPPromises
) {
const ret = [...interfaces];
// 获取网络名称
const networkDetails = await Promise.all(networkPromises);
networkDetails.forEach((network, index) => {
ret[index].network_name = network.name;
// ret[index]['router:external'] = network['router:external'];
});
// 提供判断是否为外部网络的网卡
const externalNetworks = await globalNetworkStore.pureFetchList({
'router:external': true,
});
ret.forEach((i) => {
if (isExternalNetwork()) {
i['router:external'] = true;
} else {
i['router:external'] = false;
}
function isExternalNetwork() {
return externalNetworks.some((extNetwork) =>
extNetwork.subnets.includes(i.subnet_id)
);
}
});
// 提供判断是否已经绑定了浮动ip
const floatingIPs = await Promise.all(floatingIPPromises);
floatingIPs.forEach((floatingip, index) => {
ret[index].floatingIP =
(floatingip[0] &&
floatingip[0].port_id === ret[index].port_id &&
floatingip[0].floating_ip_address) ||
'';
});
return ret;
}
/**
* get all fips from router id
* @param router
* @returns {Promise<*[]|*>}
*/
export async function getFipsFromRouterId(router) {
const { routerIdWithExternalNetworkInfo } = this.state;
// 从路由id获取路由的external_network_id
const info = routerIdWithExternalNetworkInfo.find(
(i) => i.id === router.router_id
);
if (!info.external_gateway_info) {
return [];
}
const external_network_id = info.external_gateway_info.network_id;
// 获取所有network_id === 从路由id获取路由的external_network_id的浮动ip
const fips = await globalFloatingIpsStore.pureFetchList({
floating_network_id: external_network_id,
status: 'DOWN',
project_id: this.currentProjectId,
});
// 获取外部网络的名称
const external_network_info = await globalNetworkStore.fetchDetail({
id: external_network_id,
});
return fips
.filter((fip) => !fip.fixed_ip_address && !fip.port_details)
.map((fip) => {
fip.network_name = external_network_info.name;
fip.name = fip.floating_ip_address;
return fip;
});
}
export async function handleFixedIPChange(e) {
this.setState({
fipLoading: true,
});
const { canReachSubnetIdsWithRouterId } = this.state;
if (!e.selectedRows.length) {
this.setState({
fixed_ip: null,
canAssociateFloatingIPs: [],
fipLoading: false,
});
}
const item = e.selectedRows[0];
const totalFips = [];
// 考虑单subnet连接多个路由并且路由开启了不同的公网网关。
// 从interface的子网获取到子网所在路由的id
const routerIds = canReachSubnetIdsWithRouterId.filter(
(i) => i.subnet_id === item.subnet_id
);
const results = await Promise.all(
routerIds.map((router) => getFipsFromRouterId.call(this, router))
);
results.forEach((fips) => {
totalFips.push(...fips);
});
const fipMap = {};
totalFips.forEach((fip) => {
fipMap[fip.id] = fip;
});
const norepeatFips = Object.values(fipMap);
this.setState({
fixed_ip: item,
canAssociateFloatingIPs: norepeatFips,
fipLoading: false,
});
}