1# Copyright (C) 2018 Red Hat, Inc. 2# 3# This work is licensed under the GNU GPLv2 or later. 4# See the COPYING file in the top-level directory. 5 6import re 7 8import libvirt 9 10from virtinst import log 11 12 13class _LibvirtEnumMap(object): 14 """ 15 Helper for mapping libvirt event int values to their API names 16 """ 17 # Some values we define to distinguish between API objects 18 (DOMAIN_EVENT, 19 DOMAIN_AGENT_EVENT, 20 NETWORK_EVENT, 21 STORAGE_EVENT, 22 NODEDEV_EVENT) = range(1, 6) 23 24 # Regex map for naming all event types depending on the API object 25 _EVENT_PREFIX = { 26 DOMAIN_EVENT: "VIR_DOMAIN_EVENT_ID_", 27 DOMAIN_AGENT_EVENT: "VIR_DOMAIN_EVENT_ID_AGENT_", 28 NETWORK_EVENT: "VIR_NETWORK_EVENT_ID_", 29 STORAGE_EVENT: "VIR_STORAGE_POOL_EVENT_ID_", 30 NODEDEV_EVENT: "VIR_NODE_DEVICE_EVENT_ID_", 31 } 32 33 # Regex map for 'state' values returned from lifecycle and other events 34 _DETAIL1_PREFIX = { 35 "VIR_DOMAIN_EVENT_ID_LIFECYCLE": "VIR_DOMAIN_EVENT_[^_]+$", 36 "VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE": "VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_[^_]+$", 37 "VIR_NETWORK_EVENT_ID_LIFECYCLE": "VIR_NETWORK_EVENT_[^_]+$", 38 "VIR_STORAGE_POOL_EVENT_ID_LIFECYCLE": "VIR_STORAGE_POOL_EVENT_[^_]+$", 39 "VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE": "VIR_NODE_DEVICE_EVENT_[^_]+$", 40 } 41 42 # Regex map for 'reason' values returned from lifecycle and other events 43 _DETAIL2_PREFIX = { 44 "VIR_DOMAIN_EVENT_DEFINED": "VIR_DOMAIN_EVENT_DEFINED_", 45 "VIR_DOMAIN_EVENT_UNDEFINED": "VIR_DOMAIN_EVENT_UNDEFINED_", 46 "VIR_DOMAIN_EVENT_STARTED": "VIR_DOMAIN_EVENT_STARTED_", 47 "VIR_DOMAIN_EVENT_SUSPENDED": "VIR_DOMAIN_EVENT_SUSPENDED_", 48 "VIR_DOMAIN_EVENT_RESUMED": "VIR_DOMAIN_EVENT_RESUMED_", 49 "VIR_DOMAIN_EVENT_STOPPED": "VIR_DOMAIN_EVENT_STOPPED_", 50 "VIR_DOMAIN_EVENT_SHUTDOWN": "VIR_DOMAIN_EVENT_SHUTDOWN_", 51 "VIR_DOMAIN_EVENT_PMSUSPENDED": "VIR_DOMAIN_EVENT_PMSUSPENDED_", 52 "VIR_DOMAIN_EVENT_CRASHED": "VIR_DOMAIN_EVENT_CRASHED_", 53 } 54 55 VM_STATUS_ICONS = { 56 libvirt.VIR_DOMAIN_BLOCKED: "state_running", 57 libvirt.VIR_DOMAIN_CRASHED: "state_shutoff", 58 libvirt.VIR_DOMAIN_PAUSED: "state_paused", 59 libvirt.VIR_DOMAIN_RUNNING: "state_running", 60 libvirt.VIR_DOMAIN_SHUTDOWN: "state_shutoff", 61 libvirt.VIR_DOMAIN_SHUTOFF: "state_shutoff", 62 libvirt.VIR_DOMAIN_NOSTATE: "state_running", 63 libvirt.VIR_DOMAIN_PMSUSPENDED: "state_paused", 64 } 65 66 @staticmethod 67 def pretty_run_status(status, has_managed_save): 68 if status == libvirt.VIR_DOMAIN_RUNNING: 69 return _("Running") 70 elif status == libvirt.VIR_DOMAIN_PAUSED: 71 return _("Paused") 72 elif status == libvirt.VIR_DOMAIN_SHUTDOWN: 73 return _("Shutting Down") # pragma: no cover 74 elif status == libvirt.VIR_DOMAIN_SHUTOFF: 75 if has_managed_save: 76 return _("Saved") 77 else: 78 return _("Shutoff") 79 elif status == libvirt.VIR_DOMAIN_CRASHED: 80 return _("Crashed") 81 elif status == libvirt.VIR_DOMAIN_PMSUSPENDED: 82 return _("Suspended") 83 84 log.debug( # pragma: no cover 85 "Unknown status %s, returning 'Unknown'", status) 86 return _("Unknown") # pragma: no cover 87 88 @staticmethod 89 def pretty_status_reason(status, reason): 90 def key(x, y): 91 return getattr(libvirt, "VIR_DOMAIN_" + x, y) 92 reasons = { 93 libvirt.VIR_DOMAIN_RUNNING: { 94 key("RUNNING_BOOTED", 1): _("Booted"), 95 key("RUNNING_MIGRATED", 2): _("Migrated"), 96 key("RUNNING_RESTORED", 3): _("Restored"), 97 key("RUNNING_FROM_SNAPSHOT", 4): _("From snapshot"), 98 key("RUNNING_UNPAUSED", 5): _("Unpaused"), 99 key("RUNNING_MIGRATION_CANCELED", 6): _("Migration canceled"), 100 key("RUNNING_SAVE_CANCELED", 7): _("Save canceled"), 101 key("RUNNING_WAKEUP", 8): _("Event wakeup"), 102 key("RUNNING_CRASHED", 9): _("Crashed"), 103 }, 104 libvirt.VIR_DOMAIN_PAUSED: { 105 key("PAUSED_USER", 1): _("User"), 106 key("PAUSED_MIGRATION", 2): _("Migrating"), 107 key("PAUSED_SAVE", 3): _("Saving"), 108 key("PAUSED_DUMP", 4): _("Dumping"), 109 key("PAUSED_IOERROR", 5): _("I/O error"), 110 key("PAUSED_WATCHDOG", 6): _("Watchdog"), 111 key("PAUSED_FROM_SNAPSHOT", 7): _("From snapshot"), 112 key("PAUSED_SHUTTING_DOWN", 8): _("Shutting down"), 113 key("PAUSED_SNAPSHOT", 9): _("Creating snapshot"), 114 key("PAUSED_CRASHED", 10): _("Crashed"), 115 }, 116 libvirt.VIR_DOMAIN_SHUTDOWN: { 117 key("SHUTDOWN_USER", 1): _("User"), 118 }, 119 libvirt.VIR_DOMAIN_SHUTOFF: { 120 key("SHUTOFF_SHUTDOWN", 1): _("Shut Down"), 121 key("SHUTOFF_DESTROYED", 2): _("Destroyed"), 122 key("SHUTOFF_CRASHED", 3): _("Crashed"), 123 key("SHUTOFF_MIGRATED", 4): _("Migrated"), 124 key("SHUTOFF_SAVED", 5): _("Saved"), 125 key("SHUTOFF_FAILED", 6): _("Failed"), 126 key("SHUTOFF_FROM_SNAPSHOT", 7): _("From snapshot"), 127 }, 128 libvirt.VIR_DOMAIN_CRASHED: { 129 key("CRASHED_PANICKED", 1): _("Panicked"), 130 } 131 } 132 return reasons.get(status) and reasons[status].get(reason) 133 134 def __init__(self): 135 self._mapping = {} 136 137 def _make_map(self, regex): 138 # Run the passed regex over dir(libvirt) output 139 ret = {} 140 for key in [a for a in dir(libvirt) if re.match(regex, a)]: 141 val = getattr(libvirt, key) 142 if type(val) is not int: # pragma: no cover 143 log.debug("libvirt regex=%s key=%s val=%s " 144 "isn't an integer", regex, key, val) 145 continue 146 if val in ret: # pragma: no cover 147 log.debug("libvirt regex=%s key=%s val=%s is already " 148 "in dict as key=%s", regex, key, val, regex[val]) 149 continue 150 ret[val] = key 151 return ret 152 153 def _get_map(self, key, regex): 154 if regex is None: 155 return {} 156 if key not in self._mapping: 157 self._mapping[key] = self._make_map(regex) 158 return self._mapping[key] 159 160 def _make_strs(self, api, event, detail1, detail2): 161 eventstr = str(event) 162 detail1str = str(detail1) 163 detail2str = str(detail2) 164 eventmap = self._get_map(api, self._EVENT_PREFIX[api]) 165 166 if eventmap: 167 if event not in eventmap: 168 event = next(iter(eventmap)) # pragma: no cover 169 eventstr = eventmap[event] 170 detail1map = self._get_map(eventstr, 171 self._DETAIL1_PREFIX.get(eventstr)) 172 if detail1 in detail1map: 173 detail1str = detail1map[detail1] 174 detail2map = self._get_map(detail1str, 175 self._DETAIL2_PREFIX.get(detail1str)) 176 if detail2 in detail2map: 177 detail2str = detail2map[detail2] 178 179 return eventstr, detail1str, detail2str 180 181 def _state_str(self, api, detail1, detail2): 182 ignore, d1str, d2str = self._make_strs(api, 0, 183 detail1, detail2) 184 return "state=%s reason=%s" % (d1str, d2str) 185 186 def domain_lifecycle_str(self, detail1, detail2): 187 return self._state_str(self.DOMAIN_EVENT, detail1, detail2) 188 def network_lifecycle_str(self, detail1, detail2): 189 return self._state_str(self.NETWORK_EVENT, detail1, detail2) 190 def storage_lifecycle_str(self, detail1, detail2): 191 return self._state_str(self.STORAGE_EVENT, detail1, detail2) 192 def nodedev_lifecycle_str(self, detail1, detail2): 193 return self._state_str(self.NODEDEV_EVENT, detail1, detail2) 194 def domain_agent_lifecycle_str(self, detail1, detail2): 195 return self._state_str(self.DOMAIN_AGENT_EVENT, detail1, detail2) 196 197 198LibvirtEnumMap = _LibvirtEnumMap() 199