Skip to content

Commit a960a21

Browse files
committed
fix vm power status
Signed-off-by: Abhishek Kumar <[email protected]>
1 parent 6f4abff commit a960a21

File tree

3 files changed

+124
-13
lines changed

3 files changed

+124
-13
lines changed

plugins/hypervisors/external/src/main/java/org/apache/cloudstack/hypervisor/external/provisioner/ExternalPathPayloadProvisioner.java

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292
import com.cloud.vm.VmDetailConstants;
9393
import com.cloud.vm.dao.UserVmDao;
9494
import com.cloud.vm.dao.VMInstanceDao;
95+
import com.google.gson.JsonObject;
96+
import com.google.gson.JsonParser;
9597

9698
public class ExternalPathPayloadProvisioner extends ManagerBase implements ExternalProvisioner, PluggableService {
9799

@@ -623,6 +625,38 @@ public Pair<Boolean, String> runCustomActionOnExternalSystem(String extensionNam
623625
String.format("Failed to execute custom action '%s' on external system", actionName), filename);
624626
}
625627

628+
protected VirtualMachine.PowerState getPowerStateFromString(String powerStateStr) {
629+
if (StringUtils.isBlank(powerStateStr)) {
630+
return VirtualMachine.PowerState.PowerUnknown;
631+
}
632+
if (powerStateStr.equalsIgnoreCase(VirtualMachine.PowerState.PowerOn.toString())) {
633+
return VirtualMachine.PowerState.PowerOn;
634+
} else if (powerStateStr.equalsIgnoreCase(VirtualMachine.PowerState.PowerOff.toString())) {
635+
return VirtualMachine.PowerState.PowerOff;
636+
}
637+
return VirtualMachine.PowerState.PowerUnknown;
638+
}
639+
640+
protected VirtualMachine.PowerState parsePowerStateFromResponse(UserVmVO userVmVO, String response) {
641+
logger.debug("Power status response from the external system for {} : {}", userVmVO, response);
642+
if (StringUtils.isBlank(response)) {
643+
logger.warn("Empty response while trying to fetch the power status of the {}", userVmVO);
644+
return VirtualMachine.PowerState.PowerUnknown;
645+
}
646+
if (!response.trim().startsWith("{")) {
647+
return getPowerStateFromString(response);
648+
}
649+
try {
650+
JsonObject jsonObj = new JsonParser().parse(response).getAsJsonObject();
651+
String powerState = jsonObj.has("power_state") ? jsonObj.get("power_state").getAsString() : null;
652+
return getPowerStateFromString(powerState);
653+
} catch (Exception e) {
654+
logger.warn("Failed to parse power status response: {} for {} as JSON: {}",
655+
response, userVmVO, e.getMessage());
656+
return VirtualMachine.PowerState.PowerUnknown;
657+
}
658+
}
659+
626660
private VirtualMachine.PowerState getVmPowerState(UserVmVO userVmVO, Map<String, Map<String, String>> accessDetails,
627661
String extensionName, String extensionPath) {
628662
final HypervisorGuru hvGuru = hypervisorGuruManager.getGuru(Hypervisor.HypervisorType.External);
@@ -631,23 +665,16 @@ private VirtualMachine.PowerState getVmPowerState(UserVmVO userVmVO, Map<String,
631665
accessDetails.put(ApiConstants.VIRTUAL_MACHINE, virtualMachineTO.getExternalDetails());
632666
Map<String, Object> modifiedDetails = loadAccessDetails(accessDetails, virtualMachineTO);
633667
String vmUUID = userVmVO.getUuid();
634-
logger.debug("Trying to get VM power status from the external system for the VM {}", vmUUID);
668+
logger.debug("Trying to get VM power status from the external system for {}", userVmVO);
635669
Pair<Boolean, String> result = getInstanceStatusOnExternalSystem(extensionName, extensionPath, vmUUID,
636670
modifiedDetails, AgentManager.Wait.value());
637-
if (result.first()) {
638-
if (result.second().equalsIgnoreCase(VirtualMachine.PowerState.PowerOn.toString())) {
639-
return VirtualMachine.PowerState.PowerOn;
640-
} else if (result.second().equalsIgnoreCase(VirtualMachine.PowerState.PowerOff.toString())) {
641-
return VirtualMachine.PowerState.PowerOff;
642-
} else {
643-
return VirtualMachine.PowerState.PowerUnknown;
644-
}
645-
} else {
646-
logger.debug("Exception occurred while trying to fetch the power status of the {} : {}", userVmVO, result.second());
671+
if (!result.first()) {
672+
logger.warn("Failure response received while trying to fetch the power status of the {} : {}",
673+
userVmVO, result.second());
647674
return VirtualMachine.PowerState.PowerUnknown;
648675
}
676+
return parsePowerStateFromResponse(userVmVO, result.second());
649677
}
650-
651678
public Pair<Boolean, String> prepareExternalProvisioningInternal(String extensionName, String filename,
652679
String vmUUID, Map<String, Object> accessDetails, int wait) {
653680
return executeExternalCommand(extensionName, "prepare", accessDetails, wait,

plugins/hypervisors/external/src/test/java/org/apache/cloudstack/hypervisor/external/provisioner/ExternalPathPayloadProvisionerTest.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,4 +675,76 @@ public void prepareExternalPayloadThrowsExceptionWhenFileCannotBeWritten() throw
675675
provisioner.prepareExternalPayload(extensionName, details);
676676
}
677677
}
678+
679+
@Test
680+
public void getPowerStateFromStringReturnsPowerOnForValidInput() {
681+
VirtualMachine.PowerState result = provisioner.getPowerStateFromString("PowerOn");
682+
assertEquals(VirtualMachine.PowerState.PowerOn, result);
683+
}
684+
685+
@Test
686+
public void getPowerStateFromStringReturnsPowerOffForValidInput() {
687+
VirtualMachine.PowerState result = provisioner.getPowerStateFromString("PowerOff");
688+
assertEquals(VirtualMachine.PowerState.PowerOff, result);
689+
}
690+
691+
@Test
692+
public void getPowerStateFromStringReturnsPowerUnknownForInvalidInput() {
693+
VirtualMachine.PowerState result = provisioner.getPowerStateFromString("InvalidState");
694+
assertEquals(VirtualMachine.PowerState.PowerUnknown, result);
695+
}
696+
697+
@Test
698+
public void getPowerStateFromStringReturnsPowerUnknownForBlankInput() {
699+
VirtualMachine.PowerState result = provisioner.getPowerStateFromString("");
700+
assertEquals(VirtualMachine.PowerState.PowerUnknown, result);
701+
}
702+
703+
@Test
704+
public void parsePowerStateFromResponseReturnsPowerOnForValidJson() {
705+
String response = "{\"power_state\":\"PowerOn\"}";
706+
UserVmVO vm = mock(UserVmVO.class);
707+
VirtualMachine.PowerState result = provisioner.parsePowerStateFromResponse(vm, response);
708+
assertEquals(VirtualMachine.PowerState.PowerOn, result);
709+
}
710+
711+
@Test
712+
public void parsePowerStateFromResponseReturnsPowerOffForValidJson() {
713+
String response = "{\"power_state\":\"PowerOff\"}";
714+
UserVmVO vm = mock(UserVmVO.class);
715+
VirtualMachine.PowerState result = provisioner.parsePowerStateFromResponse(vm, response);
716+
assertEquals(VirtualMachine.PowerState.PowerOff, result);
717+
}
718+
719+
@Test
720+
public void parsePowerStateFromResponseReturnsPowerUnknownForInvalidJson() {
721+
String response = "{\"invalid_key\":\"value\"}";
722+
UserVmVO vm = mock(UserVmVO.class);
723+
VirtualMachine.PowerState result = provisioner.parsePowerStateFromResponse(vm, response);
724+
assertEquals(VirtualMachine.PowerState.PowerUnknown, result);
725+
}
726+
727+
@Test
728+
public void parsePowerStateFromResponseReturnsPowerUnknownForMalformedJson() {
729+
String response = "{power_state:PowerOn";
730+
UserVmVO vm = mock(UserVmVO.class);
731+
VirtualMachine.PowerState result = provisioner.parsePowerStateFromResponse(vm, response);
732+
assertEquals(VirtualMachine.PowerState.PowerUnknown, result);
733+
}
734+
735+
@Test
736+
public void parsePowerStateFromResponseReturnsPowerUnknownForBlankResponse() {
737+
String response = "";
738+
UserVmVO vm = mock(UserVmVO.class);
739+
VirtualMachine.PowerState result = provisioner.parsePowerStateFromResponse(vm, response);
740+
assertEquals(VirtualMachine.PowerState.PowerUnknown, result);
741+
}
742+
743+
@Test
744+
public void parsePowerStateFromResponseReturnsPowerStateForPlainTextResponse() {
745+
String response = "PowerOn";
746+
UserVmVO vm = mock(UserVmVO.class);
747+
VirtualMachine.PowerState result = provisioner.parsePowerStateFromResponse(vm, response);
748+
assertEquals(VirtualMachine.PowerState.PowerOn, result);
749+
}
678750
}

test/integration/smoke/test_extension_custom.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,19 @@
157157
vm_status=$(jq -r '.status' "$file")
158158
[[ -z "$vm_status" || "$vm_status" == "null" ]] && vm_status="unknown"
159159
160-
jq -n --arg ps "$vm_status" '{status: "success", power_state: $ps}'
160+
case "${vm_status,,}" in
161+
"running"|"poweron")
162+
power_state="PowerOn"
163+
;;
164+
"stopped"|"shutdown"|"poweroff")
165+
power_state="PowerOff"
166+
;;
167+
*)
168+
power_state="$vm_status"
169+
;;
170+
esac
171+
172+
jq -n --arg ps "$power_state" '{status: "success", power_state: $ps}'
161173
}
162174
163175
testaction() {

0 commit comments

Comments
 (0)