UI Updates for receptor peering

This commit is contained in:
David O Neill
2023-12-14 21:52:34 +00:00
committed by Seth Foster
parent 6cb2cd18b0
commit 46dc61253f
5 changed files with 121 additions and 23 deletions

View File

@@ -29,6 +29,7 @@ import Notifications from './models/Notifications';
import Organizations from './models/Organizations'; import Organizations from './models/Organizations';
import ProjectUpdates from './models/ProjectUpdates'; import ProjectUpdates from './models/ProjectUpdates';
import Projects from './models/Projects'; import Projects from './models/Projects';
import ReceptorAddresses from './models/Receptor';
import Roles from './models/Roles'; import Roles from './models/Roles';
import Root from './models/Root'; import Root from './models/Root';
import Schedules from './models/Schedules'; import Schedules from './models/Schedules';
@@ -79,6 +80,7 @@ const NotificationsAPI = new Notifications();
const OrganizationsAPI = new Organizations(); const OrganizationsAPI = new Organizations();
const ProjectUpdatesAPI = new ProjectUpdates(); const ProjectUpdatesAPI = new ProjectUpdates();
const ProjectsAPI = new Projects(); const ProjectsAPI = new Projects();
const ReceptorAPI = new ReceptorAddresses()
const RolesAPI = new Roles(); const RolesAPI = new Roles();
const RootAPI = new Root(); const RootAPI = new Root();
const SchedulesAPI = new Schedules(); const SchedulesAPI = new Schedules();
@@ -130,6 +132,7 @@ export {
OrganizationsAPI, OrganizationsAPI,
ProjectUpdatesAPI, ProjectUpdatesAPI,
ProjectsAPI, ProjectsAPI,
ReceptorAPI,
RolesAPI, RolesAPI,
RootAPI, RootAPI,
SchedulesAPI, SchedulesAPI,

View File

@@ -8,6 +8,7 @@ class Instances extends Base {
this.readHealthCheckDetail = this.readHealthCheckDetail.bind(this); this.readHealthCheckDetail = this.readHealthCheckDetail.bind(this);
this.healthCheck = this.healthCheck.bind(this); this.healthCheck = this.healthCheck.bind(this);
this.readInstanceGroup = this.readInstanceGroup.bind(this); this.readInstanceGroup = this.readInstanceGroup.bind(this);
this.readReceptorAddresses = this.readReceptorAddresses.bind(this);
this.deprovisionInstance = this.deprovisionInstance.bind(this); this.deprovisionInstance = this.deprovisionInstance.bind(this);
} }
@@ -27,6 +28,10 @@ class Instances extends Base {
return this.http.get(`${this.baseUrl}${instanceId}/instance_groups/`); return this.http.get(`${this.baseUrl}${instanceId}/instance_groups/`);
} }
readReceptorAddresses(instanceId) {
return this.http.get(`${this.baseUrl}${instanceId}/receptor_addresses/`);
}
deprovisionInstance(instanceId) { deprovisionInstance(instanceId) {
return this.http.patch(`${this.baseUrl}${instanceId}/`, { return this.http.patch(`${this.baseUrl}${instanceId}/`, {
node_state: 'deprovisioning', node_state: 'deprovisioning',

View File

@@ -0,0 +1,10 @@
import Base from '../Base';
class ReceptorAddresses extends Base {
constructor(http) {
super(http);
this.baseUrl = 'api/v2/receptor_addresses/';
}
}
export default ReceptorAddresses;

View File

@@ -16,7 +16,7 @@ import { getQSConfig, parseQueryString, mergeParams } from 'util/qs';
import { useLocation, useParams } from 'react-router-dom'; import { useLocation, useParams } from 'react-router-dom';
import useRequest, { useDismissableError } from 'hooks/useRequest'; import useRequest, { useDismissableError } from 'hooks/useRequest';
import DataListToolbar from 'components/DataListToolbar'; import DataListToolbar from 'components/DataListToolbar';
import { InstancesAPI } from 'api'; import { InstancesAPI, ReceptorAPI } from 'api';
import useExpanded from 'hooks/useExpanded'; import useExpanded from 'hooks/useExpanded';
import useSelected from 'hooks/useSelected'; import useSelected from 'hooks/useSelected';
import InstancePeerListItem from './InstancePeerListItem'; import InstancePeerListItem from './InstancePeerListItem';
@@ -24,7 +24,7 @@ import InstancePeerListItem from './InstancePeerListItem';
const QS_CONFIG = getQSConfig('peer', { const QS_CONFIG = getQSConfig('peer', {
page: 1, page: 1,
page_size: 20, page_size: 20,
order_by: 'hostname', order_by: 'pk',
}); });
function InstancePeerList({ setBreadcrumb }) { function InstancePeerList({ setBreadcrumb }) {
@@ -50,14 +50,28 @@ function InstancePeerList({ setBreadcrumb }) {
data: { results, count: itemNumber }, data: { results, count: itemNumber },
}, },
actions, actions,
instances,
] = await Promise.all([ ] = await Promise.all([
InstancesAPI.readDetail(id), InstancesAPI.readDetail(id),
InstancesAPI.readPeers(id, params), InstancesAPI.readPeers(id, params),
InstancesAPI.readOptions(), InstancesAPI.readOptions(),
InstancesAPI.read(),
]); ]);
const address_list = []
for(let q = 0; q < results.length; q++) {
const receptor = results[q];
const host = instances.data.results.filter((obj) => obj.id === receptor.instance)[0];
const copy = receptor;
copy.hostname = host.hostname;
copy.node_type = host.node_type;
address_list.push(copy);
}
return { return {
instance: detail, instance: detail,
peers: results, peers: address_list,
count: itemNumber, count: itemNumber,
relatedSearchableKeys: (actions?.data?.related_search_fields || []).map( relatedSearchableKeys: (actions?.data?.related_search_fields || []).map(
(val) => val.slice(0, -8) (val) => val.slice(0, -8)
@@ -90,15 +104,60 @@ function InstancePeerList({ setBreadcrumb }) {
useSelected(peers); useSelected(peers);
const fetchInstancesToAssociate = useCallback( const fetchInstancesToAssociate = useCallback(
(params) => async (params) => {
InstancesAPI.read( const address_list = []
const instances = await InstancesAPI.read(
mergeParams(params, { mergeParams(params, {
...{ not__id: id },
...{ not__node_type: ['control', 'hybrid'] }, ...{ not__node_type: ['control', 'hybrid'] },
...{ not__hostname: instance.peers }, }))
}) const receptors = (await ReceptorAPI.read()).data.results;
),
[id, instance] // get instance ids of the current peered receptor ids
const already_peered_instance_ids = []
for(let h =0; h < instance.peers.length; h++) {
const matched = receptors.filter((obj) => obj.id === instance.peers[h]);
matched.forEach(element => {
already_peered_instance_ids.push(element.instance);
});
}
for(let q = 0; q < receptors.length; q++) {
const receptor = receptors[q];
if(already_peered_instance_ids.includes(receptor.instance)) {
// ignore reverse peers
continue
}
if(instance.peers.includes(receptor.id)) {
// no links to existing links
continue;
}
if(instance.id === receptor.instance) {
// no links to thy self
continue;
}
const host = instances.data.results.filter((obj) => obj.id === receptor.instance)[0];
if(host === undefined) {
// no hosts
continue;
}
const copy = receptor;
copy.hostname = host.hostname;
copy.node_type = host.node_type;
address_list.push(copy);
}
instances.data.results = address_list;
return instances;
},
[instance]
); );
const { const {
@@ -108,17 +167,20 @@ function InstancePeerList({ setBreadcrumb }) {
} = useRequest( } = useRequest(
useCallback( useCallback(
async (instancesPeerToAssociate) => { async (instancesPeerToAssociate) => {
const selected_hostname = instancesPeerToAssociate.map(
(obj) => obj.hostname const selected_peers = instancesPeerToAssociate.map(
(obj) => obj.id
); );
const new_peers = [ const new_peers = [
...new Set([...instance.peers, ...selected_hostname]), ...new Set([...instance.peers, ...selected_peers]),
]; ];
await InstancesAPI.update(instance.id, { peers: new_peers }); await InstancesAPI.update(instance.id, { peers: new_peers });
fetchPeers(); fetchPeers();
addToast({ addToast({
id: instancesPeerToAssociate, id: instancesPeerToAssociate,
title: t`${selected_hostname} added as a peer. Please be sure to run the install bundle for ${instance.hostname} again in order to see changes take effect.`, title: t`Peers update on ${instance.hostname}. Please be sure to run the install bundle for ${instance.hostname} again in order to see changes take effect.`,
variant: AlertVariant.success, variant: AlertVariant.success,
hasTimeout: true, hasTimeout: true,
}); });
@@ -133,17 +195,18 @@ function InstancePeerList({ setBreadcrumb }) {
error: disassociateError, error: disassociateError,
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
const new_peers = []; let new_peers = instance.peers;
const selected_hostname = selected.map((obj) => obj.hostname);
for (let i = 0; i < instance.peers.length; i++) { const selected_ids = selected.map((obj) => obj.id);
if (!selected_hostname.includes(instance.peers[i])) {
new_peers.push(instance.peers[i]); for (let i = 0; i < selected_ids.length; i++) {
} new_peers = new_peers.filter((s_id) => s_id !== selected_ids[i]);
} }
await InstancesAPI.update(instance.id, { peers: new_peers }); await InstancesAPI.update(instance.id, { peers: new_peers });
fetchPeers(); fetchPeers();
addToast({ addToast({
title: t`${selected_hostname} removed. Please be sure to run the install bundle for ${instance.hostname} again in order to see changes take effect.`, title: t`Peer removed. Please be sure to run the install bundle for ${instance.hostname} again in order to see changes take effect.`,
variant: AlertVariant.success, variant: AlertVariant.success,
hasTimeout: true, hasTimeout: true,
}); });
@@ -187,6 +250,8 @@ function InstancePeerList({ setBreadcrumb }) {
]} ]}
headerRow={ headerRow={
<HeaderRow qsConfig={QS_CONFIG} isExpandable> <HeaderRow qsConfig={QS_CONFIG} isExpandable>
<HeaderCell sortKey="address">{t`Address`}</HeaderCell>
<HeaderCell sortKey="port">{t`Port`}</HeaderCell>
<HeaderCell <HeaderCell
tooltip={t`Cannot run health check on hop nodes.`} tooltip={t`Cannot run health check on hop nodes.`}
sortKey="hostname" sortKey="hostname"
@@ -243,10 +308,12 @@ function InstancePeerList({ setBreadcrumb }) {
isModalOpen={isModalOpen} isModalOpen={isModalOpen}
onAssociate={handlePeerAssociate} onAssociate={handlePeerAssociate}
onClose={() => setIsModalOpen(false)} onClose={() => setIsModalOpen(false)}
title={t`Select Instances`} title={t`Select Peer Addresses`}
optionsRequest={readInstancesOptions} optionsRequest={readInstancesOptions}
displayKey="hostname" displayKey="hostname"
columns={[ columns={[
{ key: 'address', name: t`Address` },
{ key: 'port', name: t`Port` },
{ key: 'hostname', name: t`Name` }, { key: 'hostname', name: t`Name` },
{ key: 'node_type', name: t`Node Type` }, { key: 'node_type', name: t`Node Type` },
]} ]}

View File

@@ -43,8 +43,21 @@ function InstancePeerListItem({
}} }}
dataLabel={t`Selected`} dataLabel={t`Selected`}
/> />
<Td id={labelId} dataLabel={t`Address`}>
<Link to={`/instances/${peerInstance.instance}/details`}>
<b>{peerInstance.address}</b>
</Link>
</Td>
<Td id={labelId} dataLabel={t`Port`}>
<Link to={`/instances/${peerInstance.instance}/details`}>
<b>{peerInstance.port}</b>
</Link>
</Td>
<Td id={labelId} dataLabel={t`Name`}> <Td id={labelId} dataLabel={t`Name`}>
<Link to={`/instances/${peerInstance.id}/details`}> <Link to={`/instances/${peerInstance.instance}/details`}>
<b>{peerInstance.hostname}</b> <b>{peerInstance.hostname}</b>
</Link> </Link>
</Td> </Td>