Skip to content

Commit bb768e4

Browse files
jeongda-youngDajeong-Park
authored andcommitted
vhba 삭제 api
1 parent f31998b commit bb768e4

File tree

1 file changed

+219
-44
lines changed

1 file changed

+219
-44
lines changed

core/src/main/java/com/cloud/resource/ServerResourceBase.java

Lines changed: 219 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import com.cloud.agent.api.Answer;
2424
import com.cloud.agent.api.Command;
2525
import com.cloud.agent.api.CreateVhbaDeviceCommand;
26+
import com.cloud.agent.api.DeleteVhbaDeviceAnswer;
27+
import com.cloud.agent.api.DeleteVhbaDeviceCommand;
2628
import com.cloud.agent.api.ListHostDeviceAnswer;
2729
import com.cloud.agent.api.ListHostHbaDeviceAnswer;
2830
import com.cloud.agent.api.ListHostLunDeviceAnswer;
@@ -34,7 +36,7 @@
3436
import com.cloud.agent.api.UpdateHostScsiDeviceAnswer;
3537
import com.cloud.agent.api.UpdateHostScsiDeviceCommand;
3638
import com.cloud.agent.api.UpdateHostUsbDeviceAnswer;
37-
import com.cloud.agent.api.UpdateHostVhbaDeviceCommand;
39+
import com.cloud.agent.api.UpdateHostVhbaDeviceAnswer;
3840
import com.cloud.utils.net.NetUtils;
3941
import com.cloud.utils.script.OutputInterpreter;
4042
import com.cloud.utils.script.Script;
@@ -51,6 +53,7 @@
5153
import java.util.Arrays;
5254
import java.util.Collections;
5355
import java.util.Date;
56+
import java.util.HashMap;
5457
import java.util.HashSet;
5558
import java.util.LinkedList;
5659
import java.util.List;
@@ -64,6 +67,7 @@
6467
import org.apache.logging.log4j.Logger;
6568
import org.json.JSONArray;
6669
import org.json.JSONObject;
70+
import javax.naming.ConfigurationException;
6771

