diff --git a/frontend/.env b/frontend/.env index b40176c3..761d8972 100644 --- a/frontend/.env +++ b/frontend/.env @@ -5,6 +5,7 @@ NODE_PATH=src/ SKIP_PREFLIGHT_CHECK=true REACT_APP_DEBUG_TORNJAK=true REACT_APP_TORNJAK_MANAGER=false +REACT_APP_API_VERSION=v1 ##### Backend Server uri REACT_APP_API_SERVER_URI=http://localhost:10000/ diff --git a/frontend/src/components/agent-create-join-token.tsx b/frontend/src/components/agent-create-join-token.tsx index 45b02de7..65859249 100644 --- a/frontend/src/components/agent-create-join-token.tsx +++ b/frontend/src/components/agent-create-join-token.tsx @@ -7,6 +7,7 @@ import { serverSelectedFunc } from 'redux/actions'; import { RootState } from 'redux/reducers'; import { ToastContainer } from "react-toastify" import { showResponseToast, showToast } from './error-api'; +import apiEndpoints from './apiConfig'; type CreateJoinTokenProp = { globalServerSelected: string, @@ -102,7 +103,7 @@ class CreateJoinToken extends Component { getApiEntryCreateEndpoint(): string { if (!IsManager) { - return GetApiServerUri('/api/tornjak/clusters/create') + return GetApiServerUri(apiEndpoints.tornjakClustersApi) } else if (IsManager && this.state.selectedServer !== "") { return GetApiServerUri('/manager-api/tornjak/clusters/create') + "/" + this.state.selectedServer } else { diff --git a/frontend/src/components/cluster-edit.tsx b/frontend/src/components/cluster-edit.tsx index d04c1f96..942037d2 100644 --- a/frontend/src/components/cluster-edit.tsx +++ b/frontend/src/components/cluster-edit.tsx @@ -27,6 +27,7 @@ import { DebugServerInfo, } from './types'; import { showResponseToast, showToast } from './error-api'; +import apiEndpoints from './apiConfig'; type ClusterEditProp = { // tornjak server debug info of the selected server @@ -259,7 +260,7 @@ class ClusterEdit extends Component { getApiEntryCreateEndpoint(): string { if (!IsManager) { - return GetApiServerUri('/api/tornjak/clusters/edit') + return GetApiServerUri(apiEndpoints.tornjakClustersApi) } if (IsManager && this.state.selectedServer !== "") { return GetApiServerUri('/manager-api/tornjak/clusters/edit') + "/" + this.state.selectedServer @@ -342,7 +343,7 @@ class ClusterEdit extends Component { return } - axios.post(endpoint, cjtData) + axios.patch(endpoint, cjtData) .then( res => this.setState({ message: "Request:" + JSON.stringify(cjtData, null, ' ') + "\n\nSuccess:" + JSON.stringify(res.data, null, ' '), diff --git a/frontend/src/components/entry-create.tsx b/frontend/src/components/entry-create.tsx index 472f6951..5870eb3b 100644 --- a/frontend/src/components/entry-create.tsx +++ b/frontend/src/components/entry-create.tsx @@ -47,6 +47,7 @@ import EntryExpiryFeatures from './entry-expiry-features'; import CreateEntryJson from './entry-create-json'; import { ToastContainer } from "react-toastify" import { showResponseToast, showToast } from './error-api'; +import apiEndpoints from './apiConfig'; // import PropTypes from "prop-types"; // needed for testing will be removed on last pr type CreateEntryProp = { @@ -573,7 +574,7 @@ class CreateEntry extends Component { getApiEntryCreateEndpoint(): string { if (!IsManager) { - return GetApiServerUri('/api/entry/create') + return GetApiServerUri(apiEndpoints.spireEntriesApi) } if (IsManager && this.state.selectedServer !== "") { return GetApiServerUri('/manager-api/entry/create') + "/" + this.state.selectedServer diff --git a/frontend/src/components/tornjak-api-helpers.tsx b/frontend/src/components/tornjak-api-helpers.tsx index df847ada..5a1d4f64 100644 --- a/frontend/src/components/tornjak-api-helpers.tsx +++ b/frontend/src/components/tornjak-api-helpers.tsx @@ -18,6 +18,7 @@ import { showResponseToast } from './error-api'; // import { logError } from './helpers'; // import { displayResponseError } from './error-api'; import { env } from '../env'; +import apiEndpoints from './apiConfig'; const Auth_Server_Uri = env.REACT_APP_AUTH_SERVER_URI; type TornjakApiProp = {} @@ -61,7 +62,7 @@ class TornjakApi extends Component { spireHealthCheckingFunc: { (globalSpireHealthChecking: boolean): void; }, ) => { spireHealthCheckingFunc(false); - axios.get(GetApiServerUri("/api/healthcheck"), { crossdomain: true }) + axios.get(GetApiServerUri(apiEndpoints.spireHealthCheckApi), { crossdomain: true }) .then(response => { console.log("SPIRE HEALTH:", response.data.status); if (response.data.status === 1) { @@ -77,56 +78,17 @@ class TornjakApi extends Component { }) } - registerSelectors = (serverName: string, wLoadAttdata: { spiffeid: string; plugin: string; }, - refreshSelectorsState: { (serverName: string, agentworkloadSelectorInfoFunc: (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]) => void): void; }, - agentworkloadSelectorInfoFunc: (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]) => void) => { - axios.post(GetApiServerUri('/manager-api/tornjak/selectors/register/') + serverName, wLoadAttdata) - .then(res => { - refreshSelectorsState(serverName, agentworkloadSelectorInfoFunc); - } - ) - .catch((error) => { - showResponseToast(error, { caption: "Could not register selectors." }) - }) - } - + // registerLocalSelectors registers the selected selectors in local mode registerLocalSelectors = (wLoadAttdata: { spiffeid: string; plugin: string; }, refreshLocalSelectorsState: { (agentworkloadSelectorInfoFunc: (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]) => void): void; }, agentworkloadSelectorInfoFunc: (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]) => void) => { - axios.post(GetApiServerUri('/api/tornjak/selectors/register'), wLoadAttdata) + axios.post(GetApiServerUri(apiEndpoints.tornjakSelectorsApi), wLoadAttdata) .then(res => refreshLocalSelectorsState(agentworkloadSelectorInfoFunc)) .catch((error) => { showResponseToast(error, { caption: "Could not register local selectors." }) }) } - // refreshSelectorsState returns the list agent's with their workload plugin info for the selected server in manager mode - // [ - // "agent1workloadselectorinfo": [ - // { - // "id": "agentid", - // "spiffeid": "agentspiffeeid", - // "selectors": "agentworkloadselectors" - // } - // ], - // "agent2workloadselectorinfo": [ - // { - // "id": "agentid", - // "spiffeid": "agentspiffeeid", - // "selectors": "agentworkloadselectors" - // } - // ] - // ] - refreshSelectorsState = (serverName: string, - agentworkloadSelectorInfoFunc: { - (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]): void; - (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]): void; - }) => { - axios.get(GetApiServerUri("/manager-api/tornjak/selectors/list/") + serverName, { crossdomain: true }) - .then(response => { - agentworkloadSelectorInfoFunc(response.data["agents"]); - }) - .catch((error) => showResponseToast(error, { caption: "Could not refresh selector state." })) - } + // refreshLocalSelectorsState returns the list agent's with their workload plugin info for the local server // [ // "agent1workloadselectorinfo": [ @@ -147,7 +109,7 @@ class TornjakApi extends Component { refreshLocalSelectorsState = (agentworkloadSelectorInfoFunc: { (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]): void; }) => { - axios.get(GetApiServerUri("/api/tornjak/selectors/list"), { crossdomain: true }) + axios.get(GetApiServerUri(apiEndpoints.tornjakSelectorsApi), { crossdomain: true }) .then(response => { console.log(response.data) agentworkloadSelectorInfoFunc(response.data["agents"]) @@ -155,56 +117,19 @@ class TornjakApi extends Component { .catch((error) => showResponseToast(error, { caption: "Could not refresh local selector states." })) } - // populateTornjakAgentInfo returns tornjak info of requested agents including cluster name and selector - populateTornjakAgentInfo = (serverName: string, - agentworkloadSelectorInfoFunc: (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]) => void, - inputData: string) => { - axios.post(GetApiServerUri("/manager-api/tornjak/agents/list/") + serverName, inputData, - { - crossdomain: true, - }) - .then(response => { - agentworkloadSelectorInfoFunc(response.data["agents"]); - }) - .catch((error) => showResponseToast(error, { caption: "Could not populate tornjak agent info." })) - } - // populateLocalTornjakAgentInfo returns tornjak info of requested agents including cluster name and selector populateLocalTornjakAgentInfo = ( agentworkloadSelectorInfoFunc: (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]) => void, - inputData: string + inputData: string // Assuming this input data is used as query parameters ) => { - axios.post(GetApiServerUri("/api/tornjak/agents/list"), inputData, { crossdomain: true }) + axios.get(GetApiServerUri(apiEndpoints.tornjakAgentsApi), { + params: { input: inputData }, // Add inputData as query parameter + crossdomain: true + }) .then(response => { - agentworkloadSelectorInfoFunc(response.data["agents"]) + agentworkloadSelectorInfoFunc(response.data["agents"]); }) - .catch((error) => showResponseToast(error, { caption: "Could not populate local tornjak agent info." })) - } - - // populateTornjakServerInfo returns the tornjak server info of the selected server in manager mode - populateTornjakServerInfo = ( - serverName: string, - tornjakServerInfoUpdateFunc: { (globalTornjakServerInfo: TornjakServerInfo): void }, - tornjakMessageFunc: { (globalErrorMessage: string): void } - ) => { - axios.get(GetApiServerUri('/manager-api/tornjak/serverinfo/') + serverName, { crossdomain: true }) - .then(response => { - tornjakServerInfoUpdateFunc(response.data) - tornjakMessageFunc(response.statusText) - }).catch(error => { - showResponseToast(error, { caption: "Could not populate tornjak server info." }) - tornjakServerInfoUpdateFunc({ - plugins: { - DataStore: [], - KeyManager: [], - NodeAttestor: [], - NodeResolver: [], - Notifier: [] - }, - trustDomain: "", - verboseConfig: "" - }); - }); + .catch((error) => showResponseToast(error, { caption: "Could not populate local tornjak agent info." })); } // populateLocalTornjakDebugServerInfo returns the debug server info of the server in local mode @@ -212,7 +137,7 @@ class TornjakApi extends Component { spireDebugServerInfoUpdateFunc: { (globalDebugServerInfo: DebugServerInfo): void }, tornjakMessageFunc: { (globalErrorMessage: string): void } ) => { - axios.get(GetApiServerUri('/api/debugserver'), { crossdomain: true }) + axios.get(GetApiServerUri(apiEndpoints.spireServerInfoApi), { crossdomain: true }) .then(response => { spireDebugServerInfoUpdateFunc(response.data) tornjakMessageFunc(response.statusText) @@ -227,7 +152,7 @@ class TornjakApi extends Component { tornjakServerInfoUpdateFunc: { (globalTornjakServerInfo: TornjakServerInfo): void }, tornjakMessageFunc: { (globalErrorMessage: string): void } ) => { - axios.get(GetApiServerUri('/api/tornjak/serverinfo'), { crossdomain: true }) + axios.get(GetApiServerUri(apiEndpoints.tornjakServerInfoApi), { crossdomain: true }) .then(response => { if (response.status === 200) { tornjakServerInfoUpdateFunc(response.data) @@ -266,25 +191,10 @@ class TornjakApi extends Component { serverInfoUpdateFunc(reqInfo); } - populateEntriesUpdate = (serverName: string, - entriesListUpdateFunc: { (globalEntriesList: EntriesList[]): void; }, - tornjakMessageFunc: { (globalErrorMessage: string): void; }) => { - axios.get(GetApiServerUri('/manager-api/entry/list/') + serverName, { crossdomain: true }) - .then(response => { - if (!response.data["entries"]) { - entriesListUpdateFunc([]); - } else { entriesListUpdateFunc(response.data["entries"]); } - tornjakMessageFunc(response.statusText); - }).catch(error => { - entriesListUpdateFunc([]); - tornjakMessageFunc("Error retrieving " + serverName + " : " + error + (typeof (error.response) !== "undefined" ? ":" + error.response.data : "")); - showResponseToast(error, { caption: "Could not populate entries." }) - }) - } - + // populateLocalEntriesUpdate - returns the list of entries with their info in Local mode for the server populateLocalEntriesUpdate = (entriesListUpdateFunc: { (globalEntriesList: EntriesList[]): void; }, tornjakMessageFunc: { (globalErrorMessage: string): void; }) => { - axios.get(GetApiServerUri('/api/entry/list'), { crossdomain: true }) + axios.get(GetApiServerUri(apiEndpoints.spireEntriesApi), { crossdomain: true }) .then(response => { if (!response.data["entries"]) { entriesListUpdateFunc([]) @@ -299,30 +209,12 @@ class TornjakApi extends Component { }) } - // populateAgentsUpdate returns the list of agents with their info in manager mode for the selected server - populateAgentsUpdate = (serverName: string, - agentsListUpdateFunc: { (globalAgentsList: AgentsList[]): void; }, - tornjakMessageFunc: { (globalErrorMessage: string): void; }) => { - axios.get(GetApiServerUri('/manager-api/agent/list/') + serverName, { crossdomain: true }) - .then(response => { - if (!response.data["agents"]) { - agentsListUpdateFunc([]); - } else { agentsListUpdateFunc(response.data["agents"]); } - tornjakMessageFunc(response.statusText); - }).catch(error => { - showResponseToast(error, { caption: "Could not populate agents." }) - agentsListUpdateFunc([]); - tornjakMessageFunc("Error retrieving " + serverName + " : " + error.message); - }); - - } - // populateLocalAgentsUpdate - returns the list of agents with their info in Local mode for the server populateLocalAgentsUpdate = (agentsListUpdateFunc: { (globalAgentsList: AgentsList[]): void; }, tornjakMessageFunc: { (globalErrorMessage: string): void; }) => { - axios.get(GetApiServerUri('/api/agent/list'), { crossdomain: true }) + axios.get(GetApiServerUri(apiEndpoints.spireAgentsApi), { crossdomain: true }) .then(response => { if (!response.data["agents"]) { agentsListUpdateFunc([]); @@ -336,27 +228,12 @@ class TornjakApi extends Component { }) } - // populateClustersUpdate returns the list of clusters with their info in manager mode for the selected server - populateClustersUpdate = (serverName: string, - clustersListUpdateFunc: { (globalClustersList: ClustersList[]): void; }, - tornjakMessageFunc: { (globalErrorMessage: string): void; }) => { - axios.get(GetApiServerUri('/manager-api/tornjak/clusters/list/') + serverName, { crossdomain: true }) - .then(response => { - clustersListUpdateFunc(response.data["clusters"]); - tornjakMessageFunc(response.statusText); - }).catch(error => { - showResponseToast(error, { caption: "Could not populate clusters." }) - clustersListUpdateFunc([]); - tornjakMessageFunc("Error retrieving " + serverName + " : " + error.message); - }); - } - // populateLocalClustersUpdate - returns the list of clusters with their info in Local mode for the server populateLocalClustersUpdate = ( clustersListUpdateFunc: { (globalClustersList: ClustersList[]): void }, tornjakMessageFunc: { (globalErrorMessage: string): void } ) => { - axios.get(GetApiServerUri('/api/tornjak/clusters/list'), { crossdomain: true }) + axios.get(GetApiServerUri(apiEndpoints.tornjakClustersApi), { crossdomain: true }) .then(response => { clustersListUpdateFunc(response.data["clusters"]) tornjakMessageFunc(response.statusText) @@ -368,14 +245,59 @@ class TornjakApi extends Component { }) } - // clusterDelete - returns success message after successful deletion of a cluster in manager mode - async clusterDelete(serverName: string, inputData: { cluster: { name: string; }; }, clustersListUpdateFunc: { (globalClustersList: ClustersList[]): void }, globalClustersList: any[]) { - const response = await axios.post(GetApiServerUri("/manager-api/tornjak/clusters/delete/") + serverName, inputData, + // localClusterDelete - returns success message after successful deletion of a cluster in Local mode for the server + + async localClusterDelete( + inputData: { cluster: { name: string } }, + clustersListUpdateFunc: { (globalClustersList: ClustersList[]): void }, + globalClustersList: any[] + ) { + try { + const response = await axios.delete(GetApiServerUri(apiEndpoints.tornjakClustersApi), { + data: inputData, + headers: { + 'Content-Type': 'application/json' + }, + crossdomain: true, + }); + clustersListUpdateFunc(globalClustersList.filter(el => el.name !== inputData.cluster.name)); + return response.data; + } catch (error) { + return error; + } + } + + // localEntryDelete - returns success message after successful deletion of a entry in Local mode for the server + async localEntryDelete( + inputData: { ids: string[] }, + entriesListUpdateFunc: { (globalEntriesList: EntriesList[]): void }, + globalEntriesList: EntriesList[] + ) { + try { + const response = await axios.delete(GetApiServerUri(apiEndpoints.spireEntriesApi), { + data: { ids: inputData.ids }, + headers: { + 'Content-Type': 'application/json' + }, + crossdomain: true, + }); + entriesListUpdateFunc(globalEntriesList.filter(el => !inputData.ids.includes(el.id))); + return response.data; + } catch (error) { + return error; + } + } + + // manager apis + + // entryDelete - returns success message after successful deletion of a entry in manager mode + async entryDelete(serverName: string, inputData: { ids: string[] }, entriesListUpdateFunc: { (globalEntriesList: EntriesList[]): void }, globalEntriesList: any[]) { + const response = await axios.post(GetApiServerUri("/manager-api/tornjak/entry/delete/") + serverName, inputData, { crossdomain: true, }) .then(function (response) { - clustersListUpdateFunc(globalClustersList.filter(el => + entriesListUpdateFunc(globalEntriesList.filter(el => el.name !== inputData)) return response.data; }) @@ -385,9 +307,9 @@ class TornjakApi extends Component { return response.data; } - // localClusterDelete - returns success message after successful deletion of a cluster in Local mode for the server - async localClusterDelete(inputData: { cluster: { name: string; }; }, clustersListUpdateFunc: { (globalClustersList: ClustersList[]): void }, globalClustersList: any[]) { - const response = await axios.post(GetApiServerUri("/api/tornjak/clusters/delete"), inputData, + // clusterDelete - returns success message after successful deletion of a cluster in manager mode + async clusterDelete(serverName: string, inputData: { cluster: { name: string; }; }, clustersListUpdateFunc: { (globalClustersList: ClustersList[]): void }, globalClustersList: any[]) { + const response = await axios.post(GetApiServerUri("/manager-api/tornjak/clusters/delete/") + serverName, inputData, { crossdomain: true, }) @@ -399,7 +321,139 @@ class TornjakApi extends Component { .catch(function (error) { return error.message; }) - return response; + return response.data; + } + + // populateClustersUpdate returns the list of clusters with their info in manager mode for the selected server + populateClustersUpdate = (serverName: string, + clustersListUpdateFunc: { (globalClustersList: ClustersList[]): void; }, + tornjakMessageFunc: { (globalErrorMessage: string): void; }) => { + axios.get(GetApiServerUri('/manager-api/tornjak/clusters/list/') + serverName, { crossdomain: true }) + .then(response => { + clustersListUpdateFunc(response.data["clusters"]); + tornjakMessageFunc(response.statusText); + }).catch(error => { + showResponseToast(error, { caption: "Could not populate clusters." }) + clustersListUpdateFunc([]); + tornjakMessageFunc("Error retrieving " + serverName + " : " + error.message); + }); + } + + // populateAgentsUpdate returns the list of agents with their info in manager mode for the selected server + populateAgentsUpdate = (serverName: string, + agentsListUpdateFunc: { (globalAgentsList: AgentsList[]): void; }, + tornjakMessageFunc: { (globalErrorMessage: string): void; }) => { + axios.get(GetApiServerUri('/manager-api/agent/list/') + serverName, { crossdomain: true }) + .then(response => { + if (!response.data["agents"]) { + agentsListUpdateFunc([]); + } else { agentsListUpdateFunc(response.data["agents"]); } + tornjakMessageFunc(response.statusText); + }).catch(error => { + showResponseToast(error, { caption: "Could not populate agents." }) + agentsListUpdateFunc([]); + tornjakMessageFunc("Error retrieving " + serverName + " : " + error.message); + }); + } + + // populateEntriesUpdate - returns the list of entries with their info in manager mode for the server + populateEntriesUpdate = (serverName: string, + entriesListUpdateFunc: { (globalEntriesList: EntriesList[]): void; }, + tornjakMessageFunc: { (globalErrorMessage: string): void; }) => { + axios.get(GetApiServerUri('/manager-api/entry/list/') + serverName, { crossdomain: true }) + .then(response => { + if (!response.data["entries"]) { + entriesListUpdateFunc([]); + } else { entriesListUpdateFunc(response.data["entries"]); } + tornjakMessageFunc(response.statusText); + }).catch(error => { + entriesListUpdateFunc([]); + tornjakMessageFunc("Error retrieving " + serverName + " : " + error + (typeof (error.response) !== "undefined" ? ":" + error.response.data : "")); + showResponseToast(error, { caption: "Could not populate entries." }) + }) + } + + // populateTornjakServerInfo returns the tornjak server info of the selected server in manager mode + populateTornjakServerInfo = ( + serverName: string, + tornjakServerInfoUpdateFunc: { (globalTornjakServerInfo: TornjakServerInfo): void }, + tornjakMessageFunc: { (globalErrorMessage: string): void } + ) => { + axios.get(GetApiServerUri('/manager-api/tornjak/serverinfo/') + serverName, { crossdomain: true }) + .then(response => { + tornjakServerInfoUpdateFunc(response.data) + tornjakMessageFunc(response.statusText) + }).catch(error => { + showResponseToast(error, { caption: "Could not populate tornjak server info." }) + tornjakServerInfoUpdateFunc({ + plugins: { + DataStore: [], + KeyManager: [], + NodeAttestor: [], + NodeResolver: [], + Notifier: [] + }, + trustDomain: "", + verboseConfig: "" + }); + }); + } + + // populateTornjakAgentInfo returns tornjak info of requested agents including cluster name and selector + populateTornjakAgentInfo = (serverName: string, + agentworkloadSelectorInfoFunc: (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]) => void, + inputData: string) => { + axios.post(GetApiServerUri("/manager-api/tornjak/agents/list/") + serverName, inputData, + { + crossdomain: true, + }) + .then(response => { + agentworkloadSelectorInfoFunc(response.data["agents"]); + }) + .catch((error) => showResponseToast(error, { caption: "Could not populate tornjak agent info." })) + } + + // refreshSelectorsState returns the list agent's with their workload plugin info for the selected server in manager mode + // [ + // "agent1workloadselectorinfo": [ + // { + // "id": "agentid", + // "spiffeid": "agentspiffeeid", + // "selectors": "agentworkloadselectors" + // } + // ], + // "agent2workloadselectorinfo": [ + // { + // "id": "agentid", + // "spiffeid": "agentspiffeeid", + // "selectors": "agentworkloadselectors" + // } + // ] + // ] + refreshSelectorsState = (serverName: string, + agentworkloadSelectorInfoFunc: { + (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]): void; + (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]): void; + }) => { + axios.get(GetApiServerUri("/manager-api/tornjak/selectors/list/") + serverName, { crossdomain: true }) + .then(response => { + agentworkloadSelectorInfoFunc(response.data["agents"]); + }) + .catch((error) => showResponseToast(error, { caption: "Could not refresh selector state." })) + } + + // registerSelectors registers the selected selectors in manager mode + registerSelectors = (serverName: string, wLoadAttdata: { spiffeid: string; plugin: string; }, + refreshSelectorsState: { (serverName: string, agentworkloadSelectorInfoFunc: (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]) => void): void; }, + agentworkloadSelectorInfoFunc: (globalAgentsWorkLoadAttestorInfo: AgentsWorkLoadAttestorInfo[]) => void) => { + axios.post(GetApiServerUri('/manager-api/tornjak/selectors/register/') + serverName, wLoadAttdata) + .then(res => { + refreshSelectorsState(serverName, agentworkloadSelectorInfoFunc); + } + ) + .catch((error) => { + showResponseToast(error, { caption: "Could not register selectors." }) + }) } } diff --git a/frontend/src/env.ts b/frontend/src/env.ts index 3e12aa81..2e414d2d 100644 --- a/frontend/src/env.ts +++ b/frontend/src/env.ts @@ -10,5 +10,6 @@ declare global { REACT_APP_TORNJAK_MANAGER: string, REACT_APP_KEYCLOAK_REALM: string, REACT_APP_OIDC_CLIENT_ID: string, + REACT_APP_API_VERSION: string, } export const env: EnvType = { ...process.env, ...window.env } \ No newline at end of file diff --git a/frontend/src/tables/agents-list-table.tsx b/frontend/src/tables/agents-list-table.tsx index f193154b..e3fb7ad1 100644 --- a/frontend/src/tables/agents-list-table.tsx +++ b/frontend/src/tables/agents-list-table.tsx @@ -11,6 +11,7 @@ import { AgentsList, AgentsWorkLoadAttestorInfo } from "components/types"; import { DenormalizedRow } from "carbon-components-react"; import { RootState } from "redux/reducers"; import { showResponseToast } from "components/error-api"; +import apiEndpoints from 'components/apiConfig'; // AgentListTable takes in // listTableData: agents data to be rendered on table @@ -99,7 +100,7 @@ class AgentsListTable extends React.Component { @@ -127,33 +134,34 @@ class AgentsListTable extends React.Component showResponseToast(error, {caption: "Could not delete agent."})) + .catch((error) => showResponseToast(error, { caption: "Could not delete agent." })) } banAgent(selectedRows: readonly DenormalizedRow[]) { - var id: {path: string; trust_domain: string}[] = [], i = 0, endpoint = "", prefix = "spiffe://" + var id: { path: string; trust_domain: string }[] = [], i = 0, endpoint = "", prefix = "spiffe://" if (IsManager) { endpoint = GetApiServerUri('/manager-api/agent/ban') + "/" + this.props.globalServerSelected } else { - endpoint = GetApiServerUri('/api/agent/ban') + endpoint = GetApiServerUri(apiEndpoints.spireAgentsBanApi) } if (selectedRows === undefined || !selectedRows) return "" for (i = 0; i < selectedRows.length; i++) { - id[i] = {path: "", trust_domain: ""} + id[i] = { path: "", trust_domain: "" } id[i].trust_domain = selectedRows[i].cells[1].value id[i].path = selectedRows[i].cells[2].value.substr(selectedRows[i].cells[1].value.concat(prefix).length) - axios.post(endpoint, {id: {trust_domain: id[i].trust_domain, path: id[i].path}}) + axios.post(endpoint, { id: { trust_domain: id[i].trust_domain, path: id[i].path } }) .then(res => { alert("Ban SUCCESS") this.componentDidMount() }) - .catch((error) => showResponseToast(error, {caption: "Could not ban agent."})) + .catch((error) => showResponseToast(error, { caption: "Could not ban agent." })) } } render() { diff --git a/frontend/src/tables/clusters-list-table.tsx b/frontend/src/tables/clusters-list-table.tsx index 8d86c32b..276fe130 100644 --- a/frontend/src/tables/clusters-list-table.tsx +++ b/frontend/src/tables/clusters-list-table.tsx @@ -11,6 +11,7 @@ import { ClustersList } from "components/types"; import { DenormalizedRow } from "carbon-components-react"; import { RootState } from "redux/reducers"; import { showResponseToast } from "components/error-api"; +import TornjakApi from 'components/tornjak-api-helpers'; // ClusterListTable takes in // listTableData: clusters data to be rendered on table @@ -44,8 +45,10 @@ type ClustersListTableState = { } class ClustersListTable extends React.Component { + TornjakApi: TornjakApi; constructor(props: ClustersListTableProp) { super(props); + this.TornjakApi = new TornjakApi(props); this.state = { listData: props.data, listTableData: [], @@ -88,34 +91,29 @@ class ClustersListTable extends React.Component { - if (this.props.globalClustersList === undefined) return - for (let i = 0; i < responses.length; i++) { - this.props.clustersListUpdateFunc(this.props.globalClustersList.filter(el =>el.name !== cluster[i].name)) + cluster[i] = { name: selectedRows[i].cells[1].value }; + if (IsManager) { + successMessage = this.TornjakApi.clusterDelete(this.props.globalServerSelected, { cluster: cluster[i] }, this.props.clustersListUpdateFunc, this.props.globalClustersList); + } else { + successMessage = this.TornjakApi.localClusterDelete({ cluster: cluster[i] }, this.props.clustersListUpdateFunc, this.props.globalClustersList); + } + successMessage.then(function (result) { + if (result === "SUCCESS") { + window.alert(`CLUSTER "${cluster[i].name}" DELETED SUCCESSFULLY!`); + window.location.reload(); + } else { + window.alert(`Error deleting cluster "${cluster[i].name}": ` + result); } + return; }) - .catch((error) => showResponseToast(error, {caption: "Could not delete cluster."})) + } } + render() { const { listTableData } = this.state; const headerData = [ diff --git a/frontend/src/tables/entries-list-table.tsx b/frontend/src/tables/entries-list-table.tsx index 220cd5cf..1dd33e83 100644 --- a/frontend/src/tables/entries-list-table.tsx +++ b/frontend/src/tables/entries-list-table.tsx @@ -12,6 +12,8 @@ import { RootState } from "redux/reducers"; import { DenormalizedRow } from "carbon-components-react"; import { saveAs } from "file-saver"; import { showResponseToast } from "components/error-api"; +import apiEndpoints from 'components/apiConfig'; +import TornjakApi from 'components/tornjak-api-helpers'; // EntriesListTable takes in // listTableData: entries data to be rendered on table @@ -38,8 +40,10 @@ type EntriesListTableState = { } class EntriesListTable extends React.Component { + TornjakApi: TornjakApi; constructor(props: EntriesListTableProp) { super(props); + this.TornjakApi = new TornjakApi(props); this.state = { listData: props.data, listTableData: [{ "id": "0" }], @@ -83,33 +87,36 @@ class EntriesListTable extends React.Component { - if (this.props.globalEntriesList === undefined) { - return - } - for (let i = 0; i < responses.length; i++) { - this.props.entriesListUpdateFunc(this.props.globalEntriesList.filter(el => el.id !== responses[i].data.results[0].id)) + if (!selectedRows || selectedRows.length === 0) return ""; + + // Collect the IDs of the selected entries + const idsToDelete = selectedRows.map(row => row.cells[1].value); + + const deletePromise = IsManager + ? this.TornjakApi.entryDelete(this.props.globalServerSelected, { ids: idsToDelete }, this.props.entriesListUpdateFunc, this.props.globalEntriesList) + : this.TornjakApi.localEntryDelete({ ids: idsToDelete }, this.props.entriesListUpdateFunc, this.props.globalEntriesList); + + deletePromise + .then(response => { + const results = response.results; // Ensure you're accessing the 'results' array in the response + + if (Array.isArray(results)) { + const successIds = results.map(result => result.id); + const failedIds = idsToDelete.filter(id => !successIds.includes(id)); + + if (failedIds.length === 0) { + window.alert(`Entries deleted successfully!`); + window.location.reload(); // Reload the page or update the UI as needed + } else { + window.alert(`Error deleting entries with IDs: ${failedIds.join(', ')}`); + } + } else { + window.alert("Unexpected response format. Could not delete entries."); } }) - .catch((error) => showResponseToast(error, {caption: "Could not delete entry."})) + .catch(error => { + window.alert(`Error deleting entries: ${error.message}`); + }); } downloadEntries(selectedRows: readonly DenormalizedRow[]) { @@ -117,14 +124,14 @@ class EntriesListTable extends React.Component