001/* 002 * VM-Operator 003 * Copyright (C) 2023 Michael N. Lipp 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <https://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.vmoperator.runner.qemu.events; 020 021import com.fasterxml.jackson.databind.JsonNode; 022import java.util.Optional; 023import org.jdrupes.vmoperator.runner.qemu.commands.QmpAddCpu; 024import org.jdrupes.vmoperator.runner.qemu.commands.QmpCapabilities; 025import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand; 026import org.jdrupes.vmoperator.runner.qemu.commands.QmpDelCpu; 027import org.jdrupes.vmoperator.runner.qemu.commands.QmpQueryHotpluggableCpus; 028import org.jdrupes.vmoperator.runner.qemu.commands.QmpSetDisplayPassword; 029import org.jgrapes.core.Channel; 030import org.jgrapes.core.Components; 031import org.jgrapes.core.Event; 032 033/** 034 * Signals the reception of a result from executing a QMP command. 035 */ 036public class MonitorResult extends Event<Void> { 037 038 private final QmpCommand executed; 039 private final JsonNode response; 040 041 /** 042 * Create event from data. 043 * 044 * @param command the command 045 * @param response the response 046 * @return the monitor result 047 */ 048 public static MonitorResult from(QmpCommand command, JsonNode response) { 049 if (command instanceof QmpCapabilities) { 050 return new QmpConfigured(command, response); 051 } 052 if (command instanceof QmpQueryHotpluggableCpus) { 053 return new HotpluggableCpuStatus(command, response); 054 } 055 if (command instanceof QmpAddCpu) { 056 return new CpuAdded(command, response); 057 } 058 if (command instanceof QmpDelCpu) { 059 return new CpuDeleted(command, response); 060 } 061 if (command instanceof QmpSetDisplayPassword) { 062 return new DisplayPasswordChanged(command, response); 063 } 064 return new MonitorResult(command, response); 065 } 066 067 /** 068 * Instantiates a new monitor result. 069 * 070 * @param command the command 071 * @param response the response 072 */ 073 protected MonitorResult(QmpCommand command, JsonNode response) { 074 this.executed = command; 075 this.response = response; 076 } 077 078 /** 079 * Returns the executed executed. 080 * 081 * @return the executed 082 */ 083 public QmpCommand executed() { 084 return executed; 085 } 086 087 /** 088 * Returns true if executed has been executed successfully. 089 * 090 * @return true, if successful 091 */ 092 public boolean successful() { 093 return response.has("return"); 094 } 095 096 /** 097 * Returns the values that come with the response. 098 * 099 * @return the json node 100 */ 101 @SuppressWarnings("PMD.AvoidDuplicateLiterals") 102 public JsonNode values() { 103 if (response.has("return")) { 104 return response.get("return"); 105 } 106 if (response.has("error")) { 107 return response.get("error"); 108 } 109 return null; 110 } 111 112 /** 113 * Returns the error class if this result is an error. 114 * 115 * @return the optional 116 */ 117 public Optional<String> errorClass() { 118 if (!response.has("error")) { 119 return Optional.empty(); 120 } 121 return Optional.ofNullable(response.get("error").get("class").asText()); 122 } 123 124 /** 125 * Returns the error description if this result is an error. 126 * 127 * @return the optional 128 */ 129 public Optional<String> errorDescription() { 130 if (!response.has("error")) { 131 return Optional.empty(); 132 } 133 return Optional.ofNullable(response.get("error").get("desc").asText()); 134 } 135 136 /** 137 * Combines error class and error description to a string 138 * "class: desc". Returns an empty string is this result is not an error. 139 * 140 * @return the string 141 */ 142 public String errorMessage() { 143 if (successful()) { 144 return ""; 145 } 146 return errorClass().get() + ": " + errorDescription().get(); 147 } 148 149 @Override 150 public String toString() { 151 StringBuilder builder = new StringBuilder(); 152 builder.append(Components.objectName(this)) 153 .append(" [").append(executed).append(", ").append(successful()); 154 if (channels() != null) { 155 builder.append(", channels=").append(Channel.toString(channels())); 156 } 157 builder.append(']'); 158 return builder.toString(); 159 } 160}