6872
public abstract class ServerResourceBase implements ServerResource {
6973
protected Logger logger = LogManager.getLogger(getClass());
@@ -214,6 +218,7 @@ public Answer listHostLunDevices(Command command) {
214218
List<String> hostDevicesNames = new ArrayList<>();
215219
List<String> hostDevicesText = new ArrayList<>();
216220
List<Boolean> hasPartitions = new ArrayList<>();
221+
Map<String, String> deviceMappings = new HashMap<>(); // LUN -> SCSI 매핑
217222

218223
Script cmd = new Script("/usr/bin/lsblk");
219224
cmd.add("--json", "--paths", "--output", "NAME,TYPE,SIZE,MOUNTPOINT");
@@ -302,6 +307,7 @@ public Answer listHostScsiDevices(Command command) {
302307
List<String> hostDevicesNames = new ArrayList<>();
303308
List<String> hostDevicesText = new ArrayList<>();
304309
List<Boolean> hasPartitions = new ArrayList<>();
310+
Map<String, String> deviceMappings = new HashMap<>(); // SCSI -> LUN 매핑
305311
try {
306312
Script cmd = new Script("/usr/bin/lsscsi");
307313
cmd.add("-g");
@@ -339,6 +345,11 @@ public Answer listHostScsiDevices(Command command) {
339345
hostDevicesNames.add(name);
340346
hostDevicesText.add(text.toString());
341347
hasPartitions.add(false);
348+
349+
// SCSI 디바이스와 LUN 디바이스 매핑 저장
350+
if (dev != null && !dev.isEmpty()) {
351+
deviceMappings.put(name, dev);
352+
}
342353
}
343354
return new com.cloud.agent.api.ListHostScsiDeviceAnswer(true, hostDevicesNames, hostDevicesText, hasPartitions);
344355
} catch (Exception e) {
@@ -581,6 +592,98 @@ public Answer createHostVHbaDevice(CreateVhbaDeviceCommand command, String paren
581592
}
582593
}
583594

595+
public Answer deleteHostVHbaDevice(DeleteVhbaDeviceCommand command) {
596+
String vhbaName = command.getVhbaName();
597+
logger.info("vHBA 삭제 시작 - vHBA 이름: " + vhbaName);
598+
599+
try {
600+
// 1. 입력 파라미터 검증
601+
if (vhbaName == null || vhbaName.trim().isEmpty()) {
602+
logger.error("vHBA 이름이 제공되지 않았습니다");
603+
return new DeleteVhbaDeviceAnswer(command, false, "vHBA 이름이 필요합니다");
604+
}
605+
606+
// 2. vHBA 디바이스 존재 여부 확인
607+
if (!validateVhbaDeviceExists(vhbaName)) {
608+
logger.error("vHBA 디바이스가 존재하지 않습니다: " + vhbaName);
609+
return new DeleteVhbaDeviceAnswer(command, false, "vHBA 디바이스가 존재하지 않습니다: " + vhbaName);
610+
}
611+
612+
// 3. vHBA가 VM에 할당되어 있는지 확인
613+
if (isVhbaAllocatedToVm(vhbaName)) {
614+
logger.error("vHBA가 VM에 할당되어 있어 삭제할 수 없습니다: " + vhbaName);
615+
return new DeleteVhbaDeviceAnswer(command, false, "vHBA가 VM에 할당되어 있어 삭제할 수 없습니다. 먼저 할당을 해제해주세요.");
616+
}
617+
618+
// 4. virsh nodedev-destroy 명령 실행
619+
Script destroyCommand = new Script("/bin/bash");
620+
destroyCommand.add("-c");
621+
destroyCommand.add("virsh nodedev-destroy " + vhbaName);
622+
OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
623+
String result = destroyCommand.execute(parser);
624+
625+
if (result != null) {
626+
logger.error("vHBA 삭제 실패: " + result);
627+
return new DeleteVhbaDeviceAnswer(command, false, "vHBA 삭제 실패: " + result);
628+
}
629+
630+
// 5. 삭제 확인
631+
if (validateVhbaDeviceExists(vhbaName)) {
632+
logger.error("vHBA 삭제 후에도 여전히 존재합니다: " + vhbaName);
633+
return new DeleteVhbaDeviceAnswer(command, false, "vHBA 삭제 확인 실패");
634+
}
635+
636+
logger.info("vHBA 디바이스 삭제 성공: " + vhbaName);
637+
return new DeleteVhbaDeviceAnswer(command, true, "vHBA 디바이스가 성공적으로 삭제되었습니다: " + vhbaName);
638+
639+
} catch (Exception e) {
640+
logger.error("vHBA 디바이스 삭제 중 오류: " + e.getMessage(), e);
641+
return new DeleteVhbaDeviceAnswer(command, false, "vHBA 삭제 중 오류: " + e.getMessage());
642+
}
643+
}
644+
645+
// vHBA 디바이스 존재 여부 확인
646+
private boolean validateVhbaDeviceExists(String vhbaName) {
647+
try {
648+
Script checkCommand = new Script("/bin/bash");
649+
checkCommand.add("-c");
650+
checkCommand.add("virsh nodedev-info " + vhbaName + " >/dev/null 2>&1");
651+
String result = checkCommand.execute(null);
652+
return result == null; // 결과가 null이면 성공 (디바이스 존재)
653+
} catch (Exception e) {
654+
logger.debug("vHBA 디바이스 존재 확인 중 오류: " + e.getMessage());
655+
return false;
656+
}
657+
}
658+
659+
// vHBA가 VM에 할당되어 있는지 확인
660+
private boolean isVhbaAllocatedToVm(String vhbaName) {
661+
try {
662+
Script checkCommand = new Script("/bin/bash");
663+
checkCommand.add("-c");
664+
checkCommand.add("virsh list --all | grep -v 'Id' | grep -v '^-' | while read line; do " +
665+
"vm_id=$(echo $line | awk '{print $1}'); " +
666+
"if [ ! -z \"$vm_id\" ]; then " +
667+
"virsh dumpxml $vm_id | grep -q '" + vhbaName + "'; " +
668+
"if [ $? -eq 0 ]; then " +
669+
"echo 'allocated'; " +
670+
"break; " +
671+
"fi; " +
672+
"fi; " +
673+
"done");
674+
OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
675+
String result = checkCommand.execute(parser);
676+
677+
if (result == null && parser.getLines() != null) {
678+
return parser.getLines().trim().equals("allocated");
679+
}
680+
return false;
681+
} catch (Exception e) {
682+
logger.debug("vHBA 할당 상태 확인 중 오류: " + e.getMessage());
683+
return false;
684+
}
685+
}
686+
584687
// virsh nodedev-list --cap vports에서 나온 부모 HBA 유효성 검증
585688
private boolean validateParentHbaFromVports(String parentHbaName) {
586689
try {
@@ -1407,48 +1510,6 @@ protected Answer updateHostLunDevices(Command command, String vmName, String xml
14071510
}
14081511
}
14091512

1410-
protected Answer updateHostScsiDevices(UpdateHostScsiDeviceCommand command, String vmName, String xmlConfig, boolean isAttach) {
1411-
String scsiXmlPath = String.format("/tmp/scsi_device_%s.xml", vmName);
1412-
try {
1413-
// XML 파일이 없을 경우에만 생성
1414-
File xmlFile = new File(scsiXmlPath);
1415-
if (!xmlFile.exists()) {
1416-
try (PrintWriter writer = new PrintWriter(scsiXmlPath)) {
1417-
writer.write(xmlConfig);
1418-
}
1419-
logger.info("Generated XML file: {} for VM: {}", scsiXmlPath, vmName);
1420-
}
1421-
1422-
Script virshCmd = new Script("virsh");
1423-
if (isAttach) {
1424-
virshCmd.add("attach-device", vmName, scsiXmlPath);
1425-
} else {
1426-
virshCmd.add("detach-device", vmName, scsiXmlPath);
1427-
logger.info("Executing detach command for VM: {} with XML: {}", vmName, xmlConfig);
1428-
}
1429-
1430-
logger.info("isAttach value: {}", isAttach);
1431-
1432-
String result = virshCmd.execute();
1433-
1434-
if (result != null) {
1435-
String action = isAttach ? "attach" : "detach";
1436-
logger.error("Failed to {} SCSI device: {}", action, result);
1437-
return new UpdateHostScsiDeviceAnswer(false, vmName, xmlConfig, isAttach);
1438-
}
1439-
1440-
String action = isAttach ? "attached to" : "detached from";
1441-
logger.info("Successfully {} SCSI device for VM {}", action, vmName);
1442-
return new UpdateHostScsiDeviceAnswer(true, vmName, xmlConfig, isAttach);
1443-
1444-
} catch (Exception e) {
1445-
String action = isAttach ? "attaching" : "detaching";
1446-
logger.error("Error {} SCSI device: {}", action, e.getMessage(), e);
1447-
return new UpdateHostScsiDeviceAnswer(false, vmName, xmlConfig, isAttach);
1448-
}
1449-
}
1450-
1451-
14521513
protected Answer updateHostHbaDevices(Command command, String vmName, String xmlConfig, boolean isAttach) {
14531514
String hbaXmlPath = String.format("/tmp/hba_device_%s.xml", vmName);
14541515
try {
@@ -1492,7 +1553,7 @@ protected Answer updateHostHbaDevices(Command command, String vmName, String xml
14921553

14931554
protected Answer updateHostVHbaDevices(Command command, String vmName, String xmlConfig, boolean isAttach) {
14941555
try {
1495-
UpdateHostVhbaDeviceCommand cmd = (UpdateHostVhbaDeviceCommand) command;
1556+
UpdateHostVhbaDeviceAnswer cmd = (UpdateHostVhbaDeviceAnswer) command;
14961557
String vhbaName = cmd.getVhbaName();
14971558

14981559
String vhbaXmlPath = String.format("/tmp/vhba_device_%s.xml", vmName);
@@ -1538,4 +1599,118 @@ protected Answer updateHostVHbaDevices(Command command, String vmName, String xm
15381599
return new com.cloud.agent.api.UpdateHostVhbaDeviceAnswer(false, null, null, null, false);
15391600
}
15401601
}
1602+
1603+
protected Answer updateHostScsiDevices(UpdateHostScsiDeviceCommand command, String vmName, String xmlConfig, boolean isAttach) {
1604+
String scsiXmlPath = String.format("/tmp/scsi_device_%s.xml", vmName);
1605+
try {
1606+
// XML 파일이 없을 경우에만 생성
1607+
File xmlFile = new File(scsiXmlPath);
1608+
if (!xmlFile.exists()) {
1609+
try (PrintWriter writer = new PrintWriter(scsiXmlPath)) {
1610+
writer.write(xmlConfig);
1611+
}
1612+
logger.info("Generated XML file: {} for VM: {}", scsiXmlPath, vmName);
1613+
}
1614+
1615+
Script virshCmd = new Script("virsh");
1616+
if (isAttach) {
1617+
virshCmd.add("attach-device", vmName, scsiXmlPath);
1618+
} else {
1619+
virshCmd.add("detach-device", vmName, scsiXmlPath);
1620+
logger.info("Executing detach command for VM: {} with XML: {}", vmName, xmlConfig);
1621+
}
1622+
1623+
logger.info("isAttach value: {}", isAttach);
1624+
1625+
String result = virshCmd.execute();
1626+
1627+
if (result != null) {
1628+
String action = isAttach ? "attach" : "detach";
1629+
logger.error("Failed to {} SCSI device: {}", action, result);
1630+
return new UpdateHostScsiDeviceAnswer(false, vmName, xmlConfig, isAttach);
1631+
}
1632+
1633+
String action = isAttach ? "attached to" : "detached from";
1634+
logger.info("Successfully {} SCSI device for VM {}", action, vmName);
1635+
return new UpdateHostScsiDeviceAnswer(true, vmName, xmlConfig, isAttach);
1636+
1637+
} catch (Exception e) {
1638+
String action = isAttach ? "attaching" : "detaching";
1639+
logger.error("Error {} SCSI device: {}", action, e.getMessage(), e);
1640+
return new UpdateHostScsiDeviceAnswer(false, vmName, xmlConfig, isAttach);
1641+
}
1642+
}
1643+
1644+
public Answer createVhbaScsiStoragePool(String poolName, String parentHba, String wwnn, String wwpn, String fabricWwn) {
1645+
try {
1646+
// 1. XML 생성
1647+
StringBuilder xml = new StringBuilder();
1648+
xml.append("<pool type='scsi'>\n");
1649+
xml.append(" <name>").append(poolName).append("</name>\n");
1650+
xml.append(" <source>\n");
1651+
xml.append(" <adapter type='fc_host'");
1652+
if (parentHba != null && !parentHba.isEmpty()) {
1653+
xml.append(" parent='").append(parentHba).append("'");
1654+
}
1655+
if (wwnn != null && !wwnn.isEmpty()) {
1656+
xml.append(" wwnn='").append(wwnn).append("'");
1657+
}
1658+
if (wwpn != null && !wwpn.isEmpty()) {
1659+
xml.append(" wwpn='").append(wwpn).append("'");
1660+
}
1661+
if (fabricWwn != null && !fabricWwn.isEmpty()) {
1662+
xml.append(" fabric_wwn='").append(fabricWwn).append("'");
1663+
}
1664+
xml.append("/>\n");
1665+
xml.append(" </source>\n");
1666+
xml.append(" <target>\n");
1667+
xml.append(" <path>/dev/disk/by-path</path>\n");
1668+
xml.append(" <permissions>\n");
1669+
xml.append(" <mode>0700</mode>\n");
1670+
xml.append(" <owner>0</owner>\n");
1671+
xml.append(" <group>0</group>\n");
1672+
xml.append(" </permissions>\n");
1673+
xml.append(" </target>\n");
1674+
xml.append("</pool>\n");
1675+
1676+
// 2. XML 파일로 저장
1677+
String xmlFilePath = "/tmp/" + poolName + ".xml";
1678+
try (FileWriter writer = new FileWriter(xmlFilePath)) {
1679+
writer.write(xml.toString());
1680+
}
1681+
1682+
// 3. virsh pool-define
1683+
Script defineCmd = new Script("virsh");
1684+
defineCmd.add("pool-define", xmlFilePath);
1685+
String defineResult = defineCmd.execute();
1686+
if (defineResult != null) {
1687+
logger.error("Failed to define vHBA SCSI pool: " + defineResult);
1688+
return new Answer(null, false, "Failed to define vHBA SCSI pool: " + defineResult);
1689+
}
1690+
1691+
// 4. virsh pool-start
1692+
Script startCmd = new Script("virsh");
1693+
startCmd.add("pool-start", poolName);
1694+
String startResult = startCmd.execute();
1695+
if (startResult != null) {
1696+
logger.error("Failed to start vHBA SCSI pool: " + startResult);
1697+
return new Answer(null, false, "Failed to start vHBA SCSI pool: " + startResult);
1698+
}
1699+
1700+
// 5. virsh pool-autostart
1701+
Script autoCmd = new Script("virsh");
1702+
autoCmd.add("pool-autostart", poolName);
1703+
String autoResult = autoCmd.execute();
1704+
if (autoResult != null) {
1705+
logger.warn("Failed to autostart vHBA SCSI pool: " + autoResult);
1706+
}
1707+
1708+
logger.info("vHBA SCSI storage pool 생성 및 시작 성공: " + poolName);
1709+
return new Answer(null, true, "vHBA SCSI storage pool created and started: " + poolName);
1710+
1711+
} catch (Exception e) {
1712+
logger.error("vHBA SCSI storage pool 생성 중 오류: " + e.getMessage(), e);
1713+
return new Answer(null, false, "vHBA SCSI storage pool 생성 중 오류: " + e.getMessage());
1714+
}
1715+
}
15411716
}

0 commit comments

Comments
 (0)