-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(web): use queries to handle iSCSI configuration (#1598)
Trello: https://trello.com/c/MsGbqiwA/ This is a follow-up of #1585 which adapts the iSCSI-related code to use queries instead of the regular Agama client. Additionally, it converts a good share of the code to TypeScript and adds some iSCSI tests, that were not included in the first version.
- Loading branch information
Showing
20 changed files
with
679 additions
and
240 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/* | ||
* Copyright (c) [2024] SUSE LLC | ||
* | ||
* All Rights Reserved. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of version 2 of the GNU General Public License as published | ||
* by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
* more details. | ||
* | ||
* You should have received a copy of the GNU General Public License along | ||
* with this program; if not, contact SUSE LLC. | ||
* | ||
* To contact SUSE LLC about this file by physical or electronic mail, you may | ||
* find current contact information at www.suse.com. | ||
*/ | ||
|
||
import { del, get, patch, post } from "~/api/http"; | ||
import { ISCSIInitiator, ISCSINode } from "~/api/storage/types"; | ||
|
||
const ISCSI_NODES_NAMESPACE = "/api/storage/iscsi/nodes"; | ||
|
||
const nodePath = (node: ISCSINode): string => ISCSI_NODES_NAMESPACE + "/" + node.id; | ||
|
||
/** | ||
* Returns the iSCSI initiator. | ||
*/ | ||
const fetchInitiator = (): Promise<ISCSIInitiator> => get("/api/storage/iscsi/initiator"); | ||
|
||
/** | ||
* Updates the name of the iSCSI initiator. | ||
*/ | ||
const updateInitiator = ({ name }) => patch("/api/storage/iscsi/initiator", { name }); | ||
|
||
/** | ||
* Returns the iSCSI nodes. | ||
*/ | ||
const fetchNodes = (): Promise<ISCSINode[]> => get("/api/storage/iscsi/nodes"); | ||
|
||
type LoginOptions = { | ||
// Password for authentication by target | ||
password?: string; | ||
// Username for authentication by target | ||
username?: string; | ||
// Password for authentication by initiator | ||
reversePassword?: string; | ||
// Username for authentication by initiator | ||
reverseUsername?: string; | ||
}; | ||
|
||
/** | ||
* Performs an iSCSI discovery. | ||
* | ||
* @param address - IP address of the ISCSI server | ||
* @param port - Port of the iSCSI server | ||
* @param options - Authentication options | ||
* @return true on success, false on failure | ||
*/ | ||
const discover = async (address: string, port: number, options: LoginOptions): Promise<boolean> => { | ||
const data = { address, port, options }; | ||
try { | ||
await post("/api/storage/iscsi/discover", data); | ||
return true; | ||
} catch (error) { | ||
console.error("Error discovering iSCSI targets:", error.message); | ||
return false; | ||
} | ||
}; | ||
|
||
const deleteNode = async (node: ISCSINode): Promise<void> => { | ||
await del(nodePath(node)); | ||
}; | ||
|
||
/* | ||
* Creates an iSCSI session on the given node. | ||
* | ||
* @param node - ISCSI node | ||
* @param options - Authentication options | ||
* @return operation result (0: success; 1: invalid startup; 2: failed) | ||
*/ | ||
const login = async (node: ISCSINode, options: LoginOptions) => { | ||
try { | ||
await post(nodePath(node) + "/login", options); | ||
return 0; | ||
} catch (error) { | ||
const { data: reason } = error.response; | ||
console.warn("Could not login into the iSCSI node:", error.message, "reason:", reason); | ||
return reason === "InvalidStartup" ? 1 : 2; | ||
} | ||
}; | ||
|
||
/* | ||
* Closes an iSCSI session on the given node. | ||
* | ||
* @param node - ISCSI node | ||
*/ | ||
const logout = async (node: ISCSINode) => post(nodePath(node) + "/logout"); | ||
|
||
/** | ||
* Sets the startup status of the connection | ||
* | ||
* @param node - ISCSI node | ||
* @param startup - startup status | ||
*/ | ||
const setStartup = async (node: ISCSINode, startup: string) => patch(nodePath(node), { startup }); | ||
|
||
export { | ||
fetchInitiator, | ||
fetchNodes, | ||
updateInitiator, | ||
discover, | ||
deleteNode, | ||
login, | ||
logout, | ||
setStartup, | ||
}; | ||
export type { LoginOptions }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
67 changes: 67 additions & 0 deletions
67
web/src/components/storage/iscsi/InitiatorPresenter.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
* Copyright (c) [2024] SUSE LLC | ||
* | ||
* All Rights Reserved. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of version 2 of the GNU General Public License as published | ||
* by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
* more details. | ||
* | ||
* You should have received a copy of the GNU General Public License along | ||
* with this program; if not, contact SUSE LLC. | ||
* | ||
* To contact SUSE LLC about this file by physical or electronic mail, you may | ||
* find current contact information at www.suse.com. | ||
*/ | ||
|
||
import React from "react"; | ||
import { screen, within } from "@testing-library/react"; | ||
import { plainRender } from "~/test-utils"; | ||
|
||
import InitiatorPresenter from "./InitiatorPresenter"; | ||
import { ISCSIInitiator } from "~/types/storage"; | ||
|
||
const initiator: ISCSIInitiator = { | ||
name: "iqn.1996-04.de.suse:01:62b45cf7fc", | ||
ibft: true, | ||
offloadCard: "", | ||
}; | ||
|
||
const mockInitiatorMutation = { mutateAsync: jest.fn() }; | ||
|
||
jest.mock("~/queries/storage/iscsi", () => ({ | ||
...jest.requireActual("~/queries/storage/iscsi"), | ||
useInitiatorMutation: () => mockInitiatorMutation, | ||
})); | ||
|
||
describe("InitiatorPresenter", () => { | ||
it("displays the initiator data", () => { | ||
plainRender(<InitiatorPresenter initiator={initiator} />); | ||
screen.getByText(initiator.name); | ||
screen.getByRole("cell", { name: initiator.name }); | ||
}); | ||
|
||
it("updates the initiator data", async () => { | ||
const { user } = plainRender(<InitiatorPresenter initiator={initiator} />); | ||
|
||
const button = await screen.findByRole("button", { name: "Actions" }); | ||
await user.click(button); | ||
|
||
const editButton = await screen.findByRole("menuitem", { name: "Edit" }); | ||
await user.click(editButton); | ||
|
||
const dialog = await screen.findByRole("dialog"); | ||
const nameInput = await within(dialog).findByLabelText(/Name/); | ||
await user.clear(nameInput); | ||
await user.type(nameInput, "my-initiator"); | ||
const confirmButton = screen.getByRole("button", { name: "Confirm" }); | ||
await user.click(confirmButton); | ||
|
||
expect(mockInitiatorMutation.mutateAsync).toHaveBeenCalledWith({ name: "my-initiator" }); | ||
}); | ||
}); |
Oops, something went wrong.