Skip to content

Commit

Permalink
feat: add new button to discover new devices and the related interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
Meng-20 committed Dec 2, 2024
1 parent d67c8ae commit 7a5ff9d
Show file tree
Hide file tree
Showing 3 changed files with 266 additions and 14 deletions.
116 changes: 111 additions & 5 deletions webui/src/components/Dashboard/Dashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,22 @@
{{ currentTitle }}
</h2>

<v-btn @click="toggleGraph" style="margin-bottom: 40px" variant="tonal">
{{ buttonLabel }}
</v-btn>
<v-row>
<v-col>
<v-btn @click="toggleGraph" style="margin-bottom: 40px" variant="tonal">
{{ buttonLabel }}
</v-btn>
</v-col>
<v-col>
<v-btn
@click="discoverDevices"
style="margin-bottom: 40px"
variant="tonal"
>
Click to discover new devices</v-btn
>
</v-col>
</v-row>

<div style="position: relative; width: 25%">
<v-text-field
Expand Down Expand Up @@ -50,6 +63,55 @@
</ControlButton>
</Controls>
</VueFlow>

<!-- The dialog of the warning before the adding the new discovered devices(blades or cxl-hosts) -->
<v-dialog v-model="dialogNewDiscoveredDevices" max-width="600px">
<v-card>
<v-alert
color="info"
icon="$info"
title="New Discovered Devices"
variant="tonal"
text="Here are the discovered devices. You can add them to CFM by selecting them and clicking the 'Add' button."
></v-alert>
<v-card-text class="scrollable-content">
New Discovered Blades:
<v-checkbox
v-for="(blade, index) in discoveredBlades"
:key="index"
:label="`${blade.name} - ${blade.address}`"
v-model="selectedBlades"
:value="blade"
></v-checkbox>
New Discovered Hosts:
<v-checkbox
v-for="(host, index) in discoveredHosts"
:key="index"
:label="`${host.name} - ${host.address}`"
v-model="selectedHosts"
:value="host"
></v-checkbox>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="info"
variant="text"
id="cancelResyncBlade"
@click="dialogNewDiscoveredDevices = false"
>Cancel</v-btn
>
<v-btn
color="info"
variant="text"
id="confirmResyncBlade"
@click="addDiscoveredDevices"
>Add</v-btn
>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>

Expand All @@ -68,6 +130,43 @@ import { ControlButton, Controls } from "@vue-flow/controls";
export default {
components: { VueFlow, ControlButton, Controls },

data() {
return {
dialogNewDiscoveredDevices: false,

discoveredBlades: [],
discoveredHosts: [],

selectedBlades: [],
selectedHosts: [],
};
},

methods: {
async discoverDevices() {
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;

return response.length ? response : [];
} catch (error) {
console.error("Error fetching data:", error);
return [];
}
},

addDiscoveredDevices() {},
},

setup() {
const applianceStore = useApplianceStore();
const hostStore = useHostStore();
Expand Down Expand Up @@ -178,8 +277,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);
}
}
});
Expand All @@ -200,3 +299,10 @@ export default {
},
};
</script>

<style scoped>
.scrollable-content {
max-height: 300px; /* Adjust height as needed */
overflow-y: auto;
}
</style>
95 changes: 89 additions & 6 deletions webui/src/components/Stores/ApplianceStore.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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 }[] }[],
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: {
Expand Down Expand Up @@ -72,32 +95,92 @@ 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
const uri = responseOfBlades.data.members[i];
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 }
associatedBlades.push(response);
}
}
this.applianceIds.push({ id: detailsResponseOfAppliance.data.id, bladeIds });
this.applianceIds.push({ id: detailsResponseOfAppliance.data.id, blades: associatedBlades });
}
}
} catch (error) {
console.error("Error fetching appliances:", error);
}
},

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
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 };
appliance!.blades.push(response);
}
},

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;
Expand Down
69 changes: 66 additions & 3 deletions webui/src/components/Stores/HostStore.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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 }[],
discoveredHosts: [] as DiscoveredDevice[],

prefixHostId: "Discoverd_Host_",
newHostCredentials: {
username: "admin",
password: "admin12345",
ipAddress: "127.0.0.1",
port: 8082,
insecure: true,
protocol: "http",
customId: "",
},
}),

actions: {
Expand All @@ -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 }
this.hostIds.push(host)
}
}
} catch (error) {
Expand All @@ -68,6 +81,56 @@ 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() {
const defaultApi = new DefaultApi(undefined, API_BASE_PATH);
for (var g = 0; g < this.discoveredHosts.length; g++) {
try {
// Add all the new didcovered hosts
this.newHostCredentials.customId = this.prefixHostId + this.discoveredHosts[g].address;
this.newHostCredentials.ipAddress = this.discoveredHosts[g].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 }
this.hosts.push(responseOfHost.data);
this.hostIds.push(response)
}
} catch (error) {
console.error(`Error processing host ${g + 1}:`, error);
}
}
},

async addNewHost(newHost: Credentials) {
this.addHostError = "";
try {
Expand Down

0 comments on commit 7a5ff9d

Please sign in to comment.