diff --git a/samples/list_host_alarms.py b/samples/list_host_alarms.py new file mode 100644 index 00000000..baa912e4 --- /dev/null +++ b/samples/list_host_alarms.py @@ -0,0 +1,57 @@ +""" +Written by Michael Rice +Github: https://github.com/michaelrice +Website: https://michaelrice.github.io/ +Blog: http://www.errr-online.com/ +This code has been released under the terms of the Apache-2.0 license +http://opensource.org/licenses/Apache-2.0 +""" +from __future__ import print_function + +import atexit + +from pyVim.connect import SmartConnect, Disconnect + +from tools import alarm +from tools import cli + + +PARSER = cli.build_arg_parser() +# If you are unsure where to get the UUID of your HostSystem check out the +# MOB. For example in my lab I would connect directly to the host mob like so: +# https://10.12.254.10/mob/?moid=ha-host&doPath=hardware%2esystemInfo +PARSER.add_argument("-x", "--uuid", + required=True, + action="store", + help="The UUID of the HostSystem to list triggered alarms" + " for.") +MY_ARGS = PARSER.parse_args() +cli.prompt_for_password(MY_ARGS) +SI = SmartConnect(host=MY_ARGS.host, + user=MY_ARGS.user, + pwd=MY_ARGS.password, + port=MY_ARGS.port) + +atexit.register(Disconnect, SI) +INDEX = SI.content.searchIndex +if INDEX: + HOST = INDEX.FindByUuid(datacenter=None, uuid=MY_ARGS.uuid, vmSearch=False) + alarm.print_triggered_alarms(entity=HOST) + # Since the above method will list all of the triggered alarms we will now + # prompt the user for the entity info needed to reset an alarm from red + # to green + try: + alarm_mor = raw_input("Enter the alarm_moref from above to reset the " + "alarm to green: ") + except KeyboardInterrupt: + # this is useful in case the user decides to quit and hits control-c + print() + raise SystemExit + if alarm_mor: + if alarm.reset_alarm(entity_moref=HOST._moId, + entity_type='HostSystem', + alarm_moref=alarm_mor.strip(), + service_instance=SI): + print("Successfully reset alarm {0} to green.".format(alarm_mor)) +else: + print("Unable to create a SearchIndex.") diff --git a/samples/tools/alarm.py b/samples/tools/alarm.py new file mode 100644 index 00000000..725c7830 --- /dev/null +++ b/samples/tools/alarm.py @@ -0,0 +1,160 @@ +""" +Written by Michael Rice +Github: https://github.com/michaelrice +Website: https://michaelrice.github.io/ +Blog: http://www.errr-online.com/ +This code has been released under the terms of the Apache 2.0 licenses +http://www.apache.org/licenses/LICENSE-2.0.html +""" +from __future__ import print_function + +__author__ = 'michael rice ' + +import logging +from xml.etree.ElementTree import Element +from xml.etree.ElementTree import SubElement +from xml.etree.ElementTree import tostring + +import requests + + +def reset_alarm(**kwargs): + """ + Resets an alarm on a given HostSystem in a vCenter to the green state + without someone having to log in to do it manually. + + This is done by using an unexposed API call. This requires us + to manually construct the SOAP envelope. We use the session key + that pyvmomi provides during its connection. + + More information can be found about this process + in this article written by William Lam: + http://www.virtuallyghetto.com/2010/10/how-to-ack-reset-vcenter-alarm.html + + I adopted his process from perl to groovy: + https://gist.github.com/michaelrice/d54a237295e017b032a5 + and from groovy now to python. + + Usage: + SI = SmartConnect(xxx) + HOST = SI.content.searchIndex.FindByxxx(xxx) + alarm.reset_alarm(entity_moref=HOST._moId, entity_type='HostSystem', + alarm_moref='alarm-1', service_instance=SI) + :param service_instance: + :param entity_moref: + :param alarm: + :return boolean: + """ + service_instance = kwargs.get("service_instance") + payload = _build_payload(**kwargs) + logging.debug(payload) + session = service_instance._stub + if not _send_request(payload, session): + return False + return True + + +def _build_payload(**kwargs): + """ + Builds a SOAP envelope to send to the vCenter hidden API + + :param entity_moref: + :param alarm_moref: + :param entity_type: + :return: + """ + entity_moref = kwargs.get("entity_moref") + entity_type = kwargs.get("entity_type") + alarm_moref = kwargs.get("alarm_moref") + if not entity_moref or not entity_type or not alarm_moref: + raise ValueError("entity_moref, entity_type, and alarm_moref " + "must be set") + + attribs = { + 'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema', + 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', + 'xmlns:soap': 'http://schemas.xmlsoap.org/soap/envelope/' + } + root = Element('soap:Envelope', attribs) + body = SubElement(root, 'soap:Body') + alarm_status = SubElement(body, 'SetAlarmStatus', {'xmlns': 'urn:vim25'}) + this = SubElement(alarm_status, '_this', { + 'xsi:type': 'ManagedObjectReference', + 'type': 'AlarmManager' + }) + this.text = 'AlarmManager' + alarm = SubElement(alarm_status, 'alarm', {'type': 'Alarm'}) + alarm.text = alarm_moref + entity = SubElement(alarm_status, 'entity', { + 'xsi:type': 'ManagedObjectReference', + 'type': entity_type + }) + entity.text = entity_moref + status = SubElement(alarm_status, 'status') + status.text = 'green' + # I hate hard coding this but I have no idea how to do it any other way + # pull requests welcome :) + return '{0}'.format(tostring(root)) + + +def _send_request(payload=None, session=None): + """ + Using requests we send a SOAP envelope directly to the + vCenter API to reset an alarm to the green state. + + :param payload: + :param session: + :return: + """ + stub = session + host_port = stub.host + # Ive seen some code in pyvmomi where it seems like we check for http vs + # https but since the default is https do people really run it on http? + url = 'https://{0}/sdk'.format(host_port) + logging.debug("Sending {0} to {1}".format(payload, url)) + # I opted to ignore invalid ssl here because that happens in pyvmomi. + # Once pyvmomi validates ssl it wont take much to make it happen here. + res = requests.post(url=url, data=payload, headers={ + 'Cookie': stub.cookie, + 'SOAPAction': 'urn:vim25', + 'Content-Type': 'application/xml' + }, verify=False) + if res.status_code != 200: + logging.debug("Failed to reset alarm. HTTP Status: {0}".format( + res.status_code)) + return False + return True + + +def print_triggered_alarms(entity=None): + """ + This is a useful method if you need to print out the alarm morefs + + :param entity: + """ + alarms = entity.triggeredAlarmState + for alarm in alarms: + print("#"*40) + # The alarm key looks like alarm-101.host-95 + print("alarm_moref: {0}".format(alarm.key.split('.')[0])) + print("alarm status: {0}".format(alarm.overallStatus)) + + +def get_alarm_refs(entity=None): + """ + Useful method that will return a list of dict with the moref and alarm + status for all triggered alarms on a given entity. + + + :param entity: + :return dict: [{'alarm':'alarm-101', 'status':'red'}] + """ + alarm_states = entity.triggeredAlarmState + ret = [] + for alarm_state in alarm_states: + tdict = { + "alarm": alarm_state.key.split('.')[0], + "status": alarm_state.overallStatus + } + ret.append(tdict) + return ret