From 671cd0373b92751b8837f31d0f88150e0263527b Mon Sep 17 00:00:00 2001
From: Mengling Ding <71745861+Meng-20@users.noreply.github.com>
Date: Fri, 6 Dec 2024 12:32:11 -0700
Subject: [PATCH] feat(webui): device discovery in cfm webui (#58)
* feat: set the nodes width based on the device id dimensions
* feat: add ipaddress to the existed devices in dashboard
* feat: add new button to discover new devices and the related interfaces
* fix: fix the bug in addDiscoveredHosts interface
* fix: fix bug in addDiscoveredBlades interface
* feat: add function addDiscoveredDevices with output popup and waiting popup
* style: separate lines for discovered blades and hosts
* feat: add waiting progress for device discovery
* feat: update the content after adding new discovered devices
* feat: distinguish node status by border color
* feat: prevent the user from manually adding blades to the CMA_Discovered_Blades appliance
* style: remove unnecessary stype setup
---
webui/src/components/Appliance/Appliances.vue | 14 +-
webui/src/components/Dashboard/Dashboard.vue | 362 +++++++++++++++++-
.../Dashboard/initial-control-elements.ts | 59 +--
.../Dashboard/initial-data-elements.ts | 61 +--
webui/src/components/Dashboard/useLayout.ts | 53 ++-
webui/src/components/Stores/ApplianceStore.ts | 99 ++++-
webui/src/components/Stores/HostStore.ts | 64 +++-
7 files changed, 625 insertions(+), 87 deletions(-)
diff --git a/webui/src/components/Appliance/Appliances.vue b/webui/src/components/Appliance/Appliances.vue
index 3651a4e7..07fe5029 100644
--- a/webui/src/components/Appliance/Appliances.vue
+++ b/webui/src/components/Appliance/Appliances.vue
@@ -93,6 +93,7 @@
variant="text"
id="addBlade"
@click="addNewBladeWindowButton"
+ :disabled="isAddBladeButtonDisabled"
>
mdi-plus-thick
BLADE
@@ -1524,6 +1525,12 @@ export default {
ComposeMemoryButton,
},
+ computed: {
+ isAddBladeButtonDisabled() {
+ return this.selectedApplianceId === "CMA_Discovered_Blades";
+ },
+ },
+
methods: {
/* Open the add appliance popup */
addNewApplianceWindowButton() {
@@ -1985,7 +1992,10 @@ export default {
applianceStore.selectedApplianceId,
newBladeId
),
- bladeStore.fetchBladeById(applianceStore.selectedApplianceId, newBladeId),
+ bladeStore.fetchBladeById(
+ applianceStore.selectedApplianceId,
+ newBladeId
+ ),
]);
// Update the URL with the new blade ID
updateUrlWithBladeId(applianceStore.selectedApplianceId, newBladeId);
@@ -2063,4 +2073,4 @@ export default {
.highlighted-tab {
font-weight: bold;
}
-
\ No newline at end of file
+
diff --git a/webui/src/components/Dashboard/Dashboard.vue b/webui/src/components/Dashboard/Dashboard.vue
index c0aa88c2..07aaad58 100644
--- a/webui/src/components/Dashboard/Dashboard.vue
+++ b/webui/src/components/Dashboard/Dashboard.vue
@@ -3,7 +3,7 @@
- {{ buttonLabel }}
-
+
+
+
+ {{ buttonLabel }}
+
+
+
+
+ Click to discover new devices
+
+
+
+
+
+
+ mdi-magnify
+
+
+
+
+
+ Devices
+
+
+ mdi-rectangle
+ CMA
+
+
+
+
+ mdi-rectangle
+ Blade
+
+
+
+
+ mdi-rectangle
+ Host
+
+
+
Status
+
+
+ mdi-rectangle-outline
+ online
+
+
+
+
+ mdi-rectangle-outline
+ offline
+
+
+
+
+ mdi-rectangle-outline
+ unavailable
+
+
+
+
+
-
-
-
- mdi-magnify
-
-
-
+
+
+
+
+
+ New Discovered Blades:
+
+
+ New Discovered Hosts:
+
+
+
+
+
+ Cancel
+ Add
+
+
+
+
+
+
+
+
+
+
+ {{ addNewDiscoveredDevicesProgressText }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ discoverDevicesProgressText }}
+
+
+
+
+
+
+
+
+
+
+ Congrats! New devices were added
+
+ New blades:
+
New hosts:
+
+
+
+
+
+ Done
+
+
+
+
@@ -68,6 +265,110 @@ import { ControlButton, Controls } from "@vue-flow/controls";
export default {
components: { VueFlow, ControlButton, Controls },
+ data() {
+ return {
+ addNewDiscoveredDevicesProgressText:
+ "Adding the selected devices, please wait...",
+ discoverDevicesProgressText:"Discovering devices, please wait...",
+
+ dialogNewDiscoveredDevices: false,
+ dialogAddNewDiscoveredDevicesWait: false,
+ dialogAddNewDiscoveredDevicesOutput: false,
+ dialogDiscoverDevicesWait: false,
+
+ discoveredBlades: [],
+ discoveredHosts: [],
+
+ selectedBlades: [],
+ selectedHosts: [],
+
+ newBlades: [],
+ newHosts: [],
+ };
+ },
+
+ methods: {
+ async discoverDevices() {
+ this.dialogDiscoverDevicesWait = true;
+ const applianceStore = useApplianceStore();
+ const hostStore = useHostStore();
+
+ try {
+ const responseOfBlades = await applianceStore.discoverBlades();
+ const responseOfHosts = await hostStore.discoverHosts();
+
+ const response = (responseOfBlades || []).concat(responseOfHosts || []);
+ this.discoveredBlades = responseOfBlades || [];
+ this.discoveredHosts = responseOfHosts || [];
+
+ this.dialogNewDiscoveredDevices = true;
+ this.dialogDiscoverDevicesWait = false;
+
+ return response.length ? response : [];
+ } catch (error) {
+ this.dialogDiscoverDevicesWait = false;
+ console.error("Error fetching data:", error);
+ return [];
+ }
+ },
+
+ async addDiscoveredDevices() {
+ this.dialogNewDiscoveredDevices = false;
+ this.dialogAddNewDiscoveredDevicesWait = true;
+
+ const applianceStore = useApplianceStore();
+ const hostStore = useHostStore();
+ const bladePortStore = useBladePortStore();
+
+ if (this.selectedBlades.length === 0) {
+ console.log("No blades selected.");
+ } else {
+ for (var i = 0; i < this.selectedBlades.length; i++) {
+ try {
+ const newAddedBlade = await applianceStore.addDiscoveredBlades(
+ this.selectedBlades[i]
+ );
+
+ if (newAddedBlade) {
+ this.newBlades.push(newAddedBlade);
+ }
+ } catch (error) {
+ console.error("Error adding new discovered blade:", error);
+ }
+ }
+ }
+
+ if (this.selectedHosts.length === 0) {
+ console.log("No hosts selected.");
+ } else {
+ for (var i = 0; i < this.selectedHosts.length; i++) {
+ try {
+ const newAddedHost = await hostStore.addDiscoveredHosts(
+ this.selectedHosts[i]
+ );
+ if (newAddedHost) {
+ this.newHosts.push(newAddedHost);
+ }
+ } catch (error) {
+ console.error("Error adding new discovered host:", error);
+ }
+ }
+ }
+
+ // Update the graph content
+ await applianceStore.fetchAppliances();
+ await hostStore.fetchHosts();
+ for (const appliance of applianceStore.applianceIds) {
+ for (const blade of appliance.blades) {
+ await bladePortStore.fetchBladePorts(appliance.id, blade.id);
+ }
+ }
+
+ this.dialogAddNewDiscoveredDevicesWait = false;
+ this.dialogAddNewDiscoveredDevicesOutput = true;
+ },
+ },
+
setup() {
const applianceStore = useApplianceStore();
const hostStore = useHostStore();
@@ -178,8 +479,8 @@ export default {
await hostStore.fetchHosts();
// Ensure blade ports are fetched after appliances, this action will create the edges for dataPlane
for (const appliance of applianceStore.applianceIds) {
- for (const bladeId of appliance.bladeIds) {
- await bladePortStore.fetchBladePorts(appliance.id, bladeId);
+ for (const blade of appliance.blades) {
+ await bladePortStore.fetchBladePorts(appliance.id, blade.id);
}
}
});
@@ -200,3 +501,22 @@ export default {
},
};
+
+
diff --git a/webui/src/components/Dashboard/initial-control-elements.ts b/webui/src/components/Dashboard/initial-control-elements.ts
index 5ba362a0..0d979005 100644
--- a/webui/src/components/Dashboard/initial-control-elements.ts
+++ b/webui/src/components/Dashboard/initial-control-elements.ts
@@ -23,7 +23,7 @@ export const useControlData = () => {
id: "cfm-service",
data: { label: "CFM Service", },
position: position,
- style: { backgroundColor: "#6ebe4a", color: "#000" },
+ style: { backgroundColor: useLayout().Colors.serviceColor, border: "none" },
type: serviceNodeType,
},
]
@@ -35,26 +35,33 @@ export const useControlData = () => {
id: `appliance-${appliance.id}`,
data: { label: appliance.id, url: `/appliances/${appliance.id}` },
position: position,
- style: { backgroundColor: "#f2ae72", color: "#000" },
+ style: { backgroundColor: useLayout().Colors.applianceColor, border: "none" },
type: applianceNodeType,
},
- ...appliance.bladeIds.map((bladeId, bladeIndex) => ({
- id: `blade-${bladeId}`,
- data: { label: bladeId, url: `/appliances/${appliance.id}/blades/${bladeId}`, associatedAppliance: appliance.id },
- position: position,
- style: { backgroundColor: "#f2e394", color: "#000" },
- type: bladeNodeType,
- })),
+ ...appliance.blades.map((blade, bladeIndex) => {
+ const borderColor = useLayout().borderColorChange(blade.status);
+ return {
+ id: `blade-${blade.id}`,
+ data: { label: blade.id, url: `/appliances/${appliance.id}/blades/${blade.id}`, associatedAppliance: appliance.id },
+ position: position,
+ style: { backgroundColor: useLayout().Colors.baldeColor, border: `3px solid ${borderColor}` },
+ type: bladeNodeType,
+ }
+ }),
]
);
- const hostNodes = hostStore.hostIds.map((host, index) => ({
- id: `host-${host}`,
- data: { label: host, url: `/hosts/${host}` },
- position: position,
- style: { backgroundColor: "#d9ecd0", color: "#000" },
- type: hostNodeType,
- }));
+ const hostNodes = hostStore.hostIds.map((host, index) => {
+ const borderColor = useLayout().borderColorChange(host.status);
+
+ return {
+ id: `host-${host.id}`,
+ data: { label: host.id, url: `/hosts/${host.id}` },
+ position: position,
+ style: { backgroundColor: useLayout().Colors.hostColor, border: `3px solid ${borderColor}` },
+ type: hostNodeType,
+ }
+ });
const allNodes = [...coreNode, ...applianceNodes, ...hostNodes];
@@ -67,18 +74,18 @@ export const useControlData = () => {
source: "cfm-service",
target: `appliance-${appliance.id}`,
},
- ...appliance.bladeIds.map((bladeId) => ({
- id: `appliance-blade-${appliance.id}-${bladeId}`,
+ ...appliance.blades.map((blade) => ({
+ id: `appliance-blade-${appliance.id}-${blade.id}`,
source: `appliance-${appliance.id}`,
- target: `blade-${bladeId}`,
+ target: `blade-${blade.id}`,
})),
])
: [];
const hostEdges = hostStore.hostIds.map((host) => ({
- id: `cfm-${host}`,
+ id: `cfm-${host.id}`,
source: "cfm-service",
- target: `host-${host}`,
+ target: `host-${host.id}`,
}));
return [...coreEdges, ...hostEdges];
@@ -97,19 +104,19 @@ export const useControlData = () => {
target: `appliance-${appliance.id}`,
animated: true,
},
- ...appliance.bladeIds.map((bladeId) => ({
- id: `appliance-blade-${appliance.id}-${bladeId}`,
+ ...appliance.blades.map((blade) => ({
+ id: `appliance-blade-${appliance.id}-${blade.id}`,
source: `appliance-${appliance.id}`,
- target: `blade-${bladeId}`,
+ target: `blade-${blade.id}`,
animated: true,
})),
])
: [];
const hostEdges = hostStore.hostIds.map((host) => ({
- id: `cfm-${host}`,
+ id: `cfm-${host.id}`,
source: "cfm-service",
- target: `host-${host}`,
+ target: `host-${host.id}`,
animated: true,
}));
diff --git a/webui/src/components/Dashboard/initial-data-elements.ts b/webui/src/components/Dashboard/initial-data-elements.ts
index 28e4538b..c4ec05e5 100644
--- a/webui/src/components/Dashboard/initial-data-elements.ts
+++ b/webui/src/components/Dashboard/initial-data-elements.ts
@@ -3,6 +3,7 @@ import { computed } from "vue";
import { useApplianceStore } from "../Stores/ApplianceStore";
import { useHostStore } from "../Stores/HostStore";
import { useBladePortStore } from "../Stores/BladePortStore";
+import { useLayout } from "./useLayout";
export const useData = () => {
const applianceStore = useApplianceStore();
@@ -17,7 +18,7 @@ export const useData = () => {
let currentYPosition = 0;
const applianceNodes = applianceStore.applianceIds.flatMap(
(appliance, index) => {
- const bladeCount = appliance.bladeIds.length;
+ const bladeCount = appliance.blades.length;
const applianceHeight = 50 + bladeCount * 50; // Adjust height based on number of blades
const applianceWidth = 270; // Width of the appliance node
const bladeWidth = 250; // Width of the blade node
@@ -27,24 +28,27 @@ export const useData = () => {
id: `appliance-${appliance.id}`,
data: { label: appliance.id, url: `/appliances/${appliance.id}` },
position: { x: 100, y: currentYPosition },
- style: { backgroundColor: "rgba(242, 174, 114, 0.5)", color: "#000", height: `${applianceHeight}px`, width: `${applianceWidth}px` },
+ style: { backgroundColor: useLayout().Colors.applianceColor, height: `${applianceHeight}px`, width: `${applianceWidth}px`, border: "none" },
type: applianceNodeType,
sourcePosition: 'right',
targetPosition: 'left',
};
- const bladeNodes = appliance.bladeIds.map((bladeId, bladeIndex) => ({
- id: `blade-${bladeId}`,
- data: { label: bladeId, url: `/appliances/${appliance.id}/blades/${bladeId}`, associatedAppliance: appliance.id },
- position: { x: bladeXPosition, y: 50 + bladeIndex * 50 }, // Center blades within the appliance node
- style: { backgroundColor: "#f2e394", color: "#000", width: `${bladeWidth}px` },
- type: bladeNodeType,
- parentNode: `appliance-${appliance.id}`,
- extent: 'parent',
- expandParent: true,
- sourcePosition: 'right',
- targetPosition: 'left',
- }));
+ const bladeNodes = appliance.blades.map((blade, bladeIndex) => {
+ const borderColor = useLayout().borderColorChange(blade.status);
+ return {
+ id: `blade-${blade.id}`,
+ data: { label: blade.id, url: `/appliances/${appliance.id}/blades/${blade.id}`, associatedAppliance: appliance.id },
+ position: { x: bladeXPosition, y: 50 + bladeIndex * 50 }, // Center blades within the appliance node
+ style: { backgroundColor: useLayout().Colors.baldeColor, width: `${bladeWidth}px`, border: `3px solid ${borderColor}` },
+ type: bladeNodeType,
+ parentNode: `appliance-${appliance.id}`,
+ extent: 'parent',
+ expandParent: true,
+ sourcePosition: 'right',
+ targetPosition: 'left',
+ }
+ });
currentYPosition += applianceHeight + 20; // Add some space between nodes
@@ -52,15 +56,26 @@ export const useData = () => {
}
);
- const hostNodes = hostStore.hostIds.map((host, index) => ({
- id: `host-${host}`,
- data: { label: host, url: `/hosts/${host}` },
- position: { x: 500, y: index * 200 },
- style: { backgroundColor: "#d9ecd0", color: "#000" },
- type: hostNodeType,
- sourcePosition: 'right',
- targetPosition: 'left',
- }));
+ const hostNodes = hostStore.hostIds.map((host, index) => {
+ const { width, height } = useLayout().measureText(host.id);
+ const borderColor = useLayout().borderColorChange(host.status);
+
+ return {
+ id: `host-${host.id}`,
+ data: { label: host.id, url: `/hosts/${host.id}` },
+ position: { x: 500, y: index * 200 },
+ style: {
+ backgroundColor: useLayout().Colors.hostColor,
+ color: "#000",
+ width: `${width + 20}px`, // Adding some padding
+ height: `${height + 20}px`, // Adding some padding
+ border: `3px solid ${borderColor}`
+ },
+ type: hostNodeType,
+ sourcePosition: 'right',
+ targetPosition: 'left',
+ };
+ });
return [...applianceNodes, ...hostNodes];
});
diff --git a/webui/src/components/Dashboard/useLayout.ts b/webui/src/components/Dashboard/useLayout.ts
index acf35066..e6b6a4e5 100644
--- a/webui/src/components/Dashboard/useLayout.ts
+++ b/webui/src/components/Dashboard/useLayout.ts
@@ -7,6 +7,39 @@ import { ref } from 'vue';
* Composable to run the layout algorithm on the graph.
* It uses the `dagre` library to calculate the layout of the nodes and edges.
*/
+
+export function measureText(text: string, font = '16px Arial') {
+ const canvas = document.createElement('canvas');
+ const context = canvas.getContext('2d');
+ context!.font = font;
+ const metrics = context!.measureText(text);
+ const width = Math.max(metrics.width, 220);
+ return {
+ width: width,
+ height: parseInt(font, 10) // Assuming height is roughly the font size
+ };
+};
+
+export const Colors = {
+ applianceColor: '#f2ae72',
+ baldeColor: '#f2e394',
+ hostColor: '#d9ecd0',
+ serviceColor: '#6ebe4a',
+};
+
+export function borderColorChange(status: string | undefined) {
+ switch (status) {
+ case "online":
+ return "#6ebe4a"; // green
+ case "offline":
+ return "#b00020"; // Red
+ case "unavailable":
+ return "#ff9f40"; // Orange
+ default:
+ return "#ffffff"; // White
+ }
+};
+
export function useLayout() {
const { findNode } = useVueFlow();
@@ -28,10 +61,13 @@ export function useLayout() {
previousDirection.value = direction;
for (const node of nodes) {
- // Use the dimensions property of the internal node (`GraphNode` type)
- const graphNode = findNode(node.id);
+ // Measure the text dimensions for dynamic sizing
+ const { width, height } = measureText(node.data.label);
- dagreGraph.setNode(node.id, { width: graphNode?.dimensions.width || 150, height: graphNode?.dimensions.height || 50 });
+ dagreGraph.setNode(node.id, {
+ width: width + 20, // Adding some padding
+ height: height + 20 // Adding some padding
+ });
}
for (const edge of edges) {
@@ -41,7 +77,7 @@ export function useLayout() {
dagre.layout(dagreGraph);
// Set nodes with updated positions
- return nodes.map((node: { id: string | dagre.Label; }) => {
+ return nodes.map((node: { id: string | dagre.Label; style: any; }) => {
const nodeWithPosition = dagreGraph.node(node.id);
return {
@@ -49,9 +85,14 @@ export function useLayout() {
targetPosition: isHorizontal ? Position.Left : Position.Top,
sourcePosition: isHorizontal ? Position.Right : Position.Bottom,
position: { x: nodeWithPosition.x, y: nodeWithPosition.y },
+ style: {
+ ...node.style,
+ width: `${nodeWithPosition.width}px`,
+ height: `${nodeWithPosition.height}px`
+ }
};
});
}
- return { graph, layout, previousDirection };
-}
+ return { graph, layout, previousDirection, measureText, borderColorChange, Colors };
+}
\ No newline at end of file
diff --git a/webui/src/components/Stores/ApplianceStore.ts b/webui/src/components/Stores/ApplianceStore.ts
index 661f7779..b1ad0d3f 100644
--- a/webui/src/components/Stores/ApplianceStore.ts
+++ b/webui/src/components/Stores/ApplianceStore.ts
@@ -1,6 +1,6 @@
// Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
import { defineStore } from 'pinia'
-import { Appliance, Credentials, DefaultApi } from "@/axios/api";
+import { Appliance, Credentials, DefaultApi, DiscoveredDevice } from "@/axios/api";
import { BASE_PATH } from "@/axios/base";
import axios from 'axios';
@@ -14,7 +14,30 @@ export const useApplianceStore = defineStore('appliance', {
addApplianceError: null as unknown,
deleteApplianceError: null as unknown,
renameApplianceError: null as unknown,
- applianceIds: [] as { id: string, bladeIds: string[] }[],
+ applianceIds: [] as { id: string, blades: { id: string, ipAddress: string, status: string | undefined }[] }[],
+ discoveredBlades: [] as DiscoveredDevice[],
+
+ prefixBladeId: "Discoverd_Blade_",
+ newBladeCredentials: {
+ username: "root",
+ password: "0penBmc",
+ ipAddress: "127.0.0.1",
+ port: 443,
+ insecure: true,
+ protocol: "https",
+ customId: "",
+ },
+
+ defaultApplianceId: "CMA_Discovered_Blades",
+ newApplianceCredentials: {
+ username: "root",
+ password: "0penBmc",
+ ipAddress: "127.0.0.1",
+ port: 8443,
+ insecure: true,
+ protocol: "https",
+ customId: "",
+ },
}),
actions: {
@@ -72,7 +95,7 @@ export const useApplianceStore = defineStore('appliance', {
const responseOfBlades = await defaultApi.bladesGet(applianceId);
const bladeCount = responseOfBlades.data.memberCount;
- const bladeIds = [];
+ const associatedBlades = [];
for (let i = 0; i < bladeCount; i++) {
// Extract the id for each blade
@@ -80,10 +103,12 @@ export const useApplianceStore = defineStore('appliance', {
const bladeId: string = JSON.stringify(uri).split("/").pop()?.slice(0, -2) as string;
// Store blade in blades
if (bladeId) {
- bladeIds.push(bladeId);
+ const responseOfBlade = await defaultApi.bladesGetById(applianceId, bladeId);
+ const response = { id: responseOfBlade.data.id, ipAddress: responseOfBlade.data.ipAddress, status: responseOfBlade.data.status }
+ associatedBlades.push(response);
}
}
- this.applianceIds.push({ id: detailsResponseOfAppliance.data.id, bladeIds });
+ this.applianceIds.push({ id: detailsResponseOfAppliance.data.id, blades: associatedBlades });
}
}
} catch (error) {
@@ -91,13 +116,75 @@ export const useApplianceStore = defineStore('appliance', {
}
},
+ async discoverBlades() {
+ try {
+ // Get all the existed blades
+ const existedBladeIpAddress: (string | undefined)[] = []
+ for (var i = 0; i < this.applianceIds.length; i++) {
+ for (var j = 0; j < this.applianceIds[i].blades.length; j++) {
+ existedBladeIpAddress.push(this.applianceIds[i].blades[j].ipAddress)
+ }
+ }
+
+ const defaultApi = new DefaultApi(undefined, API_BASE_PATH);
+ this.discoveredBlades = [];
+ const responseOfBlade = await defaultApi.discoverDevices("blade");
+ this.discoveredBlades = responseOfBlade.data;
+
+ // Remove the existed blades from the discovered blades
+ for (var k = 0; k < this.discoveredBlades.length; k++) {
+ for (var m = 0; m < existedBladeIpAddress.length; m++) {
+ this.discoveredBlades = this.discoveredBlades.filter(
+ (discoveredBlade) => discoveredBlade.address !== existedBladeIpAddress[m]
+ );
+ }
+ }
+
+ return this.discoveredBlades
+ } catch (error) {
+ console.error("Error discovering new devices:", error);
+ }
+ },
+
+ async addDiscoveredBlades(blade: DiscoveredDevice) {
+ const defaultApi = new DefaultApi(undefined, API_BASE_PATH);
+ const responseOfApplianceExist = await defaultApi.appliancesGetById(this.defaultApplianceId)
+
+ // If there is no default appliance, add one
+ if (!responseOfApplianceExist) {
+ this.newApplianceCredentials.customId = this.defaultApplianceId;
+ const responseOfAppliance = await defaultApi.appliancesPost(this.newApplianceCredentials);
+
+ // Add the new appliance to the appliances and applianceIds array
+ if (responseOfAppliance) {
+ this.appliances.push(responseOfAppliance.data);
+ const newAppliance = { id: responseOfAppliance.data.id, blades: [] }
+ this.applianceIds.push(newAppliance)
+ }
+ }
+
+ // Add the new discovered blade to the default appliance
+ let appliance = this.applianceIds.find(appliance => appliance.id === this.defaultApplianceId);
+
+ this.newBladeCredentials.customId = this.prefixBladeId + blade.address;
+ this.newBladeCredentials.ipAddress = blade.address + "";
+
+ const responseOfBlade = await defaultApi.bladesPost(this.defaultApplianceId, this.newBladeCredentials);
+
+ if (responseOfBlade) {
+ const response = { id: responseOfBlade.data.id, ipAddress: responseOfBlade.data.ipAddress, status: responseOfBlade.data.status };
+ appliance!.blades.push(response);
+ }
+
+ return responseOfBlade.data;
+ },
+
async addNewAppliance(newAppliance: Credentials) {
this.addApplianceError = "";
try {
const defaultApi = new DefaultApi(undefined, API_BASE_PATH);
const response = await defaultApi.appliancesPost(newAppliance);
const addedAppliance = response.data;
- console.log("added appliance", addedAppliance)
// Add the new appliance to the appliances array
this.appliances.push(addedAppliance);
return addedAppliance;
diff --git a/webui/src/components/Stores/HostStore.ts b/webui/src/components/Stores/HostStore.ts
index 5051c548..ae3e44ae 100644
--- a/webui/src/components/Stores/HostStore.ts
+++ b/webui/src/components/Stores/HostStore.ts
@@ -1,6 +1,6 @@
// Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
import { defineStore } from 'pinia'
-import { Host, Credentials, DefaultApi } from "@/axios/api";
+import { Host, Credentials, DefaultApi, DiscoveredDevice } from "@/axios/api";
import { BASE_PATH } from "@/axios/base";
import axios from 'axios';
@@ -19,7 +19,19 @@ export const useHostStore = defineStore('host', {
deleteHostError: null as unknown,
resyncHostError: null as unknown,
renameHostError: null as unknown,
- hostIds: [] as string[],
+ hostIds: [] as { id: string, ipAddress: string, status: string | undefined }[],
+ discoveredHosts: [] as DiscoveredDevice[],
+
+ prefixHostId: "Discoverd_Host_",
+ newHostCredentials: {
+ username: "admin",
+ password: "admin12345",
+ ipAddress: "127.0.0.1",
+ port: 8082,
+ insecure: true,
+ protocol: "http",
+ customId: "",
+ },
}),
actions: {
@@ -44,7 +56,8 @@ export const useHostStore = defineStore('host', {
// Store host in hosts
if (detailsResponseOfHost) {
this.hosts.push(detailsResponseOfHost.data);
- this.hostIds.push(detailsResponseOfHost.data.id)
+ const host = { id: detailsResponseOfHost.data.id, ipAddress: detailsResponseOfHost.data.ipAddress, status: detailsResponseOfHost.data.status }
+ this.hostIds.push(host)
}
}
} catch (error) {
@@ -68,6 +81,51 @@ export const useHostStore = defineStore('host', {
}
},
+ async discoverHosts() {
+ try {
+ // Get all the existed hosts
+ const existedHostIpAddress: (string | undefined)[] = []
+ for (var i = 0; i < this.hostIds.length; i++) {
+ existedHostIpAddress.push(this.hostIds[i].ipAddress)
+ }
+
+ const defaultApi = new DefaultApi(undefined, API_BASE_PATH);
+ this.discoveredHosts = [];
+ const responseOfHost = await defaultApi.discoverDevices("cxl-host");
+ this.discoveredHosts = responseOfHost.data;
+
+ // Remove the existed hosts from the discovered hosts
+ for (var k = 0; k < this.discoveredHosts.length; k++) {
+ for (var m = 0; m < existedHostIpAddress.length; m++) {
+ this.discoveredHosts = this.discoveredHosts.filter(
+ (discoveredHost) => discoveredHost.address !== existedHostIpAddress[m]
+ );
+ }
+ }
+
+ return this.discoveredHosts
+ } catch (error) {
+ console.error("Error discovering new devices:", error);
+ }
+ },
+
+ async addDiscoveredHosts(host: DiscoveredDevice) {
+ const defaultApi = new DefaultApi(undefined, API_BASE_PATH);
+ // Add all the new didcovered hosts
+ this.newHostCredentials.customId = this.prefixHostId + host.address;
+ this.newHostCredentials.ipAddress = host.address + "";
+
+ const responseOfHost = await defaultApi.hostsPost(this.newHostCredentials);
+
+ // Update the applianceIds and appliances
+ if (responseOfHost) {
+ const response = { id: responseOfHost.data.id, ipAddress: responseOfHost.data.ipAddress, status: responseOfHost.data.status }
+ this.hosts.push(responseOfHost.data);
+ this.hostIds.push(response)
+ }
+ return responseOfHost.data;
+ },
+
async addNewHost(newHost: Credentials) {
this.addHostError = "";
try {