diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:50:17 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:50:17 +0000 |
commit | 86ed03f8adee56c050c73018537371c230a664a6 (patch) | |
tree | eae3d04cdf1c49848e5a671327ab38297f4acb0d /agents | |
parent | Initial commit. (diff) | |
download | fence-agents-fb571b7c89d25dc39569886fc83b92e1c2b4bb08.tar.xz fence-agents-fb571b7c89d25dc39569886fc83b92e1c2b4bb08.zip |
Adding upstream version 4.12.1.upstream/4.12.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'agents')
174 files changed, 67448 insertions, 0 deletions
diff --git a/agents/Makefile.am b/agents/Makefile.am new file mode 100644 index 0000000..88e0c60 --- /dev/null +++ b/agents/Makefile.am @@ -0,0 +1,123 @@ +MAINTAINERCLEANFILES = Makefile.in + +TARGET = $(AGENTS_LIST:%.py=%) + +SRC = $(TARGET:=.py) + +CLEAN_TARGET_ADDITIONAL = kdump/fence_kdump_send manual/fence_ack_manual */*.o + +EXTRA_DIST = $(SRC) + +sbin_PROGRAMS = +sbin_SCRIPTS = $(TARGET) +libexec_PROGRAMS = + +noinst_HEADERS = kdump/list.h kdump/message.h kdump/options.h kdump/version.h zvm/fence_zvm.h + +man_MANS = $(sbin_SCRIPTS:=.8) +dist_man_MANS = + +EXTRA_SCRIPTS = + +if BUILD_FENCE_VIRT +SUBDIRS = virt +endif + +if BUILD_FENCE_KDUMP +sbin_PROGRAMS += kdump/fence_kdump +libexec_PROGRAMS += kdump/fence_kdump_send + +man_MANS += kdump/fence_kdump.8 +dist_man_MANS += kdump/fence_kdump_send.8 + +kdump_fence_kdump_SOURCES = kdump/fence_kdump.c +kdump_fence_kdump_CFLAGS = -D_GNU_SOURCE -Ikdump $(AM_CFLAGS) -Wno-cast-align + +kdump_fence_kdump_send_SOURCES = kdump/fence_kdump_send.c +kdump_fence_kdump_send_CFLAGS = -D_GNU_SOURCE -Ikdump $(AM_CFLAGS) -Wno-cast-align +endif + +if BUILD_FENCE_MANUAL +EXTRA_DIST += manual/fence_ack_manual.in manual/fence_ack_manual.8 + +sbin_SCRIPTS += manual/fence_ack_manual +endif + +if BUILD_FENCE_ZVM +EXTRA_DIST += zvm/fence_zvm_man_page + +sbin_PROGRAMS += zvm/fence_zvm + +man_MANS += zvm/fence_zvm.8 + +zvm_fence_zvm_SOURCES = zvm/fence_zvm.c +zvm_fence_zvm_CFLAGS = -D_GNU_SOURCE -Izvm $(AM_CFLAGS) +endif + +if BUILD_FENCE_MPATH +mpathdatadir = $(CLUSTERDATA) +mpathdata_SCRIPTS = mpath/fence_mpath_check mpath/fence_mpath_check_hardreboot +endif + +if BUILD_FENCE_SCSI +scsidatadir = $(CLUSTERDATA) +scsidata_SCRIPTS = scsi/fence_scsi_check scsi/fence_scsi_check_hardreboot +endif + +FENCE_TEST_ARGS = \ +login=test\n\ +passwd=test\n\ +ipaddr=test\n\ +port=1\n\ +managed=1\n\ +devices=test\n\ +session_url=http://test\n\ +email=test@test.te\n\ +ping_targets=localhost + +manual/fence_ack_manual: manual/fence_ack_manual.in + mkdir -p $(@D) + cat $^ | sed \ + -e 's#@clustervarrun@#${CLUSTERVARRUN}#g' \ + > $@ + +mpath/fence_mpath_check: mpath/fence_mpath + cp $^ $@ + +mpath/fence_mpath_check_hardreboot: mpath/fence_mpath + cp $^ $@ + +scsi/fence_scsi_check: scsi/fence_scsi + cp $^ $@ + +scsi/fence_scsi_check_hardreboot: scsi/fence_scsi + cp $^ $@ + +kdump/fence_kdump.8: kdump/fence_kdump $(top_srcdir)/lib/fence2man.xsl + set -e && \ + ./$(@:%.8=%) -o metadata > $(@D)/.$(@F).tmp && \ + xmllint --noout --relaxng $(top_srcdir)/lib/metadata.rng $(@D)/.$(@F).tmp && \ + xsltproc $(top_srcdir)/lib/fence2man.xsl $(@D)/.$(@F).tmp > $@ + xsltproc $(top_srcdir)/lib/fence2wiki.xsl $(@D)/.$(@F).tmp | grep -v '<?xml' > $(@D)/$(@F:%.8=%.wiki) + +kdump/fence_kdump_send.8: + true + +manual/fence_ack_manual.8: + true + +zvm/fence_zvm.8: zvm/fence_zvm + cp $(top_srcdir)/agents/zvm/fence_zvm_man_page $(@D)/fence_zvm.8 + +cisco_mds/fence_cisco_mds.delay-check: cisco_mds/fence_cisco_mds + $(eval INPUT=$(subst .delay-check,,$@)) + FENCE_TEST_ARGS_CISCO_MDS=$$(printf '$(FENCE_TEST_ARGS)' | sed 's#port=1#port=fc1/1#'); \ + test `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \ + sh -c "printf 'delay=10\n $$FENCE_TEST_ARGS_CISCO_MDS' | $(PYTHON) ./$(INPUT)" 2>&1 |\ + awk -F"[. ]" -vOFS= '/real/ {print $$2,$$3}'` -ge 1000 || ( \ + PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \ + sh -c "printf "delay=0\n $$FENCE_TEST_ARGS_CISCO_MDS" | $(PYTHON) ./$(INPUT)"; false ) + +include $(top_srcdir)/make/fencebuild.mk +include $(top_srcdir)/make/fenceman.mk +include $(top_srcdir)/make/agentpycheck.mk diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py new file mode 100644 index 0000000..1e9c790 --- /dev/null +++ b/agents/aliyun/fence_aliyun.py @@ -0,0 +1,192 @@ +#!@PYTHON@ -tt + +import sys +import logging +import atexit +import json + +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, run_delay + + +try: + from aliyunsdkcore import client + from aliyunsdkcore.auth.credentials import EcsRamRoleCredential + from aliyunsdkcore.profile import region_provider +except ImportError as e: + logging.warn("The 'aliyunsdkcore' module has been not installed or is unavailable, try to execute the command 'pip install aliyun-python-sdk-core --upgrade' to solve. error: %s" % e) + + +try: + from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest + from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest + from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest + from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest +except ImportError as e: + logging.warn("The 'aliyunsdkecs' module has been not installed or is unavailable, try to execute the command 'pip install aliyun-python-sdk-ecs --upgrade' to solve. error: %s" % e) + + +def _send_request(conn, request): + logging.debug("send request action: %s" % request.get_action_name()) + request.set_accept_format('json') + try: + response_str = conn.do_action_with_exception(request) + except Exception as e: + fail_usage("Failed: send request failed: Error: %s" % e) + + response_detail = json.loads(response_str) + logging.debug("reponse: %s" % response_detail) + return response_detail + +def start_instance(conn, instance_id): + logging.debug("start instance %s" % instance_id) + request = StartInstanceRequest() + request.set_InstanceId(instance_id) + _send_request(conn, request) + +def stop_instance(conn, instance_id): + logging.debug("stop instance %s" % instance_id) + request = StopInstanceRequest() + request.set_InstanceId(instance_id) + request.set_ForceStop('true') + _send_request(conn, request) + +def reboot_instance(conn, instance_id): + logging.debug("reboot instance %s" % instance_id) + request = RebootInstanceRequest() + request.set_InstanceId(instance_id) + request.set_ForceStop('true') + _send_request(conn, request) + +def get_status(conn, instance_id): + logging.debug("get instance %s status" % instance_id) + request = DescribeInstancesRequest() + request.set_InstanceIds(json.dumps([instance_id])) + response = _send_request(conn, request) + instance_status = None + if response is not None: + instance_list = response.get('Instances').get('Instance') + for item in instance_list: + instance_status = item.get('Status') + return instance_status + +def get_nodes_list(conn, options): + logging.debug("start to get nodes list") + result = {} + request = DescribeInstancesRequest() + request.set_PageSize(100) + response = _send_request(conn, request) + if response is not None: + instance_list = response.get('Instances').get('Instance') + for item in instance_list: + instance_id = item.get('InstanceId') + instance_name = item.get('InstanceName') + result[instance_id] = (instance_name, None) + logging.debug("get nodes list: %s" % result) + return result + +def get_power_status(conn, options): + logging.debug("start to get power(%s) status" % options["--plug"]) + state = get_status(conn, options["--plug"]) + + if state == "Running": + status = "on" + elif state == "Stopped": + status = "off" + else: + status = "unknown" + logging.debug("the power(%s) status is %s" % (options["--plug"], status)) + return status + +def set_power_status(conn, options): + logging.info("start to set power(%s) status to %s" % (options["--plug"], options["--action"])) + + if (options["--action"]=="off"): + stop_instance(conn, options["--plug"]) + elif (options["--action"]=="on"): + start_instance(conn, options["--plug"]) + elif (options["--action"]=="reboot"): + reboot_instance(conn, options["--plug"]) + +def define_new_opts(): + all_opt["region"] = { + "getopt" : "r:", + "longopt" : "region", + "help" : "-r, --region=[name] Region, e.g. cn-hangzhou", + "shortdesc" : "Region.", + "required" : "0", + "order" : 2 + } + all_opt["access_key"] = { + "getopt" : "a:", + "longopt" : "access-key", + "help" : "-a, --access-key=[name] Access Key", + "shortdesc" : "Access Key.", + "required" : "0", + "order" : 3 + } + all_opt["secret_key"] = { + "getopt" : "s:", + "longopt" : "secret-key", + "help" : "-s, --secret-key=[name] Secret Key", + "shortdesc" : "Secret Key.", + "required" : "0", + "order" : 4 + } + all_opt["ram_role"] = { + "getopt": ":", + "longopt": "ram-role", + "help": "--ram-role=[name] Ram Role", + "shortdesc": "Ram Role.", + "required": "0", + "order": 5 + } + +# Main agent method +def main(): + conn = None + + device_opt = ["port", "no_password", "region", "access_key", "secret_key", "ram_role"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["power_timeout"]["default"] = "60" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Aliyun (Aliyun Web Services)" + docs["longdesc"] = "fence_aliyun is an I/O Fencing agent for Aliyun" + docs["vendorurl"] = "http://www.aliyun.com" + show_docs(options, docs) + + run_delay(options) + + if "--region" in options: + region = options["--region"] + if "--access-key" in options and "--secret-key" in options: + access_key = options["--access-key"] + secret_key = options["--secret-key"] + conn = client.AcsClient(access_key, secret_key, region) + elif "--ram-role" in options: + ram_role = options["--ram-role"] + role = EcsRamRoleCredential(ram_role) + conn = client.AcsClient(region_id=region, credential=role) + else: + fail_usage("Failed: User credentials are not set. Please set the Access Key and the Secret Key, or configure the RAM role.") + + # Use intranet endpoint to access ECS service + try: + region_provider.modify_point('Ecs', region, 'ecs.%s.aliyuncs.com' % region) + except Exception as e: + logging.warn("Failed: failed to modify endpoint to 'ecs.%s.aliyuncs.com': %s" % (region, e)) + + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/alom/fence_alom.py b/agents/alom/fence_alom.py new file mode 100644 index 0000000..7b03dc2 --- /dev/null +++ b/agents/alom/fence_alom.py @@ -0,0 +1,53 @@ +#!@PYTHON@ -tt + +# The Following Agent Has Been Tested On: +# +# Sun(tm) Advanced Lights Out Manager CMT v1.6.1 +# as found on SUN T2000 Niagara + +import sys, re, time +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * + +def get_power_status(conn, options): + conn.send_eol("showplatform") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + status = re.search("standby", conn.before.lower()) + result = (status != None and "off" or "on") + + return result + +def set_power_status(conn, options): + cmd_line = (options["--action"] == "on" and "poweron" or "poweroff -f -y") + conn.send_eol(cmd_line) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + # Get the machine some time between poweron and poweroff + time.sleep(int(options["--power-timeout"])) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure"] + + atexit.register(atexit_handler) + + all_opt["secure"]["default"] = "1" + all_opt["cmd_prompt"]["default"] = [r"sc\>\ "] + + options = check_input(device_opt, process_input(device_opt)) + options["telnet_over_ssh"] = 1 + + docs = {} + docs["shortdesc"] = "Fence agent for Sun ALOM" + docs["longdesc"] = "fence_alom is an I/O Fencing \ +agent which can be used with ALOM connected machines." + docs["vendorurl"] = "http://www.sun.com" + show_docs(options, docs) + + # Operate the fencing device + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, None) + fence_logout(conn, "logout") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/amt/fence_amt.py b/agents/amt/fence_amt.py new file mode 100644 index 0000000..feec6e3 --- /dev/null +++ b/agents/amt/fence_amt.py @@ -0,0 +1,128 @@ +#!@PYTHON@ -tt + +import sys, re, os +import atexit +from pipes import quote +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, is_executable, run_command, run_delay + +def get_power_status(_, options): + output = amt_run_command(options, create_command(options, "status")) + match = re.search('Powerstate:[\\s]*(..)', str(output)) + status = match.group(1) if match else None + + if status == None: + return "fail" + elif status == "S0": # SO = on; S3 = sleep; S5 = off + return "on" + else: + return "off" + +def set_power_status(_, options): + amt_run_command(options, create_command(options, options["--action"])) + return + +def reboot_cycle(_, options): + (status, _, _) = run_command(options, create_command(options, "cycle")) + return not bool(status) + +def amt_run_command(options, command, timeout=None): + env = os.environ.copy() + + x = quote(options["--password"]) + x = x[:-1] if x.endswith("'") else x + x = x[1:] if x.startswith("'") else x + env["AMT_PASSWORD"] = x + + # This is needed because setting the AMT_PASSWORD env + # variable only works when no pipe is involved. E.g.: + # - Broken: + # $ AMT_PASSWORD='foobar' echo 'y' | /usr/bin/amttool nuc2 powerdown + # 401 Unauthorized at /usr/bin/amttool line 129. + # - Working: + # $ AMT_PASSWORD='foobar' sh -c "(echo 'y' | /usr/bin/amttool nuc2 powerdown)" + # execute: powerdown + # result: pt_status: success + newcommand = "sh -c \"(%s)\"" % command + return run_command(options, newcommand, timeout, env) + +def create_command(options, action): + cmd = options["--amttool-path"] + + # --ip / -a + cmd += " " + options["--ip"] + + # --action / -o + if action == "status": + cmd += " info" + elif action == "on": + cmd = "echo \"y\"|" + cmd + cmd += " powerup" + elif action == "off": + cmd = "echo \"y\"|" + cmd + cmd += " powerdown" + elif action == "cycle": + cmd = "echo \"y\"|" + cmd + cmd += " powercycle" + if action in ["on", "off", "cycle"] and "--boot-option" in options: + cmd += options["--boot-option"] + + # --use-sudo / -d + if "--use-sudo" in options: + cmd = options["--sudo-path"] + " " + cmd + + return cmd + +def define_new_opts(): + all_opt["boot_option"] = { + "getopt" : "b:", + "longopt" : "boot-option", + "help" : "-b, --boot-option=[option] " + "Change the default boot behavior of the machine. (pxe|hd|hdsafe|cd|diag)", + "required" : "0", + "shortdesc" : "Change the default boot behavior of the machine.", + "choices" : ["pxe", "hd", "hdsafe", "cd", "diag"], + "order" : 1 + } + all_opt["amttool_path"] = { + "getopt" : ":", + "longopt" : "amttool-path", + "help" : "--amttool-path=[path] Path to amttool binary", + "required" : "0", + "shortdesc" : "Path to amttool binary", + "default" : "@AMTTOOL_PATH@", + "order": 200 + } + +def main(): + atexit.register(atexit_handler) + + device_opt = ["ipaddr", "no_login", "passwd", "boot_option", "no_port", + "sudo", "amttool_path", "method"] + + define_new_opts() + + all_opt["ipport"]["default"] = "16994" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for AMT" + docs["longdesc"] = "fence_amt is an I/O Fencing agent \ +which can be used with Intel AMT. This agent calls support software amttool\ +(http://www.kraxel.org/cgit/amtterm/)." + docs["vendorurl"] = "http://www.intel.com/" + show_docs(options, docs) + + run_delay(options) + + if not is_executable(options["--amttool-path"]): + fail_usage("Amttool not found or not accessible") + + result = fence_action(None, options, set_power_status, get_power_status, None, reboot_cycle) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/amt_ws/fence_amt_ws.py b/agents/amt_ws/fence_amt_ws.py new file mode 100755 index 0000000..5e7452a --- /dev/null +++ b/agents/amt_ws/fence_amt_ws.py @@ -0,0 +1,240 @@ +#!@PYTHON@ -tt + +# +# Fence agent for Intel AMT (WS) based on code from the openstack/ironic project: +# https://github.com/openstack/ironic/blob/master/ironic/drivers/modules/amt/power.py +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import sys +import atexit +import logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import run_delay, fail_usage, fail, EC_STATUS + +from xml.etree import ElementTree + +try: + import pywsman +except ImportError: + pass + +POWER_ON='2' +POWER_OFF='8' +POWER_CYCLE='10' + +RET_SUCCESS = '0' + +CIM_PowerManagementService = ('http://schemas.dmtf.org/wbem/wscim/1/' + 'cim-schema/2/CIM_PowerManagementService') +CIM_ComputerSystem = ('http://schemas.dmtf.org/wbem/wscim/' + '1/cim-schema/2/CIM_ComputerSystem') +CIM_AssociatedPowerManagementService = ('http://schemas.dmtf.org/wbem/wscim/' + '1/cim-schema/2/' + 'CIM_AssociatedPowerManagementService') + +CIM_BootConfigSetting = ('http://schemas.dmtf.org/wbem/wscim/' + '1/cim-schema/2/CIM_BootConfigSetting') +CIM_BootSourceSetting = ('http://schemas.dmtf.org/wbem/wscim/' + '1/cim-schema/2/CIM_BootSourceSetting') + + +def xml_find(doc, namespace, item): + if doc is None: + return + tree = ElementTree.fromstring(doc.root().string()) + query = ('.//{%(namespace)s}%(item)s' % {'namespace': namespace, + 'item': item}) + return tree.find(query) + +def _generate_power_action_input(action): + method_input = "RequestPowerStateChange_INPUT" + address = 'http://schemas.xmlsoap.org/ws/2004/08/addressing' + anonymous = ('http://schemas.xmlsoap.org/ws/2004/08/addressing/' + 'role/anonymous') + wsman = 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' + namespace = CIM_PowerManagementService + + doc = pywsman.XmlDoc(method_input) + root = doc.root() + root.set_ns(namespace) + root.add(namespace, 'PowerState', action) + + child = root.add(namespace, 'ManagedElement', None) + child.add(address, 'Address', anonymous) + + grand_child = child.add(address, 'ReferenceParameters', None) + grand_child.add(wsman, 'ResourceURI', CIM_ComputerSystem) + + g_grand_child = grand_child.add(wsman, 'SelectorSet', None) + g_g_grand_child = g_grand_child.add(wsman, 'Selector', 'ManagedSystem') + g_g_grand_child.attr_add(wsman, 'Name', 'Name') + return doc + +def get_power_status(_, options): + client = pywsman.Client(options["--ip"], int(options["--ipport"]), \ + '/wsman', 'http', 'admin', options["--password"]) + namespace = CIM_AssociatedPowerManagementService + client_options = pywsman.ClientOptions() + doc = client.get(client_options, namespace) + _SOAP_ENVELOPE = 'http://www.w3.org/2003/05/soap-envelope' + item = 'Fault' + fault = xml_find(doc, _SOAP_ENVELOPE, item) + if fault is not None: + logging.error("Failed to get power state for: %s port:%s", \ + options["--ip"], options["--ipport"]) + fail(EC_STATUS) + + item = "PowerState" + try: power_state = xml_find(doc, namespace, item).text + except AttributeError: + logging.error("Failed to get power state for: %s port:%s", \ + options["--ip"], options["--ipport"]) + fail(EC_STATUS) + if power_state == POWER_ON: + return "on" + elif power_state == POWER_OFF: + return "off" + else: + fail(EC_STATUS) + +def set_power_status(_, options): + client = pywsman.Client(options["--ip"], int(options["--ipport"]), \ + '/wsman', 'http', 'admin', options["--password"]) + + method = 'RequestPowerStateChange' + client_options = pywsman.ClientOptions() + client_options.add_selector('Name', 'Intel(r) AMT Power Management Service') + + if options["--action"] == "on": + target_state = POWER_ON + elif options["--action"] == "off": + target_state = POWER_OFF + elif options["--action"] == "reboot": + target_state = POWER_CYCLE + if options["--action"] in ["on", "off", "reboot"] \ + and "--boot-option" in options: + set_boot_order(_, client, options) + + doc = _generate_power_action_input(target_state) + client_doc = client.invoke(client_options, CIM_PowerManagementService, \ + method, doc) + item = "ReturnValue" + return_value = xml_find(client_doc, CIM_PowerManagementService, item).text + if return_value != RET_SUCCESS: + logging.error("Failed to set power state: %s for: %s", \ + options["--action"], options["--ip"]) + fail(EC_STATUS) + +def set_boot_order(_, client, options): + method_input = "ChangeBootOrder_INPUT" + address = 'http://schemas.xmlsoap.org/ws/2004/08/addressing' + anonymous = ('http://schemas.xmlsoap.org/ws/2004/08/addressing/' + 'role/anonymous') + wsman = 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' + namespace = CIM_BootConfigSetting + + if options["--boot-option"] == "PXE": + device = "Intel(r) AMT: Force PXE Boot" + elif options["--boot-option"] in ["HD", "HDSAFE"]: + device = "Intel(r) AMT: Force Hard-drive Boot" + elif options["--boot-option"] == "CD": + device = "Intel(r) AMT: Force CD/DVD Boot" + elif options["--boot-option"] == "DIAG": + device = "Intel(r) AMT: Force Diagnostic Boot" + else: + logging.error('Boot device: %s not supported.', \ + options["--boot-option"]) + return + + method = 'ChangeBootOrder' + client_options = pywsman.ClientOptions() + client_options.add_selector('InstanceID', \ + 'Intel(r) AMT: Boot Configuration 0') + + doc = pywsman.XmlDoc(method_input) + root = doc.root() + root.set_ns(namespace) + + child = root.add(namespace, 'Source', None) + child.add(address, 'Address', anonymous) + + grand_child = child.add(address, 'ReferenceParameters', None) + grand_child.add(wsman, 'ResourceURI', CIM_BootSourceSetting) + + g_grand_child = grand_child.add(wsman, 'SelectorSet', None) + g_g_grand_child = g_grand_child.add(wsman, 'Selector', device) + g_g_grand_child.attr_add(wsman, 'Name', 'InstanceID') + if options["--boot-option"] == "hdsafe": + g_g_grand_child = g_grand_child.add(wsman, 'Selector', 'True') + g_g_grand_child.attr_add(wsman, 'Name', 'UseSafeMode') + + client_doc = client.invoke(client_options, CIM_BootConfigSetting, \ + method, doc) + item = "ReturnValue" + return_value = xml_find(client_doc, CIM_BootConfigSetting, item).text + if return_value != RET_SUCCESS: + logging.error("Failed to set boot device to: %s for: %s", \ + options["--boot-option"], options["--ip"]) + fail(EC_STATUS) + +def reboot_cycle(_, options): + status = set_power_status(_, options) + return not bool(status) + +def define_new_opts(): + all_opt["boot_option"] = { + "getopt" : "b:", + "longopt" : "boot-option", + "help" : "-b, --boot-option=[option] " + "Change the default boot behavior of the\n" + " machine." + " (pxe|hd|hdsafe|cd|diag)", + "required" : "0", + "shortdesc" : "Change the default boot behavior of the machine.", + "choices" : ["pxe", "hd", "hdsafe", "cd", "diag"], + "order" : 1 + } + +def main(): + atexit.register(atexit_handler) + + device_opt = ["ipaddr", "no_login", "passwd", "boot_option", "no_port", + "method"] + + define_new_opts() + + all_opt["ipport"]["default"] = "16992" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for AMT (WS)" + docs["longdesc"] = "fence_amt_ws is an I/O Fencing agent \ +which can be used with Intel AMT (WS). This agent requires \ +the pywsman Python library which is included in OpenWSMAN. \ +(http://openwsman.github.io/)." + docs["vendorurl"] = "http://www.intel.com/" + show_docs(options, docs) + + run_delay(options) + + result = fence_action(None, options, set_power_status, get_power_status, \ + None, reboot_cycle) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/apc/fence_apc.py b/agents/apc/fence_apc.py new file mode 100644 index 0000000..3ea0f37 --- /dev/null +++ b/agents/apc/fence_apc.py @@ -0,0 +1,263 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## Model Firmware +## +---------------------------------------------+ +## AP7951 AOS v2.7.0, PDU APP v2.7.3 +## AP7941 AOS v3.5.7, PDU APP v3.5.6 +## AP9606 AOS v2.5.4, PDU APP v2.7.3 +## +## @note: ssh is very slow on AP79XX devices protocol (1) and +## cipher (des/blowfish) have to be defined +##### + +import sys, re, time +import logging +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, EC_STATUS + +# Fix for connection timed out issue in: +# https://bugzilla.redhat.com/show_bug.cgi?id=1342584 +TIMEDOUT_DELAY = 0.5 + +def get_power_status(conn, options): + exp_result = 0 + outlets = {} + + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + version = 0 + admin = 0 + switch = 0 + + if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before): + switch = 1 + if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before): + if "--switch" not in options: + fail_usage("Failed: You have to enter physical switch number") + else: + if "--switch" not in options: + options["--switch"] = "1" + + if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before): + version = 2 + else: + version = 3 + + if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before): + admin = 0 + else: + admin = 1 + + if switch == 0: + if version == 2: + if admin == 0: + conn.send_eol("2") + else: + conn.send_eol("3") + else: + conn.send_eol("2") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.send_eol("1") + else: + conn.send_eol(options["--switch"]) + + while True: + exp_result = conn.log_expect( + ["Press <ENTER>"] + options["--command-prompt"], int(options["--shell-timeout"])) + lines = conn.before.split("\n") + show_re = re.compile(r'(^|\x0D)\s*(\d+)- (.*?)\s+(ON|OFF)\s*') + for line in lines: + res = show_re.search(line) + if res != None: + outlets[res.group(2)] = (res.group(3), res.group(4)) + time.sleep(TIMEDOUT_DELAY) + conn.send_eol("") + if exp_result != 0: + break + conn.send(chr(0o3)) + conn.log_expect("- Logout", int(options["--shell-timeout"])) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + if ["list", "monitor"].count(options["--action"]) == 1: + return outlets + else: + try: + (_, status) = outlets[options["--plug"]] + return status.lower().strip() + except KeyError as e: + logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + +def set_power_status(conn, options): + action = { + 'on' : "1", + 'off': "2" + }[options["--action"]] + + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + version = 0 + admin2 = 0 + admin3 = 0 + switch = 0 + + if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before): + switch = 1 + ## MasterSwitch has different schema for on/off actions + action = { + 'on' : "1", + 'off': "3" + }[options["--action"]] + if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before): + if "--switch" not in options: + fail_usage("Failed: You have to enter physical switch number") + else: + if "--switch" not in options: + options["--switch"] = 1 + + if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before): + version = 2 + else: + version = 3 + + if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before): + admin2 = 0 + else: + admin2 = 1 + + if switch == 0: + if version == 2: + if admin2 == 0: + conn.send_eol("2") + else: + conn.send_eol("3") + else: + conn.send_eol("2") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + if None == re.compile('.*2- Outlet Restriction.*', re.IGNORECASE | re.S).match(conn.before): + admin3 = 0 + else: + admin3 = 1 + conn.send_eol("1") + else: + conn.send_eol(options["--switch"]) + + while 0 == conn.log_expect( + ["Press <ENTER>"] + options["--command-prompt"], int(options["--shell-timeout"])): + time.sleep(TIMEDOUT_DELAY) + conn.send_eol("") + + conn.send_eol(options["--plug"]+"") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + if switch == 0: + if admin2 == 1: + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + if admin3 == 1: + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + else: + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + conn.send_eol(action) + conn.log_expect("Enter 'YES' to continue or <ENTER> to cancel :", int(options["--shell-timeout"])) + conn.send_eol("YES") + conn.log_expect("Press <ENTER> to continue...", int(options["--power-timeout"])) + time.sleep(TIMEDOUT_DELAY) + conn.send_eol("") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + conn.send(chr(0o3)) + conn.log_expect("- Logout", int(options["--shell-timeout"])) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def get_power_status5(conn, options): + outlets = {} + + conn.send_eol("olStatus all") + + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + lines = conn.before.split("\n") + + show_re = re.compile(r'^\s*(\d+): (.*): (On|Off)\s*$', re.IGNORECASE) + + for line in lines: + res = show_re.search(line) + if res != None: + outlets[res.group(1)] = (res.group(2), res.group(3)) + + if ["list", "monitor"].count(options["--action"]) == 1: + return outlets + else: + try: + (_, status) = outlets[options["--plug"]] + return status.lower().strip() + except KeyError as e: + logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + +def set_power_status5(conn, options): + action = { + 'on' : "olOn", + 'off': "olOff" + }[options["--action"]] + + conn.send_eol(action + " " + options["--plug"]) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "port", "switch", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["\n>", "\napc>"] + all_opt["ssh_options"]["default"] = "-1 -c blowfish" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for APC over telnet/ssh" + docs["longdesc"] = "fence_apc is an I/O Fencing agent \ +which can be used with the APC network power switch. It logs into device \ +via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh connections \ +should be avoided while a GFS cluster is running because the connection \ +will block any necessary fencing actions." + docs["vendorurl"] = "http://www.apc.com" + show_docs(options, docs) + + ## Support for --plug [switch]:[plug] notation that was used before + if (("--plug" in options) == 1) and (-1 != options["--plug"].find(":")): + (switch, plug) = options["--plug"].split(":", 1) + options["--switch"] = switch + options["--plug"] = plug + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + + ## Detect firmware version (ASCII menu vs command-line interface) + ## and continue with proper action + #### + result = -1 + firmware_version = re.compile(r'\s*v(\d)*\.').search(conn.before) + if (firmware_version != None) and (firmware_version.group(1) in [ "5", "6", "7" ]): + result = fence_action(conn, options, set_power_status5, get_power_status5, get_power_status5) + else: + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + + fence_logout(conn, "4") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/apc_snmp/README b/agents/apc_snmp/README new file mode 100644 index 0000000..75aa37a --- /dev/null +++ b/agents/apc_snmp/README @@ -0,0 +1,45 @@ +This is an snmp based fence agent for APC power switches to be used +with RHEL4 Red Hat Cluster Suite. + +The reasons to use this agent rather than the current fence_apc agent are: +1) This script has been tested with EVERY powerswitch that APC currently +makes. +2) It will work on many older models that are no longer supported by APC. +I have been told that it even works with the AP9200 switch. Older switches +usually don't do well with the fence_apc script. +3) This agent works with large power switches that have more than 8 outlets. +The fence_apc script will also, in the next update -- this script will work for you now. + +If feedback on this beta version of the agent is good, and if ganged switches +can be supported, then this agent may replace fence_apc. + +In order to use this agent, you will need to have net-snmp-utils installed +on every node in your cluster. net-snmp-utils is scheduled for inclusion +in the base RHEL distribution for Update 4, and is yummable in FC5. + +After net-snmp-utils is installed, there will be a directory named: +/usr/share/snmp/mibs/ + +Place the accompanying powernet369.mib file in this directory. + +To use the agent, cp the agent to the /sbin directory on every +cluster node. The interface for the fence_apc_snmp agent is identical to +the existing fence_apc agent, so if you are using APC for fencing in +your cluster, you *could* backup your current fence_apc agent, and +rename this agent from fence_apc_snmp to fence_apc, and it should just work. + +NOTE: The fence_apc_snmp agent does not yet support ganged or 'daisy-chained' +APC switches. + +If you would rather not copy over your fence_apc agent, you can still use +the fence_apc_snmp agent by dropping it into /sbin on every node, and then +defining a <fencedevice> in the cluster.conf file with agent="fence_apc_snmp" +as an attribute, and use it that way. Note, please, that the GUI does +not support this agent yet, and you will have to edit your cluster.conf +by hand and then propagate it yourself. If you need help with this, email +me on linux-cluster or at the address below. + +Big thanks to Nate Straz who laid the foundation for this agent. + +Please let me know how this agent works. +--Jim Parsons - jparsons@redhat.com diff --git a/agents/apc_snmp/fence_apc_snmp.py b/agents/apc_snmp/fence_apc_snmp.py new file mode 100644 index 0000000..cd60166 --- /dev/null +++ b/agents/apc_snmp/fence_apc_snmp.py @@ -0,0 +1,232 @@ +#!@PYTHON@ -tt + +# The Following agent has been tested on: +# - APC Switched Rack PDU - SNMP v1 +# (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3 +# AN1:apc_hw02_aos_270.bin AF1:v2.7.3 AN1:apc_hw02_rpdu_273.bin MN:AP7930 HR:B2) +# - APC Web/SNMP Management Card - SNMP v1 and v3 (noAuthNoPrivacy,authNoPrivacy, authPrivacy) +# (MB:v3.8.6 PF:v3.5.8 PN:apc_hw02_aos_358.bin AF1:v3.5.7 +# AN1:apc_hw02_aos_358.bin AF1:v3.5.7 AN1:apc_hw02_rpdu_357.bin MN:AP7900 HR:B2) +# - APC Switched Rack PDU - SNMP v1 +# (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3 +# AN1:apc_hw02_rpdu_273.bin MN:AP7951 HR:B2) +# - Tripplite PDUMH20HVNET 12.04.0055 - SNMP v1, v2c, v3 +# - Tripplite PDU15NETLX 15.5.4 - SNMP v1, v2c, v3 + +import sys +import atexit +import logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage +from fencing_snmp import FencingSnmp + +### CONSTANTS ### +# oid defining fence device +OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' + +### GLOBAL VARIABLES ### +# Device - see ApcRPDU, ApcMSP, ApcMS, TripplitePDU, TrippliteLXPDU +device = None + +# Port ID +port_id = None +# Switch ID +switch_id = None + +# Classes describing Device params +class TripplitePDU(object): + # Rack PDU + status_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.2.1.%d' + control_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.4.1.%d' + outlet_table_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.5' + ident_str = "Tripplite" + state_on = 2 + state_off = 1 + turn_on = 2 + turn_off = 1 + has_switches = False + +class TrippliteLXPDU(object): + # WEBCARDLX-based PDU + status_oid = '.1.3.6.1.4.1.850.1.1.3.2.3.3.1.1.4.1.%d' + control_oid = '.1.3.6.1.4.1.850.1.1.3.2.3.3.1.1.6.1.%d' + outlet_table_oid = '.1.3.6.1.4.1.850.1.1.3.2.3.3.1.1.2.1' + ident_str = "Tripplite LX" + state_on = 2 + state_off = 1 + turn_on = 2 + turn_off = 1 + has_switches = False + +class ApcRPDU(object): + # Rack PDU + status_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.%d' + control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%d' + outlet_table_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.2' + ident_str = "APC rPDU" + state_on = 1 + state_off = 2 + turn_on = 1 + turn_off = 2 + has_switches = False + +class ApcMSP(object): + # Master Switch+ + status_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.5.%d.1.%d' + control_oid = '.1.3.6.1.4.1.318.1.1.6.5.1.1.5.%d.1.%d' + outlet_table_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.4' + ident_str = "APC Master Switch+" + state_on = 1 + state_off = 2 + turn_on = 1 + turn_off = 3 + has_switches = True + +class ApcMS(object): + # Master Switch - seems oldest, but supported on every APC PDU + status_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d' + control_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d' + outlet_table_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.4' + ident_str = "APC Master Switch (fallback)" + state_on = 1 + state_off = 2 + turn_on = 1 + turn_off = 2 + has_switches = False + +class ApcMS6(object): + # Master Switch with 6.x firmware + status_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d' + control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%d' + outlet_table_oid = '1.3.6.1.4.1.318.1.1.4.4.2.1.4' + ident_str = "APC Master Switch with firmware v6.x" + state_on = 1 + state_off = 2 + turn_on = 1 + turn_off = 2 + has_switches = False + +### FUNCTIONS ### +def apc_set_device(conn): + global device + + agents_dir = {'.1.3.6.1.4.1.318.1.3.4.5':ApcRPDU, + '.1.3.6.1.4.1.318.1.3.4.4':ApcMSP, + '.1.3.6.1.4.1.850.1':TripplitePDU, + '.1.3.6.1.4.1.850.1.1.1':TrippliteLXPDU, + '.1.3.6.1.4.1.318.1.3.4.6':ApcMS6, + None:ApcMS} + + # First resolve type of APC + apc_type = conn.walk(OID_SYS_OBJECT_ID) + + if not ((len(apc_type) == 1) and (apc_type[0][1] in agents_dir)): + apc_type = [[None, None]] + + device = agents_dir[apc_type[0][1]] + + logging.debug("Trying %s"%(device.ident_str)) + +def apc_resolv_port_id(conn, options): + global port_id, switch_id + + if device == None: + apc_set_device(conn) + + # Now we resolv port_id/switch_id + if (options["--plug"].isdigit()) and ((not device.has_switches) or (options["--switch"].isdigit())): + port_id = int(options["--plug"]) + + if device.has_switches: + switch_id = int(options["--switch"]) + else: + table = conn.walk(device.outlet_table_oid, 30) + + for x in table: + if x[1].strip('"') == options["--plug"]: + t = x[0].split('.') + if device.has_switches: + port_id = int(t[len(t)-1]) + switch_id = int(t[len(t)-3]) + else: + port_id = int(t[len(t)-1]) + + if port_id == None: + fail_usage("Can't find port with name %s!"%(options["--plug"])) + +def get_power_status(conn, options): + if port_id == None: + apc_resolv_port_id(conn, options) + + oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id)) + + (oid, status) = conn.get(oid) + return status == str(device.state_on) and "on" or "off" + +def set_power_status(conn, options): + if port_id == None: + apc_resolv_port_id(conn, options) + + oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id)) + + conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off)) + + +def get_outlets_status(conn, options): + result = {} + + if device == None: + apc_set_device(conn) + + res_ports = conn.walk(device.outlet_table_oid, 30) + + for x in res_ports: + t = x[0].split('.') + + port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1])) + + port_name = x[1].strip('"') + port_status = "" + result[port_num] = (port_name, port_status) + + return result + +# Main agent method +def main(): + device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ + "port", "snmp_version", "snmp"] + + atexit.register(atexit_handler) + + all_opt["snmp_version"]["default"] = "1" + all_opt["community"]["default"] = "private" + + options = check_input(device_opt, process_input(device_opt)) + + ## Support for -n [switch]:[plug] notation that was used before + if ("--plug" in options) and (-1 != options["--plug"].find(":")): + (switch, plug) = options["--plug"].split(":", 1) + if switch.isdigit() and plug.isdigit(): + options["--switch"] = switch + options["--plug"] = plug + + if "--switch" not in options: + options["--switch"] = "1" + + docs = {} + docs["shortdesc"] = "Fence agent for APC, Tripplite PDU over SNMP" + docs["longdesc"] = "fence_apc_snmp is an I/O Fencing agent \ +which can be used with the APC network power switch or Tripplite PDU devices.\ +It logs into a device via SNMP and reboots a specified outlet. It supports \ +SNMP v1, v2c, v3 with all combinations of authenticity/privacy settings." + docs["vendorurl"] = "http://www.apc.com" + docs["symlink"] = [("fence_tripplite_snmp", "Fence agent for Tripplife over SNMP")] + show_docs(options, docs) + + # Operate the fencing device + result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) +if __name__ == "__main__": + main() diff --git a/agents/apc_snmp/powernet369.mib b/agents/apc_snmp/powernet369.mib new file mode 100644 index 0000000..ab948f8 --- /dev/null +++ b/agents/apc_snmp/powernet369.mib @@ -0,0 +1,31109 @@ +-- ************************************************************************* +-- AMERICAN POWER CONVERSION PowerNet-MIB +-- ************************************************************************* +-- Copyright (c) 2005 American Power Conversion, Inc. +-- PowerNet is a Trademark of American Power Conversion Corp. +-- +-- Title: APC TOP LEVEL PowerNet MIB +-- +-- Version : 3.6.9 +-- +-- Generated by script: tomib.awk +-- +-- Input File: powernetPS.mib +-- +-- Created: Wednesday, January, 26, 2005 +-- +-- Revision History: +-- ************************************************************************* + +-- - v3.2.0 Added functionality for MasterSwitch Plus +-- - v3.3.0 Added functionality for MX28B (dcDM3) and 3-phase UPS +-- - v3.3.2 New traps for Symmetra PX UPS +-- 07/15/01 - v3.4.0 Added transfer switch +-- - v3.4.3 Added functionality for External and Integrated Environmental Monitor +-- 06/14/02 - v3.4.4 Added dcmim2(Siemens) branch, Battery Manager(Reading) traps, and +-- Psx Traps for PDU and RM-PDU and Netlock branch/traps +-- 06/18/02 - v3.5.0a Sync Control Group support +-- 08/06/02 - v3.5.0a Environmental Management System branch/traps +-- 09/16/02 - v3.5.0b Fixed some odds/ends ... going to RM-PDU for MS additions +-- 09/25/02 - v3.5.0c MS3 additions +-- 11/05/02 - v3.5.0e More Environmental Management System/A-Link devices(ARU) +-- 11/22/02 - v3.5.0g Added General APC device status OID +-- 11/27/02 - v3.5.0h Wrapped up MS3 ((Controlled or Metered) Rack PDU) changes +-- 12/26/02 - v3.5.1a Changed MS3 name again, Controlled to Switched Rack PDU +-- 01/07/03 - v3.6.0a Added OIDs/Traps for UPS Switchable Outlet Groups. +-- 01/09/03 - Adding the General APC device discovery OIDs (hidden) +-- 01/28/03 - v3.6.0c Made some small trap pair fixes for Switched Rack PDU (MS3) +-- 02/13/03 - v3.6.0d Mods from the review and some EMS fixes. +-- Added OID for the new 20kVA Symmetra 3 Phase type. +-- Added OIDs to upsAdvConfig for Symmetra type UPSs. +-- Added upsDiagnostics branch OID for Symmetra module information. +-- 04/05/03 - v3.6.2 Added OID for the new Smart-UPS 7500 and 10000 types. +-- 06/04/03 - v3.6.3 Added OIDs/Traps for AirFM. +-- 06/24/03 - v3.6.4 Moved some AirFM temps and humidities from system level to module level. +-- 10/24/03 - v3.6.4a Added OIDs/Traps for xPDU. +-- 10/27/03 - v3.6.4f Added AirPA OIDs. +-- 11/03/03 - v3.6.4g Merge of 3.6.4e and 3.6.4f +-- 11/07/03 - v3.6.4h Additional review corrections +-- 12/01/03 - v3.6.5a Added group OIDs for Air FM. Added C & F OIDs for Air PA setpoint. +-- 12/19/03 - v3.6.5b Review corrections. +-- 02/23/04 - v3.6.5c Added Modbus to experimental and multiple CB(bank) rPDU support +-- 05/05/04 - v3.6.6 Adding EMS status OID and trap for H/W issues, redefined duplicate +-- trap #228 (to ARU Device config change) and minor clean-up +-- 05/12/04 - v3.6.7a Added Air FM alarm status OIDs. +-- 06/03/04 - v3.6.7b Added UPS Config for Simple Signal Shutdowns and Number of External +-- batteries. Added Mute option to the UPS Config Audible Alarm. +-- 07/12/04 - v3.6.7d Removed Air FM alarm status OIDs due to delay in release. +-- 07/14/04 - v3.6.7d Added a detailed description to the UPSAdvConfigAlarm OID +-- 07/14/04 - v3.6.7e Added Custom Event traps +-- 08/04/04 - v3.6.7 Tag for final builds, see v3.6.7 beta build notes for changes +-- 08/26/04 - v3.6.8a Added new traps for UPS internal over temperature fault and cleared. +-- 09/01/04 - v3.6.8b Adding new thresholds for EMS probe config & status +-- 09/08/04 - v3.6.8c Corrections from MIB review. +-- 09/30/04 - v3.6.8d Added new traps for AIS ^F Message events. +-- 10/21/04 - v3.6.8e EMS. Added missing traps and new Rate functionality. +-- 10/22/04 - v3.6.8f Added resetNetworkLeaveModeAndRestart option to the mcontrolRestartAgent OID. +-- 10/28/04 - v3.6.8g Updated EMS sections from mib committee review. +-- 11/22/04 - v3.6.8 Tag for final build. +-- 12/02/04 - v3.6.9a Added OIDs and traps for BMS-HVA. +-- 12/20/04 - v3.6.9c corrections to xPDU. +-- 12/20/04 - v3.6.9c added OIDs and traps for xATS. +-- 01/03/05 - v3.6.9d removed traps for xATS. +-- 01/03/05 - v3.6.9e correction to xATS entries, that removed underscores (mib browser incompatibility) +-- 01/07/05 - v3.6.9f +-- 01/14/05 - v3.6.9g add xPDU OIDs and traps and some corrections. +-- 01/14/05 - v3.6.9g modifications to xATS OIDs and traps. + +-- ************************************************************************* +-- ************************************************************************* +-- PowerNet-MIB { iso org(3) dod(6) internet(1) private(4) +-- enterprises(1) apc(318) } + +PowerNet-MIB DEFINITIONS ::= BEGIN + +IMPORTS + enterprises, IpAddress, Gauge, TimeTicks FROM RFC1155-SMI + DisplayString FROM RFC1213-MIB + OBJECT-TYPE FROM RFC-1212 + TRAP-TYPE FROM RFC-1215; + +apc OBJECT IDENTIFIER ::= { enterprises 318 } + +products OBJECT IDENTIFIER ::= { apc 1 } +apcmgmt OBJECT IDENTIFIER ::= { apc 2 } + +hardware OBJECT IDENTIFIER ::= { products 1 } +software OBJECT IDENTIFIER ::= { products 2 } +system OBJECT IDENTIFIER ::= { products 3 } +experimental OBJECT IDENTIFIER ::= { products 4 } + +mconfig OBJECT IDENTIFIER ::= { apcmgmt 1 } +mcontrol OBJECT IDENTIFIER ::= { apcmgmt 2 } +mtrapargs OBJECT IDENTIFIER ::= { apcmgmt 3 } +mfiletransfer OBJECT IDENTIFIER ::= { apcmgmt 4 } + +mconfigClock OBJECT IDENTIFIER ::= { mconfig 6 } + +mfiletransferStatus OBJECT IDENTIFIER ::= { mfiletransfer 1 } +mfiletransferConfig OBJECT IDENTIFIER ::= { mfiletransfer 2 } +mfiletransferControl OBJECT IDENTIFIER ::= { mfiletransfer 3 } + +mfiletransferConfigSettings OBJECT IDENTIFIER ::= { mfiletransferConfig 1 } +mfiletransferConfigTFTP OBJECT IDENTIFIER ::= { mfiletransferConfig 2 } +mfiletransferConfigFTP OBJECT IDENTIFIER ::= { mfiletransferConfig 3 } + +ups OBJECT IDENTIFIER ::= { hardware 1 } +measureUps OBJECT IDENTIFIER ::= { hardware 2 } +miniSNMPadapter OBJECT IDENTIFIER ::= { hardware 3 } +masterswitch OBJECT IDENTIFIER ::= { hardware 4 } +masterswitchVM OBJECT IDENTIFIER ::= { hardware 5 } +masterswitchMSP OBJECT IDENTIFIER ::= { hardware 6 } +dcDM3 OBJECT IDENTIFIER ::= { hardware 7 } +automaticTransferSwitch OBJECT IDENTIFIER ::= { hardware 8 } +dc2 OBJECT IDENTIFIER ::= { hardware 9 } +environmentalMonitor OBJECT IDENTIFIER ::= { hardware 10 } +netlock OBJECT IDENTIFIER ::= { hardware 11 } +rPDU OBJECT IDENTIFIER ::= { hardware 12 } +airConditioners OBJECT IDENTIFIER ::= { hardware 13 } +rARU OBJECT IDENTIFIER ::= { hardware 14 } +xPDU OBJECT IDENTIFIER ::= { hardware 15 } +battMan OBJECT IDENTIFIER ::= { hardware 16 } +xATS OBJECT IDENTIFIER ::= { hardware 17 } +generator OBJECT IDENTIFIER ::= { hardware 18 } + +powerNetSubAgent OBJECT IDENTIFIER ::= { software 1 } + +powerNetSoftwareSystem OBJECT IDENTIFIER ::= { powerNetSubAgent 1 } +powerNetSoftwareConfig OBJECT IDENTIFIER ::= { powerNetSubAgent 2 } + +backUPS OBJECT IDENTIFIER ::= { system 1 } +smartUPS OBJECT IDENTIFIER ::= { system 2 } +matrixUPS OBJECT IDENTIFIER ::= { system 3 } +masterSwitch OBJECT IDENTIFIER ::= { system 4 } +symmetraUPS OBJECT IDENTIFIER ::= { system 5 } +dp100E OBJECT IDENTIFIER ::= { system 6 } +dp300E OBJECT IDENTIFIER ::= { system 7 } +monitors OBJECT IDENTIFIER ::= { system 8 } +redundantSwitch OBJECT IDENTIFIER ::= { system 9 } +dcPower OBJECT IDENTIFIER ::= { system 10 } +automaticXferSwitch OBJECT IDENTIFIER ::= { system 11 } +netLock OBJECT IDENTIFIER ::= { system 12 } +symmetra3PhaseUPS OBJECT IDENTIFIER ::= { system 13 } +networkAir OBJECT IDENTIFIER ::= { system 14 } +infraXurePDU OBJECT IDENTIFIER ::= { system 15 } +ais5000UPS OBJECT IDENTIFIER ::= { system 16 } +smartUPS3Phase OBJECT IDENTIFIER ::= { system 17 } +battManager OBJECT IDENTIFIER ::= { system 18 } +infraXureATS OBJECT IDENTIFIER ::= { system 19 } + +battManIdent OBJECT IDENTIFIER ::= { battMan 1 } +battManSystemCalib OBJECT IDENTIFIER ::= { battMan 2 } +battManUnitCalib OBJECT IDENTIFIER ::= { battMan 3 } +battManStringCalib OBJECT IDENTIFIER ::= { battMan 4 } +battManBatteryCalib OBJECT IDENTIFIER ::= { battMan 5 } +battManConfig OBJECT IDENTIFIER ::= { battMan 6 } +battManAlarm OBJECT IDENTIFIER ::= { battMan 7 } +battManSystemStatus OBJECT IDENTIFIER ::= { battMan 8 } +battManStringStatus OBJECT IDENTIFIER ::= { battMan 9 } +battManBatteryStatus OBJECT IDENTIFIER ::= { battMan 10 } +battManInputContactStatus OBJECT IDENTIFIER ::= { battMan 11 } +battManControl OBJECT IDENTIFIER ::= { battMan 12 } +battManTestResults OBJECT IDENTIFIER ::= { battMan 13 } + +xPDUIdent OBJECT IDENTIFIER ::= { xPDU 1 } +xPDUDevice OBJECT IDENTIFIER ::= { xPDU 2 } +xPDUACMonitoringPoint OBJECT IDENTIFIER ::= { xPDU 3 } +xPDUCircuitBreakers OBJECT IDENTIFIER ::= { xPDU 4 } +xPDUInputContacts OBJECT IDENTIFIER ::= { xPDU 5 } +xPDUOutputRelays OBJECT IDENTIFIER ::= { xPDU 6 } +xPDUMiscGroup OBJECT IDENTIFIER ::= { xPDU 7 } + +xPDUMainInput OBJECT IDENTIFIER ::= { xPDUACMonitoringPoint 1 } +xPDUBypassInput OBJECT IDENTIFIER ::= { xPDUACMonitoringPoint 2 } +xPDUUPSInput OBJECT IDENTIFIER ::= { xPDUACMonitoringPoint 3 } +xPDUSystemOutput OBJECT IDENTIFIER ::= { xPDUACMonitoringPoint 4 } +xPDUGroundMonitorPoint OBJECT IDENTIFIER ::= { xPDUACMonitoringPoint 5 } + +xPDUSystemBreakers OBJECT IDENTIFIER ::= { xPDUCircuitBreakers 1 } +xPDUBranchBreakers OBJECT IDENTIFIER ::= { xPDUCircuitBreakers 2 } + +xATSIdent OBJECT IDENTIFIER ::= { xATS 1 } +xATSDevice OBJECT IDENTIFIER ::= { xATS 2 } +xATSSwitch OBJECT IDENTIFIER ::= { xATS 3 } +xATSACMonitoringPoint OBJECT IDENTIFIER ::= { xATS 4 } +xATSTesting OBJECT IDENTIFIER ::= { xATS 5 } +xATSInputContacts OBJECT IDENTIFIER ::= { xATS 6 } +xATSOutputRelays OBJECT IDENTIFIER ::= { xATS 7 } +xATSMisc OBJECT IDENTIFIER ::= { xATS 8 } + +xATSSwitchStatus OBJECT IDENTIFIER ::= { xATSSwitch 1 } +xATSSwitchSettings OBJECT IDENTIFIER ::= { xATSSwitch 2 } +xATSSwitchTimers OBJECT IDENTIFIER ::= { xATSSwitch 3 } +xATSSwitchBlockMap OBJECT IDENTIFIER ::= { xATSSwitch 4 } +xATSSwitchStatistics OBJECT IDENTIFIER ::= { xATSSwitch 5 } + +xATSSource1 OBJECT IDENTIFIER ::= { xATSACMonitoringPoint 1 } +xATSSource2 OBJECT IDENTIFIER ::= { xATSACMonitoringPoint 2 } +xATSSystemOutput OBJECT IDENTIFIER ::= { xATSACMonitoringPoint 3 } + +xATSTestingStatus OBJECT IDENTIFIER ::= { xATSTesting 1 } +xATSTestingResults OBJECT IDENTIFIER ::= { xATSTesting 2 } +xATSTestingSchedule OBJECT IDENTIFIER ::= { xATSTesting 3 } +xATSTestingSimulatePowerFail OBJECT IDENTIFIER ::= { xATSTesting 4 } + +xATSGenerator OBJECT IDENTIFIER ::= { generator 1 } + +xATSGeneratorIdent OBJECT IDENTIFIER ::= { xATSGenerator 1 } +xATSGeneratorStatus OBJECT IDENTIFIER ::= { xATSGenerator 2 } +xATSGeneratorAdvStatus OBJECT IDENTIFIER ::= { xATSGenerator 3 } +xATSGeneratorOutput OBJECT IDENTIFIER ::= { xATSGenerator 4 } +xATSGeneratorSettings OBJECT IDENTIFIER ::= { xATSGenerator 5 } +xATSGeneratorService OBJECT IDENTIFIER ::= { xATSGenerator 6 } +xATSGeneratorFuelSystem OBJECT IDENTIFIER ::= { xATSGenerator 7 } + + +smartUPS250 OBJECT IDENTIFIER ::= { smartUPS 1 } +smartUPS400 OBJECT IDENTIFIER ::= { smartUPS 2 } +smartUPS600 OBJECT IDENTIFIER ::= { smartUPS 3 } +smartUPS900 OBJECT IDENTIFIER ::= { smartUPS 4 } +smartUPS1250 OBJECT IDENTIFIER ::= { smartUPS 5 } +smartUPS2000 OBJECT IDENTIFIER ::= { smartUPS 6 } + +smartUPS450 OBJECT IDENTIFIER ::= { smartUPS 7 } +smartUPS700 OBJECT IDENTIFIER ::= { smartUPS 8 } +smartUPS1000 OBJECT IDENTIFIER ::= { smartUPS 9 } +smartUPS1400 OBJECT IDENTIFIER ::= { smartUPS 10 } +smartUPS2200 OBJECT IDENTIFIER ::= { smartUPS 11 } +smartUPS3000 OBJECT IDENTIFIER ::= { smartUPS 12 } +smartUPS5000 OBJECT IDENTIFIER ::= { smartUPS 13 } +smartUPS7500 OBJECT IDENTIFIER ::= { smartUPS 14 } +smartUPS10000 OBJECT IDENTIFIER ::= { smartUPS 15 } +smartUPS1500 OBJECT IDENTIFIER ::= { smartUPS 16 } + +matrixUPS3000 OBJECT IDENTIFIER ::= { matrixUPS 1 } +matrixUPS5000 OBJECT IDENTIFIER ::= { matrixUPS 2 } + +masterSwitchV1 OBJECT IDENTIFIER ::= { masterSwitch 1} +masterSwitchV2 OBJECT IDENTIFIER ::= { masterSwitch 2} +masterSwitchVM OBJECT IDENTIFIER ::= { masterSwitch 3} +masterSwitchMSP OBJECT IDENTIFIER ::= { masterSwitch 4} +masterSwitchrPDU OBJECT IDENTIFIER ::= { masterSwitch 5} + +symmetraUPS4kVA OBJECT IDENTIFIER ::= { symmetraUPS 1 } +symmetraUPS8kVA OBJECT IDENTIFIER ::= { symmetraUPS 2 } +symmetraUPS12kVA OBJECT IDENTIFIER ::= { symmetraUPS 3 } +symmetraUPS16kVA OBJECT IDENTIFIER ::= { symmetraUPS 4 } + +environmental OBJECT IDENTIFIER ::= { monitors 1 } +environmentalMgtSystem OBJECT IDENTIFIER ::= { monitors 2 } +emu2 OBJECT IDENTIFIER ::= { monitors 3 } + +dm3 OBJECT IDENTIFIER ::= { dcPower 1 } +dcmim2 OBJECT IDENTIFIER ::= { dcPower 2 } + +symmetra3PhaseUPS40kVA OBJECT IDENTIFIER ::= { symmetra3PhaseUPS 1 } +symmetra3PhaseUPS60kVA OBJECT IDENTIFIER ::= { symmetra3PhaseUPS 2 } +symmetra3PhaseUPS80kVA OBJECT IDENTIFIER ::= { symmetra3PhaseUPS 3 } +symmetra3PhaseUPS20kVA OBJECT IDENTIFIER ::= { symmetra3PhaseUPS 4 } + +airFMSeries OBJECT IDENTIFIER ::= { networkAir 1 } +rackAirRemovalUnit OBJECT IDENTIFIER ::= { networkAir 2 } +airPASeries OBJECT IDENTIFIER ::= { networkAir 3 } + +ais5000UPS10kVA OBJECT IDENTIFIER ::= { ais5000UPS 1 } +ais5000UPS20kVA OBJECT IDENTIFIER ::= { ais5000UPS 2 } +ais5000UPS30kVA OBJECT IDENTIFIER ::= { ais5000UPS 3 } +ais5000UPS40kVA OBJECT IDENTIFIER ::= { ais5000UPS 4 } +ais5000UPS60kVA OBJECT IDENTIFIER ::= { ais5000UPS 5 } +ais5000UPS80kVA OBJECT IDENTIFIER ::= { ais5000UPS 6 } +ais5000UPS100kVA OBJECT IDENTIFIER ::= { ais5000UPS 7 } + +smartUPS3Phase10kVA OBJECT IDENTIFIER ::= { smartUPS3Phase 1 } +smartUPS3Phase15kVA OBJECT IDENTIFIER ::= { smartUPS3Phase 2 } +smartUPS3Phase20kVA OBJECT IDENTIFIER ::= { smartUPS3Phase 3 } +smartUPS3Phase30kVA OBJECT IDENTIFIER ::= { smartUPS3Phase 4 } +smartUPS3Phase40kVA OBJECT IDENTIFIER ::= { smartUPS3Phase 5 } + +upsIdent OBJECT IDENTIFIER ::= { ups 1 } +upsBattery OBJECT IDENTIFIER ::= { ups 2 } +upsInput OBJECT IDENTIFIER ::= { ups 3 } +upsOutput OBJECT IDENTIFIER ::= { ups 4 } +upsConfig OBJECT IDENTIFIER ::= { ups 5 } +upsControl OBJECT IDENTIFIER ::= { ups 6 } +upsTest OBJECT IDENTIFIER ::= { ups 7 } +upsComm OBJECT IDENTIFIER ::= { ups 8 } +upsPhase OBJECT IDENTIFIER ::= { ups 9 } +upsSyncCtrlGroup OBJECT IDENTIFIER ::= { ups 10 } +upsState OBJECT IDENTIFIER ::= { ups 11 } +upsOutletGroups OBJECT IDENTIFIER ::= { ups 12 } +upsDiagnostics OBJECT IDENTIFIER ::= { ups 13 } + +upsBasicIdent OBJECT IDENTIFIER ::= { upsIdent 1 } +upsAdvIdent OBJECT IDENTIFIER ::= { upsIdent 2 } + +upsBasicBattery OBJECT IDENTIFIER ::= { upsBattery 1 } +upsAdvBattery OBJECT IDENTIFIER ::= { upsBattery 2 } + +upsBasicInput OBJECT IDENTIFIER ::= { upsInput 1 } +upsAdvInput OBJECT IDENTIFIER ::= { upsInput 2 } + +upsBasicOutput OBJECT IDENTIFIER ::= { upsOutput 1 } +upsAdvOutput OBJECT IDENTIFIER ::= { upsOutput 2 } + +upsBasicConfig OBJECT IDENTIFIER ::= { upsConfig 1 } +upsAdvConfig OBJECT IDENTIFIER ::= { upsConfig 2 } + +upsBasicControl OBJECT IDENTIFIER ::= { upsControl 1 } +upsAdvControl OBJECT IDENTIFIER ::= { upsControl 2 } + +upsBasicTest OBJECT IDENTIFIER ::= { upsTest 1 } +upsAdvTest OBJECT IDENTIFIER ::= { upsTest 2 } + +upsPhaseResetValues OBJECT IDENTIFIER ::= { upsPhase 1 } +upsPhaseInput OBJECT IDENTIFIER ::= { upsPhase 2 } +upsPhaseOutput OBJECT IDENTIFIER ::= { upsPhase 3 } + +upsSyncCtrlGroupConfig OBJECT IDENTIFIER ::= { upsSyncCtrlGroup 1 } +upsSyncCtrlGroupStatus OBJECT IDENTIFIER ::= { upsSyncCtrlGroup 2 } + +upsBasicState OBJECT IDENTIFIER ::= { upsState 1 } +upsAdvState OBJECT IDENTIFIER ::= { upsState 2 } + +upsOutletGroupStatus OBJECT IDENTIFIER ::= { upsOutletGroups 1 } +upsOutletGroupConfig OBJECT IDENTIFIER ::= { upsOutletGroups 2 } +upsOutletGroupControl OBJECT IDENTIFIER ::= { upsOutletGroups 3 } + +upsDiagnosticIM OBJECT IDENTIFIER ::= { upsDiagnostics 1 } +upsDiagnosticPowerModules OBJECT IDENTIFIER ::= { upsDiagnostics 2 } +upsDiagnosticBatteries OBJECT IDENTIFIER ::= { upsDiagnostics 3 } +upsDiagnosticSubsystem OBJECT IDENTIFIER ::= { upsDiagnostics 4 } +upsDiagnosticExternalDevices OBJECT IDENTIFIER ::= { upsDiagnostics 5 } +upsDiagnosticComBus OBJECT IDENTIFIER ::= { upsDiagnostics 6 } + +upsDiagSwitchGear OBJECT IDENTIFIER ::= { upsDiagnosticExternalDevices 1 } +upsDiagMCCBBox OBJECT IDENTIFIER ::= { upsDiagnosticExternalDevices 2 } +upsDiagTransformer OBJECT IDENTIFIER ::= { upsDiagnosticExternalDevices 3 } + +mUpsEnviron OBJECT IDENTIFIER ::= { measureUps 1 } +mUpsContact OBJECT IDENTIFIER ::= { measureUps 2 } + +serialPort OBJECT IDENTIFIER ::= { miniSNMPadapter 1} + +serialPort1 OBJECT IDENTIFIER ::= { serialPort 1} +serialPort2 OBJECT IDENTIFIER ::= { serialPort 2} + +serialPort2Config OBJECT IDENTIFIER ::= { serialPort2 1} +serialPort2Control OBJECT IDENTIFIER ::= { serialPort2 2} + +sPDUIdent OBJECT IDENTIFIER ::= { masterswitch 1 } +sPDUMasterControl OBJECT IDENTIFIER ::= { masterswitch 2 } +sPDUMasterConfig OBJECT IDENTIFIER ::= { masterswitch 3 } +sPDUOutletControl OBJECT IDENTIFIER ::= { masterswitch 4 } +sPDUOutletConfig OBJECT IDENTIFIER ::= { masterswitch 5 } + +sPDUIdentVM OBJECT IDENTIFIER ::= { masterswitchVM 1 } +sPDUMasterControlVM OBJECT IDENTIFIER ::= { masterswitchVM 2 } +sPDUMasterConfigVM OBJECT IDENTIFIER ::= { masterswitchVM 3 } +sPDUMasterStatusVM OBJECT IDENTIFIER ::= { masterswitchVM 4 } +sPDUOutletControlVM OBJECT IDENTIFIER ::= { masterswitchVM 5 } +sPDUOutletConfigVM OBJECT IDENTIFIER ::= { masterswitchVM 6 } +sPDUOutletStatusVM OBJECT IDENTIFIER ::= { masterswitchVM 7 } + +sPDUIdentMSP OBJECT IDENTIFIER ::= { masterswitchMSP 1 } +sPDUMasterControlMSP OBJECT IDENTIFIER ::= { masterswitchMSP 2 } +sPDUMasterConfigMSP OBJECT IDENTIFIER ::= { masterswitchMSP 3 } +sPDUMasterStatusMSP OBJECT IDENTIFIER ::= { masterswitchMSP 4 } +sPDUOutletControlMSP OBJECT IDENTIFIER ::= { masterswitchMSP 5 } +sPDUOutletConfigMSP OBJECT IDENTIFIER ::= { masterswitchMSP 6 } +sPDUOutletStatusMSP OBJECT IDENTIFIER ::= { masterswitchMSP 7 } + +sPDUOutletConfigMSPall OBJECT IDENTIFIER ::= { sPDUOutletConfigMSP 1 } +sPDUOutletConfigMSPgs OBJECT IDENTIFIER ::= { sPDUOutletConfigMSP 2 } +sPDUOutletConfigMSPannun OBJECT IDENTIFIER ::= { sPDUOutletConfigMSP 3 } +sPDUOutletConfigMSPmups OBJECT IDENTIFIER ::= { sPDUOutletConfigMSP 4 } + +rPDUIdent OBJECT IDENTIFIER ::= { rPDU 1 } +rPDULoad OBJECT IDENTIFIER ::= { rPDU 2 } +rPDUOutlet OBJECT IDENTIFIER ::= { rPDU 3 } +rPDUPowerSupply OBJECT IDENTIFIER ::= { rPDU 4 } + +rPDULoadDevice OBJECT IDENTIFIER ::= { rPDULoad 1 } +rPDULoadPhaseConfig OBJECT IDENTIFIER ::= { rPDULoad 2 } +rPDULoadStatus OBJECT IDENTIFIER ::= { rPDULoad 3 } +rPDULoadBankConfig OBJECT IDENTIFIER ::= { rPDULoad 4 } + +rPDUOutletDevice OBJECT IDENTIFIER ::= { rPDUOutlet 1 } +rPDUOutletPhase OBJECT IDENTIFIER ::= { rPDUOutlet 2 } +rPDUOutletControl OBJECT IDENTIFIER ::= { rPDUOutlet 3 } +rPDUOutletConfig OBJECT IDENTIFIER ::= { rPDUOutlet 4 } +rPDUOutletStatus OBJECT IDENTIFIER ::= { rPDUOutlet 5 } +rPDUOutletBank OBJECT IDENTIFIER ::= { rPDUOutlet 6 } + +rPDUPowerSupplyDevice OBJECT IDENTIFIER ::= { rPDUPowerSupply 1 } + +dm3Ident OBJECT IDENTIFIER ::= { dcDM3 1 } +dm3Config OBJECT IDENTIFIER ::= { dcDM3 2 } +dm3Status OBJECT IDENTIFIER ::= { dcDM3 3 } + +dm3IdentSystem OBJECT IDENTIFIER ::= { dm3Ident 1} + +dm3ConfigSystem OBJECT IDENTIFIER ::= { dm3Config 1 } +dm3ConfigLVD OBJECT IDENTIFIER ::= { dm3Config 2 } +dm3ConfigBattery OBJECT IDENTIFIER ::= { dm3Config 3 } +dm3ConfigPowerModules OBJECT IDENTIFIER ::= { dm3Config 4 } +dm3ConfigRelays OBJECT IDENTIFIER ::= { dm3Config 5 } +dm3ConfigDistribution OBJECT IDENTIFIER ::= { dm3Config 6 } + +dm3ConfigRectifier OBJECT IDENTIFIER ::= { dm3ConfigPowerModules 1 } +dm3ConfigConverter OBJECT IDENTIFIER ::= { dm3ConfigPowerModules 2 } + +dm3ConfigRectThresh OBJECT IDENTIFIER ::= { dm3ConfigRectifier 1 } +dm3ConfigRectAlarms OBJECT IDENTIFIER ::= { dm3ConfigRectifier 2 } + +dm3ConfigConvThresh OBJECT IDENTIFIER ::= { dm3ConfigConverter 1 } +dm3ConfigConvAlarms OBJECT IDENTIFIER ::= { dm3ConfigConverter 2 } + +dm3ConfigOutputRelays OBJECT IDENTIFIER ::= { dm3ConfigRelays 1 } +dm3ConfigInputRelays OBJECT IDENTIFIER ::= { dm3ConfigRelays 2 } + +dm3ConfigBreakers OBJECT IDENTIFIER ::= { dm3ConfigDistribution 1 } +dm3ConfigFuses OBJECT IDENTIFIER ::= { dm3ConfigDistribution 2 } + +dm3StatusSystem OBJECT IDENTIFIER ::= { dm3Status 1 } +dm3StatusAlarms OBJECT IDENTIFIER ::= { dm3Status 2 } +dm3StatusBattery OBJECT IDENTIFIER ::= { dm3Status 3 } +dm3StatusOEM OBJECT IDENTIFIER ::= { dm3Status 4 } +dm3StatusLVD OBJECT IDENTIFIER ::= { dm3Status 5 } +dm3StatusPowerModules OBJECT IDENTIFIER ::= { dm3Status 6 } +dm3StatusRelays OBJECT IDENTIFIER ::= { dm3Status 7 } +dm3StatusDistribution OBJECT IDENTIFIER ::= { dm3Status 8 } + +dm3StatusRectifier OBJECT IDENTIFIER ::= { dm3StatusPowerModules 1 } +dm3StatusConverter OBJECT IDENTIFIER ::= { dm3StatusPowerModules 2 } + +dm3StatusOutputRelays OBJECT IDENTIFIER ::= { dm3StatusRelays 1 } +dm3StatusInputRelays OBJECT IDENTIFIER ::= { dm3StatusRelays 2 } + +dm3StatusBreakers OBJECT IDENTIFIER ::= { dm3StatusDistribution 1 } +dm3StatusFuses OBJECT IDENTIFIER ::= { dm3StatusDistribution 2 } + +atsIdent OBJECT IDENTIFIER ::= { automaticTransferSwitch 1 } +atsCalibration OBJECT IDENTIFIER ::= { automaticTransferSwitch 2 } +atsControl OBJECT IDENTIFIER ::= { automaticTransferSwitch 3 } +atsConfig OBJECT IDENTIFIER ::= { automaticTransferSwitch 4 } +atsStatus OBJECT IDENTIFIER ::= { automaticTransferSwitch 5 } + +atsCalibrationInput OBJECT IDENTIFIER ::= { atsCalibration 1 } +atsCalibrationPowerSupply OBJECT IDENTIFIER ::= { atsCalibration 2 } +atsCalibrationOutput OBJECT IDENTIFIER ::= { atsCalibration 3 } + +atsStatusDeviceStatus OBJECT IDENTIFIER ::= { atsStatus 1 } +atsStatusResetValues OBJECT IDENTIFIER ::= { atsStatus 2 } +atsStatusInput OBJECT IDENTIFIER ::= { atsStatus 3 } +atsStatusOutput OBJECT IDENTIFIER ::= { atsStatus 4 } + +dcmim2Ident OBJECT IDENTIFIER ::= { dc2 1 } +dcmim2Control OBJECT IDENTIFIER ::= { dc2 2 } +dcmim2Config OBJECT IDENTIFIER ::= { dc2 3 } +dcmim2Status OBJECT IDENTIFIER ::= { dc2 4 } + +dcmim2IdentSystem OBJECT IDENTIFIER ::= { dcmim2Ident 1 } + +dcmim2ControlSystem OBJECT IDENTIFIER ::= { dcmim2Control 1 } + +dcmim2ConfigSystem OBJECT IDENTIFIER ::= { dcmim2Config 1 } +dcmim2ConfigBattery OBJECT IDENTIFIER ::= { dcmim2Config 2 } +dcmim2ConfigLVD OBJECT IDENTIFIER ::= { dcmim2Config 3 } + +dcmim2StatusSystem OBJECT IDENTIFIER ::= { dcmim2Status 1 } +dcmim2StatusRectifier OBJECT IDENTIFIER ::= { dcmim2Status 2 } +dcmim2StatusBattery OBJECT IDENTIFIER ::= { dcmim2Status 3 } +dcmim2StatusLVD OBJECT IDENTIFIER ::= { dcmim2Status 4 } +dcmim2StatusAlarms OBJECT IDENTIFIER ::= { dcmim2Status 5 } + +external OBJECT IDENTIFIER ::= { environmentalMonitor 1 } +integrated OBJECT IDENTIFIER ::= { environmentalMonitor 2 } +envMgtSystem OBJECT IDENTIFIER ::= { environmentalMonitor 3 } + +emIdent OBJECT IDENTIFIER ::= { external 1 } +emConfig OBJECT IDENTIFIER ::= { external 2 } +emStatus OBJECT IDENTIFIER ::= { external 3 } + +iemIdent OBJECT IDENTIFIER ::= { integrated 1 } +iemConfig OBJECT IDENTIFIER ::= { integrated 2 } +iemStatus OBJECT IDENTIFIER ::= { integrated 3 } + +emsIdent OBJECT IDENTIFIER ::= { envMgtSystem 1 } + +emsOutputRelayControl OBJECT IDENTIFIER ::= { envMgtSystem 2 } +emsOutletControl OBJECT IDENTIFIER ::= { envMgtSystem 3 } +emsSensorControl OBJECT IDENTIFIER ::= { envMgtSystem 4 } +emsAlarmDeviceControl OBJECT IDENTIFIER ::= { envMgtSystem 5 } + +emsConfig OBJECT IDENTIFIER ::= { envMgtSystem 6 } +emsProbeConfig OBJECT IDENTIFIER ::= { envMgtSystem 7 } +emsInputContactConfig OBJECT IDENTIFIER ::= { envMgtSystem 8 } +emsOutputRelayConfig OBJECT IDENTIFIER ::= { envMgtSystem 9 } +emsOutletConfig OBJECT IDENTIFIER ::= { envMgtSystem 10 } +emsSensorConfig OBJECT IDENTIFIER ::= { envMgtSystem 11 } + +emsStatus OBJECT IDENTIFIER ::= { envMgtSystem 12 } +emsProbeStatus OBJECT IDENTIFIER ::= { envMgtSystem 13 } +emsInputContactStatus OBJECT IDENTIFIER ::= { envMgtSystem 14 } +emsOutputRelayStatus OBJECT IDENTIFIER ::= { envMgtSystem 15 } +emsOutletStatus OBJECT IDENTIFIER ::= { envMgtSystem 16 } +emsAlarmDeviceStatus OBJECT IDENTIFIER ::= { envMgtSystem 17 } +emsSensorStatus OBJECT IDENTIFIER ::= { envMgtSystem 18 } + +nlIdent OBJECT IDENTIFIER ::= { netlock 1 } +nlStatus OBJECT IDENTIFIER ::= { netlock 2 } + +airFM OBJECT IDENTIFIER ::= { airConditioners 1 } +airFMIdent OBJECT IDENTIFIER ::= { airFM 1 } +airFMStatus OBJECT IDENTIFIER ::= { airFM 2 } +airFMGroup OBJECT IDENTIFIER ::= { airFM 3 } + +airPA OBJECT IDENTIFIER ::= { airConditioners 2 } +airPAIdent OBJECT IDENTIFIER ::= { airPA 1 } +airPAStatus OBJECT IDENTIFIER ::= { airPA 2 } + +rARUIdent OBJECT IDENTIFIER ::= { rARU 1 } +rARUConfig OBJECT IDENTIFIER ::= { rARU 2 } +rARUStatus OBJECT IDENTIFIER ::= { rARU 3 } + + +-- object types + +-- the products group +-- the experimental group + + + +-- the apcmgmt group +-- the mconfig group + +mconfigNumTrapReceivers OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of managers to send traps to." + ::= { mconfig 1 } + +mconfigTrapReceiverTable OBJECT-TYPE + SYNTAX SEQUENCE OF MconfigTrapReceiverEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of managers to send traps to. The number of + entries is given by the value of mconfigNumTrapReceivers. + Maximum number of Trap Receivers is four." + ::= { mconfig 2 } + +mconfigTrapReceiverEntry OBJECT-TYPE + SYNTAX MconfigTrapReceiverEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The managers to send traps to." + INDEX { trapIndex} + ::= { mconfigTrapReceiverTable 1 } + +MconfigTrapReceiverEntry ::= + SEQUENCE { + trapIndex + INTEGER, + receiverAddr + IpAddress, + communityString + DisplayString, + severity + INTEGER, + acceptThisReceiver + INTEGER, + receiveTrapType + INTEGER + } + +trapIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to a trap receiver entry." + ::= { mconfigTrapReceiverEntry 1 } + +receiverAddr OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The IP address of the manager to send a trap to." + ::= { mconfigTrapReceiverEntry 2 } + +communityString OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The community name to use in the trap when + sent to the manager." + ::= { mconfigTrapReceiverEntry 3 } + +severity OBJECT-TYPE + SYNTAX INTEGER { + information(1), + warning(2), + severe(3) + } + ACCESS read-only + STATUS obsolete + DESCRIPTION + "The severity threshold of traps to send to the manager. + traps are labeled in severity as informational(1), warning(2), + severe(3). Only traps of equal or greater severity than + this value are sent to the manager." + ::= { mconfigTrapReceiverEntry 4 } + +acceptThisReceiver OBJECT-TYPE + SYNTAX INTEGER { + yes (1), + no (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An entry will become active if yes, and will + be deleted if no." + ::= { mconfigTrapReceiverEntry 5 } + + +receiveTrapType OBJECT-TYPE + SYNTAX INTEGER { + powernet (1), + ietf (2), + both (3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The node in this entry will receive traps defined in APC + PowerNet MIB, if this OID is set to yes." + ::= { mconfigTrapReceiverEntry 6 } + +mconfigBOOTPEnabled OBJECT-TYPE + SYNTAX INTEGER { + yes (1), + no (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The value of yes(1) indicates the PowerNet Adapter is configured to + obtain its IP configuration parameters from a BOOTP server. + + The value of no(2) indicates adapter will assume IP configuration parameters + values saved in adapter's eeprom, which was originally configured at local + console." + ::= { mconfig 3 } + +mconfigTFTPServerIP OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The IP address of TFTP server. If mconfigBOOTPEnabled is yes(1), then this IP address + is provided by BOOTP server and not allowed to be modified; otherwise, this IP address + can be modified. + + Before using TFTP to load new code image, the image file should be placed in proper + directory of the specified TFTP server. This OID is only supported by AP9605, AP9205, + and AP9603 PowerNet SNMP Adapters." + ::= { mconfig 4 } + +newCodeAuthentViaTFTP OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + validNewAgentCodeImage (2), + sameAgentCodeImage (3), + invalidAgentCodeImage (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Once mcontrolRestartAgent is set to loadAndExecuteNewAgent (3), PowerNet adapter will + start to load the remote image file, for authentication only, instead of saving the code + into flash memory. Only if a validNewAgentCodeImage (1) is found will the agent reboot + the PowerNet adapter and invoke the loader to load and save new code into the flash memory. + Otherwise, the current agent code will continue to run. + + This OID shows the result of the above authentication process. + validNewAgentCodeImage (1) means the code image on TFTP server + is a valid APC agent code and is different version from the current agent. + Once agent identifies this, loader will start to update flash memory with + the new agent code. + + sameAgentCodeImage (2) means the code image on TFTP server is exactly the + same as the currently running agent. Currently running agent will not invoke + loader to load the same again. + + invalidAgentCodeImage (3) means the code image on TFTP server is NOT a valid + APC agent code. Thus, current agent will not load it into the flash memory. + + The value of this OID will be associated with TRAP codeImageAuthentDone. + This OID is only supported by AP9605, AP9205, and AP9603 PowerNet SNMP Adapters." + + ::= { mconfig 5 } + +mconfigClockDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The current date in the mm/dd/yyyy format. Example: 01/01/2000." + ::= { mconfigClock 1 } + +mconfigClockTime OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The current time in the hh:mm:ss am/pm format. Example: 12:00:00 am." + ::= { mconfigClock 2 } + +mcontrolRestartAgent OBJECT-TYPE + SYNTAX INTEGER { + restartCurrentAgent (1), + continueCurrentAgent (2), + loadAndExecuteNewAgent (3), + restartWithoutAgent (4), + resetNetworkAndRestart (5), + resetNetworkLeaveModeAndRestart (6) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to restartCurrentAgent (1) will restart the same SNMP + agent code currently saved in flash memory. Setting this OID to + loadAndExecuteNewAgent (3) will enable adapter to load a new agent code + into the flash memory and start to execute this new agent code. + Bootp/tftp is the default protocol. loadAndExecuteNewAgent is only + supported by AP9605, AP9205, and AP9603 PowerNet SNMP Adapters. Setting + this OID to restartWithoutAgent (4) will restart the system and not + start the agent. The subsequent time the system restarts the agent will + also automatically restart. Setting this OID to + resetNetworkAndRestart (5) will set the Boot Mode, IP Address, Subnet + Mask, and Default Gateway to defaults, expire any existing DHCP lease + and then restart the system. Setting this OID to + resetNetworkLeaveModeAndRestart (6) will leave the Boot Mode at the + current setting, set the IP Address, Subnet Mask, and Default Gateway to + defaults, expire any existing DHCP lease and then restart the system." + + ::= { mcontrol 1 } + +-- The mtrapargs group +-- These OIDs allows APC traps to be sent with additional arguments +-- which may not be defined in the APC MIB. + +mtrapargsInteger OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with an integer argument + that my not be defined in the APC MIB. + + A get of this OID will return 0." + ::= { mtrapargs 1 } + +mtrapargsIpAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with an IP address argument + that my not be defined in the APC MIB. + + A get of this OID will return 0.0.0.0." + ::= { mtrapargs 2 } + +mtrapargsString OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with an octet string argument + that my not be defined in the APC MIB. + + A get of this OID will return a NULL string." + ::= { mtrapargs 3 } + +mtrapargsGauge OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with a Gauge argument + that my not be defined in the APC MIB. + + A get of this OID will return 0." + ::= { mtrapargs 4 } + +mtrapargsTimeTicks OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with a TimeTicks argument + that my not be defined in the APC MIB. + + A get of this OID will return 0." + ::= { mtrapargs 5 } + +mtrapargsInteger02 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with an integer argument + that my not be defined in the APC MIB. + + A get of this OID will return 0." + ::= { mtrapargs 6 } + +mtrapargsInteger03 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with an integer argument + that my not be defined in the APC MIB. + + A get of this OID will return 0." + ::= { mtrapargs 7 } + +mtrapargsIpAddress02 OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with an IP address argument + that my not be defined in the APC MIB. + + A get of this OID will return 0.0.0.0." + ::= { mtrapargs 8 } + +mtrapargsIpAddress03 OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with an IP address argument + that my not be defined in the APC MIB. + + A get of this OID will return 0.0.0.0." + ::= { mtrapargs 9 } + +mtrapargsString02 OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with an octet string argument + that my not be defined in the APC MIB. + + A get of this OID will return a NULL string." + ::= { mtrapargs 10 } + +mtrapargsString03 OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with an octet string argument + that my not be defined in the APC MIB. + + A get of this OID will return a NULL string." + ::= { mtrapargs 11 } + +mtrapargsGauge02 OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with a Gauge argument + that my not be defined in the APC MIB. + + A get of this OID will return 0." + ::= { mtrapargs 12 } + +mtrapargsGauge03 OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with a Gauge argument + that my not be defined in the APC MIB. + + A get of this OID will return 0." + ::= { mtrapargs 13 } + +mtrapargsTimeTicks02 OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with a TimeTicks argument + that my not be defined in the APC MIB. + + A get of this OID will return 0." + ::= { mtrapargs 14 } + +mtrapargsTimeTicks03 OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID allows APC traps to be sent with a TimeTicks argument + that my not be defined in the APC MIB. + + A get of this OID will return 0." + ::= { mtrapargs 15 } + +-- the mfiletransfer group +-- the mfiletransferStatus group +mfiletransferStatusLastTransferResult OBJECT-TYPE + SYNTAX INTEGER { + lastFileTransferResultSuccessful (1), + lastFileTransferResultNotAvailable (2), + lastFileTransferResultFailureUnknown (3), + lastFileTransferResultFailureServerInaccessible (4), + lastFileTransferResultFailureServerAccessDenied (5), + lastFileTransferResultFailureFileNotFound (6), + lastFileTransferResultFailureFileTypeUnknown (7), + lastFileTransferResultFailureFileCorrupted (8) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Once mfiletransferControlInitiateFileTransfer is set to a value other than doNotInitiateFileTransfer + a file transfer of mfiletransferConfigSettingsFilename will be attempted from either a TFTP or FTP + server. + + This OID shows the last attempted file transfer result. + lastFileTransferResultSuccessful (1) means the file transfer was successful. + lastFileTransferResultNotAvailable (2) means that there have been no previous file transfers. + lastFileTransferResultFailureUnknown (3) means that the last file transfer failed for an unknown reason. + lastFileTransferResultFailureServerInaccessible (4) means that the TFTP or FTP server could not be found on the network. + lastFileTransferResultFailureServerAccessDenied (5) means that the TFTP or FTP server denied access. + lastFileTransferResultFailureFileNotFound (6) means that the file could not be located. + lastFileTransferResultFailureFileTypeUnknown (7) means the file was examined, but the contents were unknown. + lastFileTransferResultFailureFileCorrupt (8) means the transferred file was corrupt." + + ::= { mfiletransferStatus 1 } + +-- the mfiletransferConfig group +-- the mfiletransferConfigSettings group + +mfiletransferConfigSettingsFilename OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The path and name of the file to transfer using the mfiletransferControlInitiateFileTransfer OID. + If the file to transfer exists in the default server directory then the path may be omitted." + + ::= { mfiletransferConfigSettings 1 } + +-- the mfiletransferConfigTFTP group + +mfiletransferConfigTFTPServerAddress OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The IP Address in dotted decimal notation of the TFTP server involved in the file transfer." + + ::= { mfiletransferConfigTFTP 1 } + +-- the mfiletransferConfigFTP group + +mfiletransferConfigFTPServerAddress OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The IP Address in dotted decimal notation of the FTP server involved in the file transfer." + + ::= { mfiletransferConfigFTP 1 } + +mfiletransferConfigFTPServerUser OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The user identification for logging into the FTP server specified with mfiletransferConfigFTPServerAddress." + + ::= { mfiletransferConfigFTP 2 } + +mfiletransferConfigFTPServerPassword OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The password for logging into the FTP server specified with mfiletransferConfigFTPServerAddress." + + ::= { mfiletransferConfigFTP 3 } + +-- the mfiletransferControl group + +mfiletransferControlInitiateFileTransfer OBJECT-TYPE + SYNTAX INTEGER { + doNotInitiateFileTransfer (1), + initiateFileTransferDownloadViaTFTP (2), + initiateFileTransferDownloadViaFTP (3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to doNotInitiateFileTransfer (1) will do nothing. + + Setting this OID to initiateFileTransferDownloadViaTFTP (2) will attempt to transfer the file named in + mfiletransferConfigSettingsFilename from the TFTP Server identified in mfiletransferConfigTFTPAddress. + + Setting this OID to initiateFileTransferDownloadViaFTP (3) will attempt to transfer the file named in + mfiletransferConfigSettingsFilename from the FTP Server identified in mfiletransferConfigFTPAddress + using mfiletransferConfigFTPUser and mfiletransferConfigFTPPassword for the FTP Server login process." + + ::= { mfiletransferControl 1 } + +-- the battManIdent group + +battManIdentProductName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the battery manager." + ::= { battManIdent 1 } + +battManIdentHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery manager network interface hardware revision. + This value is set at the factory." + ::= { battManIdent 2 } + +battManIdentFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery manager network interface firmware revision. + This value is set at the factory and can change with firmware update." + ::= { battManIdent 3 } + +battManIdentDateOfManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date the battery manager was manufactured in mm/dd/yyyy format. + This value is set at the factory." + ::= { battManIdent 4 } + +battManIdentModelNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery manager model number character string. + This value is set at the factory." + ::= { battManIdent 5 } + +battManIdentSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery manager serial number character string. + This value is set at the factory." + ::= { battManIdent 6 } + +-- the battManCalib group +-- system calibration + +battManOhmicValueCorrectionFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The system ohmic value correction factor in percent." + ::= { battManSystemCalib 1 } + +-- unit calibration + +battManUnitCalibTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManUnitCalibTable." + ::= { battManUnitCalib 1 } + +battManUnitCalibTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManUnitCalibTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting calibration information from each unit in the system." + ::= { battManUnitCalib 2 } + +battManUnitCalibTableEntry OBJECT-TYPE + SYNTAX BattManUnitCalibTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The unit to get data from." + INDEX { battManUnitCalibIndex } + ::= { battManUnitCalibTable 1 } + +BattManUnitCalibTableEntry ::= + SEQUENCE { + battManUnitCalibIndex INTEGER, + battManUnitSerialNumber DisplayString, + battManBatteryVoltageZeroCalib INTEGER, + battManBatteryVoltageSpanCalib INTEGER + } + +battManUnitCalibIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of unit calibration entries in the table." + ::= { battManUnitCalibTableEntry 1 } + +battManUnitSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The serial number of the unit." + ::= { battManUnitCalibTableEntry 2 } + +battManBatteryVoltageZeroCalib OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The unit battery voltage zero calibration in millivolts." + ::= { battManUnitCalibTableEntry 3 } + +battManBatteryVoltageSpanCalib OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The unit battery voltage span calibration in percent." + ::= { battManUnitCalibTableEntry 4 } + +-- string calibration table + +battManStringCalibTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManStringCalibTable." + ::= { battManStringCalib 1 } + +battManStringCalibTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManStringCalibTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting calibration information from each string in the system." + ::= { battManStringCalib 2 } + +battManStringCalibTableEntry OBJECT-TYPE + SYNTAX BattManStringCalibTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManStringCalibIndex } + ::= { battManStringCalibTable 1 } + +BattManStringCalibTableEntry ::= + SEQUENCE { + battManStringCalibIndex INTEGER, + battManDCCurrentZeroCalib INTEGER, + battManACCurrentZeroCalib INTEGER, + battManProbeRange INTEGER + } + +battManStringCalibIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of string calibration entries in the table." + ::= { battManStringCalibTableEntry 1 } + +battManDCCurrentZeroCalib OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The string DC current zero calibration in tenths of amps." + ::= { battManStringCalibTableEntry 2 } + +battManACCurrentZeroCalib OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The string AC current zero calibration in tenths of amps." + ::= { battManStringCalibTableEntry 3 } + +battManProbeRange OBJECT-TYPE + SYNTAX INTEGER { + amps1000 (1), + amps500 (2), + amps100 (3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The string probe range in amps." + ::= { battManStringCalibTableEntry 4 } + +--string 1 battery calibration table + +battManString1BatteryCalibTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManString1BatteryCalibTable." + ::= { battManBatteryCalib 1 } + +battManString1BatteryCalibTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManString1BatteryCalibTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting calibration information from each battery in String 1." + ::= { battManBatteryCalib 2 } + +battManString1BatteryCalibTableEntry OBJECT-TYPE + SYNTAX BattManString1BatteryCalibTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManString1BatteryCalibIndex } + ::= { battManString1BatteryCalibTable 1 } + +BattManString1BatteryCalibTableEntry ::= + SEQUENCE { + battManString1BatteryCalibIndex INTEGER, + battManString1BatteryInterTierOhmicValue INTEGER + } + +battManString1BatteryCalibIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of battery calibration entries in the table." + ::= { battManString1BatteryCalibTableEntry 1 } + +battManString1BatteryInterTierOhmicValue OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The battery inter-tier ohmic value in ohms. This corresponds to the ohmic + value for the positive terminal of the battery." + ::= { battManString1BatteryCalibTableEntry 2 } + +--string 2 battery calibration table + +battManString2BatteryCalibTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManString2BatteryCalibTable." + ::= { battManBatteryCalib 3 } + +battManString2BatteryCalibTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManString2BatteryCalibTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting calibration information from each battery in String 2." + ::= { battManBatteryCalib 4 } + +battManString2BatteryCalibTableEntry OBJECT-TYPE + SYNTAX BattManString2BatteryCalibTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManString2BatteryCalibIndex } + ::= { battManString2BatteryCalibTable 1 } + +BattManString2BatteryCalibTableEntry ::= + SEQUENCE { + battManString2BatteryCalibIndex INTEGER, + battManString2BatteryInterTierOhmicValue INTEGER + } + +battManString2BatteryCalibIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of battery calibration entries in the table." + ::= { battManString2BatteryCalibTableEntry 1 } + +battManString2BatteryInterTierOhmicValue OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The battery inter-tier ohmic value in ohms." + ::= { battManString2BatteryCalibTableEntry 2 } + +-- the battManConfig group + +battManConfigApplication OBJECT-TYPE + SYNTAX INTEGER { + silcon (1), + other (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The type of application the battery manager is installed on: + Silcon(1) Silcon UPS or + Other(2) Other UPS/Charger." + ::= { battManConfig 1 } + +battManConfigBatteryChemistry OBJECT-TYPE + SYNTAX INTEGER { + leadAcid (1), + nickel-Cadmium (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The battery chemistry of the monitored batteries: + LeadAcid(1) Lead Acid or + Nickel-Cadmium(2) Nickel-Cadmium." + ::= { battManConfig 2 } + +battManConfigBatteryAHCapacity OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amp hour capacity of the monitored batteries 5-2000 AH." + ::= { battManConfig 3 } + +battManConfigNumberofStrings OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The number of strings in the battery manager system (1 - 2 Silcon)/(1 Other)." + ::= { battManConfig 4 } + +battManConfigBatteriesperString OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The number of batteries per string." + ::= { battManConfig 5 } + +battManConfigCellsperBattery OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The number of cells per battery (1 - 6 for lead-acid, 1 - 2 for NiCd." + ::= { battManConfig 6 } + +battManConfigMinCellVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The minimum battery cell voltage alarm limit in millivolts DC." + ::= { battManConfig 7 } + +battManConfigMaxCellVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The maximum battery cell voltage alarm limit in millivolts DC." + ::= { battManConfig 8 } + +battManConfigMaxPilotTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The maximum pilot battery temperature alarm limit in tenths of degrees Fahrenheit." + ::= { battManConfig 9 } + +battManConfigMaxPilotTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The maximum pilot battery temperature alarm limit in tenths of degrees Celcius." + ::= { battManConfig 10 } + +battManConfigMaxAmbientTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The maximum ambient temperature alarm limit in tenths of degrees Fahrenheit." + ::= { battManConfig 11 } + +battManConfigMaxAmbientTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The maximum ambient temperature alarm limit in tenths of degrees Celcius." + ::= { battManConfig 12 } + +battManConfigMinAmbientTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The Minimum Ambient Temperature alarm limit in tenths of degrees Fahrenheit." + ::= { battManConfig 13 } + +battManConfigMinAmbientTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The Minimum Ambient Temperature alarm limit in tenths of degrees Celcius." + ::= { battManConfig 14 } + +battManConfigMaxRippleCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The maximum ripple current alarm limit for the monitored battery + strings in percent of AH capacity." + ::= { battManConfig 15 } + +battManConfigMaxCurrentAcceptanceDeviation OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The maximum current acceptance deviation alarm limit in percentage." + ::= { battManConfig 16 } + +battManConfigMonitorWireLength OBJECT-TYPE + SYNTAX INTEGER { + fiftyFeetOrLess (1), + moreThanFiftyFeet (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The monitor wire length: + fiftyFeetOrLess (1) indicates that the wire length is less than or equal to 50 feet. + moreThanFiftyFeet (2) indicates that the wire length is greater than 50 feet." + ::= { battManConfig 17 } + +battManConfigDischargeVoltageAlarmLevel OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The discharge voltage alarm level in percent." + ::= { battManConfig 18 } + +battManConfigAutoAnnunciatorReset OBJECT-TYPE + SYNTAX INTEGER { + disabled (1), + enabled (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The annunciator output signal reset method: + disabled(1) means the annunciator signal output will be reset when the reset button is pressed. + enabled(2) means the annunciator will stop signalling when all alarm conditions clear." + ::= { battManConfig 19 } + +-- the battManAlarm group + +battManAlarmManagementController OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Management Controller Alarm is : + normal(1) no alarm condtions identified + alarm(2) an alarm condition exits." + ::= { battManAlarm 1 } + +battManAlarmBatteries OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Batteries Alarm is : + normal(1) no alarm condtions identified + alarm(2) an alarm condition exits." + ::= { battManAlarm 2 } + +battManAlarmCharger OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Charger Alarm is : + normal(1) no alarm condtions identified + alarm(2) an alarm condition exits." + ::= { battManAlarm 3 } + +battManAlarmEnvironment OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Environment Alarm is : + normal(1) no alarm condtions identified + alarm(2) an alarm condition exits." + ::= { battManAlarm 4 } + +-- the battManSystemStatus group + +-- These are system wide parameters + +battManSystemAmbientTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system ambient temperture in tenths of degrees Celcius." + ::= { battManSystemStatus 1 } + +battManSystemAmbientTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system ambient temperture in tenths of degrees Fahrenheit." + ::= { battManSystemStatus 2 } + +battManSystemPilotTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system pilot temperature in tenths of degrees Celcius." + ::= { battManSystemStatus 3 } + +battManSystemPilotTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system pilot temperature in tenths of degrees Fahrenheit." + ::= { battManSystemStatus 4 } + +battManSystemAmbientHighTempAlarm OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the system has a high temperature alarm." + ::= { battManSystemStatus 5 } + +battManSystemAmbientLowTempAlarm OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the system has a low temperature alarm." + ::= { battManSystemStatus 6 } + +battManSystemPilotBatteryHighTempAlarm OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the system has a pilot battery high temperature alarm." + ::= { battManSystemStatus 7 } + +battManSystemPilotProbeDisconnected OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the system pilot probe is disconnected." + ::= { battManSystemStatus 8 } + +battManSystemAmbientProbeDisconnected OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the system ambient probe is disconnected." + ::= { battManSystemStatus 9 } + +-- This is a table of input contact parameters + +battManInputContactTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManContactTable." + ::= { battManInputContactStatus 1 } + +battManInputContactTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManInputContactTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting information from each contact + in the system. " + ::= { battManInputContactStatus 2 } + +battManInputContactTableEntry OBJECT-TYPE + SYNTAX BattManInputContactTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The contact to get data from." + INDEX { battManInputContactIndex } + ::= { battManInputContactTable 1 } + +BattManInputContactTableEntry ::= + SEQUENCE { + battManInputContactIndex INTEGER, + battManInputContactName DisplayString, + battManInputContactAlarmState INTEGER, + battManInputContactState INTEGER, + battManInputContactNormalState INTEGER, + battManInputContactAlarmDelay INTEGER + } + +battManInputContactIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of contact entries in the table." + ::= { battManInputContactTableEntry 1 } + +battManInputContactName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the input contact." + ::= { battManInputContactTableEntry 2 } + +battManInputContactAlarmState OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the alarm condition is active for this contact." + ::= { battManInputContactTableEntry 3 } + +battManInputContactState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to open(1), the input contact is in the open state. + When set to closed(2), the input contact is in the closed state." + ::= { battManInputContactTableEntry 4 } + +battManInputContactNormalState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to open(1), the input contact is normally open. + When set to closed(2), the input contact is normally closed." + ::= { battManInputContactTableEntry 5 } + +battManInputContactAlarmDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The alarm delay time in seconds." + ::= { battManInputContactTableEntry 6 } + +-- This is a table of battery string parameters + +battManStringTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManStringTable." + ::= { battManStringStatus 1 } + +battManStringTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManStringTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting information from each string + in the system. " + ::= { battManStringStatus 2 } + +battManStringTableEntry OBJECT-TYPE + SYNTAX BattManStringTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManStringIndex } + ::= { battManStringTable 1 } + +BattManStringTableEntry ::= + SEQUENCE { + battManStringIndex INTEGER, + battManStringCurrent INTEGER, + battManStringRippleCurrent INTEGER, + battManStringChargerHighVoltageAlarm INTEGER, + battManStringChargerLowVoltageAlarm INTEGER, + battManStringCurrentProbeDisconnected INTEGER, + battManStringOnBattery INTEGER + } + +battManStringIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of string entries in the table." + ::= { battManStringTableEntry 1 } + +battManStringCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The string current in tenths of Amps." + ::= { battManStringTableEntry 2 } + +battManStringRippleCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The string ripple current in tenths of Amps." + ::= { battManStringTableEntry 3 } + +battManStringChargerHighVoltageAlarm OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the string charger has a high voltage alarm." + ::= { battManStringTableEntry 4 } + +battManStringChargerLowVoltageAlarm OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the string charger has a low voltage alarm." + ::= { battManStringTableEntry 5 } + +battManStringCurrentProbeDisconnected OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the string charger probe is disconnected." + ::= { battManStringTableEntry 6 } + +battManStringOnBattery OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that the string is in the on-battery state." + ::= { battManStringTableEntry 7 } + +-- the battManString1BatteryStatus group + +battManString1BatteryTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManString1BatteryStatusTable." + ::= { battManBatteryStatus 1 } + +battManString1BatteryTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManString1BatteryTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting information from each string + in the system. " + ::= { battManBatteryStatus 2 } + +battManString1BatteryTableEntry OBJECT-TYPE + SYNTAX BattManString1BatteryTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManString1BatteryIndex } + ::= { battManString1BatteryTable 1 } + +BattManString1BatteryTableEntry ::= + SEQUENCE { + battManString1BatteryIndex INTEGER, + battManString1BatteryVoltage INTEGER, + battManString1BatteryLowestVoltage INTEGER, + battManString1BatteryCellShorted INTEGER, + battManString1BatteryOpenFuseOrConnection INTEGER, + battManString1BatteryLowCapacity INTEGER, + battManString1BatteryHighOhmicValue INTEGER, + battManString1BatteryThermalRunaway INTEGER, + battManString1BatteryDryout INTEGER + } + +battManString1BatteryIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of string entries in the table." + ::= { battManString1BatteryTableEntry 1 } + +battManString1BatteryVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery voltage in milli VDC." + ::= { battManString1BatteryTableEntry 2 } + +battManString1BatteryLowestVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The lowest battery discharge voltage during the last power event in milli VDC." + ::= { battManString1BatteryTableEntry 3 } + +battManString1BatteryCellShorted OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that a battery cell is shorted." + ::= { battManString1BatteryTableEntry 4 } + +battManString1BatteryOpenFuseOrConnection OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that a fuse or connection is open." + ::= { battManString1BatteryTableEntry 5 } + +battManString1BatteryLowCapacity OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates a battery has low capacity." + ::= { battManString1BatteryTableEntry 6 } + +battManString1BatteryHighOhmicValue OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates a battery has a high ohmic value." + ::= { battManString1BatteryTableEntry 7 } + +battManString1BatteryThermalRunaway OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates a battery has a thermal runaway condition." + ::= { battManString1BatteryTableEntry 8 } + +battManString1BatteryDryout OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates a battery has a dryout condition." + ::= { battManString1BatteryTableEntry 9 } + +-- the battManString2BatteryStatus group + +battManString2BatteryTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManString2BatteryStatusTable." + ::= { battManBatteryStatus 3 } + +battManString2BatteryTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManString2BatteryTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting information from each string + in the system. " + ::= { battManBatteryStatus 4 } + +battManString2BatteryTableEntry OBJECT-TYPE + SYNTAX BattManString2BatteryTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManString2BatteryIndex } + ::= { battManString2BatteryTable 1 } + +BattManString2BatteryTableEntry ::= + SEQUENCE { + battManString2BatteryIndex INTEGER, + battManString2BatteryVoltage INTEGER, + battManString2BatteryLowestVoltage INTEGER, + battManString2BatteryCellShorted INTEGER, + battManString2BatteryOpenFuseOrConnection INTEGER, + battManString2BatteryLowCapacity INTEGER, + battManString2BatteryHighOhmicValue INTEGER, + battManString2BatteryThermalRunaway INTEGER, + battManString2BatteryDryout INTEGER + } + +battManString2BatteryIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of string entries in the table." + ::= { battManString2BatteryTableEntry 1 } + +battManString2BatteryVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery voltage in milli VDC." + ::= { battManString2BatteryTableEntry 2 } + +battManString2BatteryLowestVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The lowest battery discharge voltage during the last power event in milli VDC." + ::= { battManString2BatteryTableEntry 3 } + +battManString2BatteryCellShorted OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that a battery cell is shorted." + ::= { battManString2BatteryTableEntry 4 } + +battManString2BatteryOpenFuseOrConnection OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates that a fuse or connection is open." + ::= { battManString2BatteryTableEntry 5 } + +battManString2BatteryLowCapacity OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates a battery has low capacity." + ::= { battManString2BatteryTableEntry 6 } + +battManString2BatteryHighOhmicValue OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates a battery has a high ohmic value." + ::= { battManString2BatteryTableEntry 7 } + +battManString2BatteryThermalRunaway OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates a battery has a thermal runaway condition." + ::= { battManString2BatteryTableEntry 8 } + +battManString2BatteryDryout OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + alarm (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When set to alarm(2), indicates a battery has a dryout condition." + ::= { battManString2BatteryTableEntry 9 } + +-- battery manager control group +battManRemoteAnnunciatorReset OBJECT-TYPE + SYNTAX INTEGER { + noOperation (1), + reset (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to reset(2) will reset the user interface annunciator. + Getting this OID will do nothing and return the noOperation(1) value." + ::= { battManControl 1 } + +battManResetChargeCurrentDeviationBenchmark OBJECT-TYPE + SYNTAX INTEGER { + noOperation (1), + reset (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to reset(2) will reset the charge current deviation benchmark. + Getting this OID will do nothing and return the noOperation(1) value." + ::= { battManControl 2 } + +battManResetLowestDischargeVoltages OBJECT-TYPE + SYNTAX INTEGER { + noOperation (1), + reset (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to reset(2) will reset the lowest discharge voltages. + Getting this OID will do nothing and return the noOperation(1) value." + ::= { battManControl 3 } + +-- the battManTestResults group + +--string 1 test results table + +battManString1OhmicValueLastDischargeInfo OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Informational text showing the date/time, load, and pilot temperature for the string + during the last discharge when ohmic values were recorded." + ::= { battManTestResults 1 } + +battManString1OhmicValueTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManString1OhmicValueTable." + ::= { battManTestResults 2 } + +battManString1OhmicValueTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManString1OhmicValueTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting ohmic value information from each battery in String 1." + ::= { battManTestResults 3 } + +battManString1OhmicValueTableEntry OBJECT-TYPE + SYNTAX BattManString1OhmicValueTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManString1OhmicValueIndex } + ::= { battManString1OhmicValueTable 1 } + +BattManString1OhmicValueTableEntry ::= + SEQUENCE { + battManString1OhmicValueIndex INTEGER, + battManString1OhmicValueData INTEGER + } + +battManString1OhmicValueIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery number." + ::= { battManString1OhmicValueTableEntry 1 } + +battManString1OhmicValueData OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery inter-tier ohmic value in ohms. + Note: Negative values are invalid and may indicate faulty calibration + of ohmic value correction factors." + ::= { battManString1OhmicValueTableEntry 2 } + +battManString1ResponseTestChangeTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManString1ResponseTestChangeTable." + ::= { battManTestResults 4 } + +battManString1ResponseTestChangeTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManString1ResponseTestChangeTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting response test change information from each battery in String 1." + ::= { battManTestResults 5 } + +battManString1ResponseTestChangeTableEntry OBJECT-TYPE + SYNTAX BattManString1ResponseTestChangeTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManString1ResponseTestChangeIndex } + ::= { battManString1ResponseTestChangeTable 1 } + +BattManString1ResponseTestChangeTableEntry ::= + SEQUENCE { + battManString1ResponseTestChangeIndex INTEGER, + battManString1ResponseTestChangeData INTEGER + } + +battManString1ResponseTestChangeIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of the entries in the table." + ::= { battManString1ResponseTestChangeTableEntry 1 } + +battManString1ResponseTestChangeData OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery response test change in percent." + ::= { battManString1ResponseTestChangeTableEntry 2 } + +battManString2OhmicValueLastDischargeInfo OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Informational text showing the date/time, load, and pilot temperature for the string + during the last discharge when ohmic values were recorded." + ::= { battManTestResults 6 } + +battManString2OhmicValueTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManString2OhmicValueTable." + ::= { battManTestResults 7 } + +battManString2OhmicValueTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManString2OhmicValueTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting ohmic value information from each battery in String 1." + ::= { battManTestResults 8 } + +battManString2OhmicValueTableEntry OBJECT-TYPE + SYNTAX BattManString2OhmicValueTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManString2OhmicValueIndex } + ::= { battManString2OhmicValueTable 1 } + +BattManString2OhmicValueTableEntry ::= + SEQUENCE { + battManString2OhmicValueIndex INTEGER, + battManString2OhmicValueData INTEGER + } + +battManString2OhmicValueIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of battery calibration entries in the table." + ::= { battManString2OhmicValueTableEntry 1 } + +battManString2OhmicValueData OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery inter-tier ohmic value in ohms. + Note: Negative values are invalid and may indicate faulty calibration + of ohmic value correction factors." + ::= { battManString2OhmicValueTableEntry 2 } + +battManString2ResponseTestChangeTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the battManString2ResponseTestChangeTable." + ::= { battManTestResults 9 } + +battManString2ResponseTestChangeTable OBJECT-TYPE + SYNTAX SEQUENCE OF BattManString2ResponseTestChangeTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting response test change information from each battery in String 1." + ::= { battManTestResults 10 } + +battManString2ResponseTestChangeTableEntry OBJECT-TYPE + SYNTAX BattManString2ResponseTestChangeTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The string to get data from." + INDEX { battManString2ResponseTestChangeIndex } + ::= { battManString2ResponseTestChangeTable 1 } + +BattManString2ResponseTestChangeTableEntry ::= + SEQUENCE { + battManString2ResponseTestChangeIndex INTEGER, + battManString2ResponseTestChangeData INTEGER + } + +battManString2ResponseTestChangeIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of the entries in the table." + ::= { battManString2ResponseTestChangeTableEntry 1 } + +battManString2ResponseTestChangeData OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery response test change in percent." + ::= { battManString2ResponseTestChangeTableEntry 2 } + +-- the xPDUIdent group + +xPDUIdentProductName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the PDU." + ::= { xPDUIdent 1 } + +xPDUIdentHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the PDU. + This value is set at the factory." + ::= { xPDUIdent 2 } + +xPDUIdentFirmwareAppRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ID string identifying the application firmware revision of the PDU." + ::= { xPDUIdent 3 } + +xPDUIdentFirmwareAppOSRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ID string identifying the application operating system firmware revision of the PDU." + ::= { xPDUIdent 4 } + +xPDUIdentFirmwareControllerRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ID string identifying the PDU controller firmware revision." + ::= { xPDUIdent 5 } + +xPDUIdentDateOfManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date when the PDU was manufactured in mm/dd/yyyy format. + This value is set at the factory." + ::= { xPDUIdent 6 } + +xPDUIdentModelNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the model number of + the PDU. This value is set at the factory." + ::= { xPDUIdent 7 } + +xPDUIdentSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the serial number of + the PDU. This value is set at the factory." + ::= { xPDUIdent 8 } + +-- the xPDUDevice group + +xPDUDeviceNominalMainInputVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The nominal main input voltage to the PDU. + Measured in Volts, line-to-line for a delta service or + line-to-neutral for a wye service." + ::= { xPDUDevice 1 } + +xPDUDeviceServiceType OBJECT-TYPE + SYNTAX INTEGER { + delta (1), + wye (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The type of utility input to the PDU. Either 3 wires (delta), or 4 wires (wye)." + ::= { xPDUDevice 2 } + +xPDUDeviceNominalOutputVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The nominal line-to-neutral output voltage to the load measured in Volts." + ::= { xPDUDevice 3 } + +xPDUDeviceMainInputBreakerRating OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The rating of the main input breaker measured in Amps." + ::= { xPDUDevice 4 } + +xPDUDevicePanelBreakerRating OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The rating of the panel breaker measured in Amps." + ::= { xPDUDevice 5 } + +xPDUDeviceTransformerPresent OBJECT-TYPE + SYNTAX INTEGER { + notPresent (1), + present (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether or not a transformer is installed in the PDU." + ::= { xPDUDevice 6 } + +xPDUDeviceLoadTieBreakerPresent OBJECT-TYPE + SYNTAX INTEGER { + notPresent (1), + present (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether or not a load tie breaker is installed in the PDU." + ::= { xPDUDevice 7 } + +xPDUDeviceLoadTestPortPresent OBJECT-TYPE + SYNTAX INTEGER { + notPresent (1), + present (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether or not a load test port is installed in the PDU." + ::= { xPDUDevice 8 } + +xPDUDeviceFusesPresent OBJECT-TYPE + SYNTAX INTEGER { + notPresent (1), + present (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether or not the UPS feed from the PDU includes fuses." + ::= { xPDUDevice 9 } + +xPDUDeviceFansPresent OBJECT-TYPE + SYNTAX INTEGER { + notPresent (1), + present (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether or not cooling fans are installed in the PDU." + ::= { xPDUDevice 10 } + +xPDUDeviceBypassInputPresent OBJECT-TYPE + SYNTAX INTEGER { + notPresent (1), + present (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether or not the PDU is equipped with a second feed for + the UPS's bypass input." + ::= { xPDUDevice 11 } + +xPDUDeviceCrossTieOutputPresent OBJECT-TYPE + SYNTAX INTEGER { + notPresent (1), + present (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether or not the PDU is equipped with a cross-tie output." + ::= { xPDUDevice 12 } + +xPDUDeviceEarthGroundMonitorPresent OBJECT-TYPE + SYNTAX INTEGER { + notPresent (1), + present (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether or not the PDU can provide ground current measurements." + ::= { xPDUDevice 13 } + +xPDUDeviceInfraXureType OBJECT-TYPE + SYNTAX INTEGER { + typeB (1), + typeC (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates the configuration of this PDU system. + Type-B PDU is in a distributed UPS system and has bypass capabilities. + Type-C PDU receives power from a larger central UPS." + ::= { xPDUDevice 14 } + +-- Main Input + +xPDUMainInputOverVoltThreshold OBJECT-TYPE + SYNTAX INTEGER (0..30) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold above which an input over voltage condition will be generated. + Specified as percent deviation from nominal." + ::= { xPDUMainInput 1 } + +xPDUMainInputUnderVoltThreshold OBJECT-TYPE + SYNTAX INTEGER (0..30) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which an input under voltage condition will be generated. + Specified as percent deviation from nominal." + ::= { xPDUMainInput 2 } + +-- Main Input Voltage Table + +xPDUMainInputVoltageTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of Main input voltage entries." + ::= { xPDUMainInput 3 } + +xPDUMainInputVoltageTable OBJECT-TYPE + SYNTAX SEQUENCE OF XPDUMainInputVoltagePhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of input voltage table entries. The number of + entries are the phase entries. + The number of entries is contained in the + xPDUMainInputVoltageTableSize OID." + ::= { xPDUMainInput 4 } + + xPDUMainInputVoltagePhaseEntry OBJECT-TYPE + SYNTAX XPDUMainInputVoltagePhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular main input voltage phase." + INDEX { xPDUMainInputVoltagePhaseIndex } + ::= { xPDUMainInputVoltageTable 1 } + + XPDUMainInputVoltagePhaseEntry ::= SEQUENCE { + xPDUMainInputVoltagePhaseIndex INTEGER, + xPDUMainInputVoltageLtoL INTEGER, + xPDUMainInputVoltageLtoN INTEGER + } + + xPDUMainInputVoltagePhaseIndex OBJECT-TYPE + SYNTAX INTEGER{ + phase1(1), + phase2(2), + phase3(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Description of each input phase entry in the table." + ::= { xPDUMainInputVoltagePhaseEntry 1 } + + xPDUMainInputVoltageLtoL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-line PDU input voltage when an isolation transformer is present, + or -1 if no transformer present in this PDU. Measured in tenths of Volts." + ::= { xPDUMainInputVoltagePhaseEntry 2 } + + xPDUMainInputVoltageLtoN OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-neutral PDU input voltage when an isolation transformer is not present, + or -1 if a transformer is present in this PDU. Measured in tenths of Volts." + ::= { xPDUMainInputVoltagePhaseEntry 3 } + + +xPDUBypassInputOverVoltThreshold OBJECT-TYPE + SYNTAX INTEGER (0..30) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold above which a bypass input over voltage condition will be generated. + Specified as percent deviation from nominal." + ::= { xPDUBypassInput 1 } + +xPDUBypassInputUnderVoltThreshold OBJECT-TYPE + SYNTAX INTEGER (0..30) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which an bypass input under voltage condition will be generated. + Specified as percent deviation from nominal." + ::= { xPDUBypassInput 2 } + +-- Bypass Input Voltage Table + +xPDUBypassInputVoltageTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of bypass input voltage entries." + ::= { xPDUBypassInput 3 } + +xPDUBypassInputVoltageTable OBJECT-TYPE + SYNTAX SEQUENCE OF XPDUBypassInputVoltagePhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of output table entries. The number of + entries are the phase entries. + The number of entries is contained in the + xPDUBypassInputVoltageTableSize OID." + ::= { xPDUBypassInput 4 } + + xPDUBypassInputVoltagePhaseEntry OBJECT-TYPE + SYNTAX XPDUBypassInputVoltagePhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular bypass input voltage phase." + INDEX { xPDUBypassInputVoltagePhaseIndex } + ::= { xPDUBypassInputVoltageTable 1 } + + XPDUBypassInputVoltagePhaseEntry ::= SEQUENCE { + xPDUBypassInputVoltagePhaseIndex INTEGER, + xPDUBypassInputVoltageLtoL INTEGER, + xPDUBypassInputVoltageLtoN INTEGER + } + + xPDUBypassInputVoltagePhaseIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of each bypass input phase entry in the table." + ::= { xPDUBypassInputVoltagePhaseEntry 1 } + + xPDUBypassInputVoltageLtoL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-line bypass input voltage, or -1 if no bypass + feed is present in this PDU. Measured in tenths of Volts" + ::= { xPDUBypassInputVoltagePhaseEntry 2 } + + xPDUBypassInputVoltageLtoN OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-neutral bypass input voltage, or -1 if no bypass + feed is present in this PDU. Measured in tenths of Volts" + ::= { xPDUBypassInputVoltagePhaseEntry 3 } + +-- UPS Input Table + +xPDUUPSInputVoltageTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of UPS input voltage entries." + ::= { xPDUUPSInput 1 } + +xPDUUPSInputVoltageTable OBJECT-TYPE + SYNTAX SEQUENCE OF XPDUUPSInputVoltagePhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of UPS input table entries. The number of + entries are the phase entries. + The number of entries is contained in the + xPDUUPSInputVoltageTableSize OID." + ::= { xPDUUPSInput 2 } + + xPDUUPSInputVoltagePhaseEntry OBJECT-TYPE + SYNTAX XPDUUPSInputVoltagePhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular UPS input voltage phase." + INDEX { xPDUUPSInputVoltagePhaseIndex } + ::= { xPDUUPSInputVoltageTable 1 } + + XPDUUPSInputVoltagePhaseEntry ::= SEQUENCE { + xPDUUPSInputVoltagePhaseIndex INTEGER, + xPDUUPSInputVoltageLtoNPresent INTEGER + } + + xPDUUPSInputVoltagePhaseIndex OBJECT-TYPE + SYNTAX INTEGER{ + phase1(1), + phase2(2), + phase3(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Description of each UPS input phase entry in the table." + ::= { xPDUUPSInputVoltagePhaseEntry 1 } + + xPDUUPSInputVoltageLtoNPresent OBJECT-TYPE + SYNTAX INTEGER { + notPresent (1), + present (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether or not voltage is present at the UPS feed." + ::= { xPDUUPSInputVoltagePhaseEntry 2 } + +-- System Output + +xPDUSystemOutputFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system output frequency in tenths of Hertz." + ::= { xPDUSystemOutput 1 } + +xPDUSystemOutputNeutralCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Shows the neutral current measured at the system output in tenths of Amps." + ::= { xPDUSystemOutput 2 } + +xPDUSystemOutputTotalPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Shows the total system output power in tenths of kW." + ::= { xPDUSystemOutput 3 } + +xPDUSystemOutputTotalApparentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Shows the total system output power in tenths of kVA." + ::= { xPDUSystemOutput 4 } + +xPDUSystemOutputTotalPowerFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates the total power factor of the system output. + A value of 100 representing a unity power factor (1.00). + Measured in hundredths." + ::= { xPDUSystemOutput 5 } + +xPDUSystemOutputFrequencyTolerance OBJECT-TYPE + SYNTAX INTEGER{ + freqToleranceOff (1), + freqTolerancePointTwo (2), + freqTolerancePointFive (3), + freqToleranceOne (4), + freqToleranceOnePointFive (5), + freqToleranceTwo (6), + freqToleranceThree (7), + freqToleranceFour (8), + freqToleranceFive (9), + freqToleranceNine (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Shows the circuit panel output frequency tolerance in Hertz." + ::= { xPDUSystemOutput 6 } + +xPDUSystemOutputMaxKWPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Defines 100% load in kW. + Purpose is to set to match UPS capabilities." + ::= { xPDUSystemOutput 7 } + +xPDUSystemOutputOverVoltThreshold OBJECT-TYPE + SYNTAX INTEGER (0..30) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold above which an output over voltage condition will be generated. + Specified as percent deviation from nominal." + ::= { xPDUSystemOutput 8 } + +xPDUSystemOutputUnderVoltThreshold OBJECT-TYPE + SYNTAX INTEGER (0..30) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which an output under voltage condition will be generated. + Specified as percent deviation from nominal." + ::= { xPDUSystemOutput 9 } + + +xPDUSystemOutputOverCurrentThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold above which an over current condition will be generated. + Specified as a percent of the panel breaker rating." + ::= { xPDUSystemOutput 10 } + +xPDUSystemOutputOverCurrentNeutralThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold above which an Over current neutral condition will be generated. + Specified as a percent of the panel breaker rating." + ::= { xPDUSystemOutput 11 } + +xPDUSystemOutputUnderCurrentThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which an under current condition will be generated. + Specified as a percent of the panel breaker rating." + ::= { xPDUSystemOutput 12 } + +xPDUSystemOutputTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of System Output phase entries." + ::= { xPDUSystemOutput 13 } + +xPDUSystemOutputTable OBJECT-TYPE + SYNTAX SEQUENCE OF XPDUSystemOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of system output table entries. + The number of entries is contained in the + xPDUSystemOutputTableSize OID." + ::= { xPDUSystemOutput 14 } + + xPDUSystemOutputPhaseEntry OBJECT-TYPE + SYNTAX XPDUSystemOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular system output phase." + INDEX { xPDUSystemOutputPhaseIndex } + ::= { xPDUSystemOutputTable 1 } + + XPDUSystemOutputPhaseEntry ::= SEQUENCE { + xPDUSystemOutputPhaseIndex INTEGER, + xPDUSystemOutputVoltageLtoL INTEGER, + xPDUSystemOutputVoltageLtoN INTEGER, + xPDUSystemOutputPhaseCurrent INTEGER, + xPDUSystemOutputPower INTEGER, + xPDUSystemOutputApparentPower INTEGER, + xPDUSystemOutputPowerFactor INTEGER + } + + xPDUSystemOutputPhaseIndex OBJECT-TYPE + SYNTAX INTEGER{ + phase1(1), + phase2(2), + phase3(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Description of each output phase entry in the table." + ::= { xPDUSystemOutputPhaseEntry 1 } + + xPDUSystemOutputVoltageLtoL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-line system output voltage available at the cicuit panel. + Measured in tenths of Volts." + ::= { xPDUSystemOutputPhaseEntry 2 } + + xPDUSystemOutputVoltageLtoN OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-neutral system output voltage available at the cicuit panel. + Measured in tenths of Volts." + ::= { xPDUSystemOutputPhaseEntry 3 } + + + xPDUSystemOutputPhaseCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System load current per phase. Measured in tenths of Amps." + ::= { xPDUSystemOutputPhaseEntry 4 } + + xPDUSystemOutputPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System output power per phase. Measured in tenths of kW." + ::= { xPDUSystemOutputPhaseEntry 5 } + + xPDUSystemOutputApparentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System output power per phase. Measured in tenths of kVA." + ::= { xPDUSystemOutputPhaseEntry 6 } + + xPDUSystemOutputPowerFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates the Power Factor of the system output per phase. + A value of 100 representing a unity Power Factor (1.00). + Measured in hundredths." + ::= { xPDUSystemOutputPhaseEntry 7 } + +xPDUGroundCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Shows the current measured in the earth ground conductor in tenths of Amps." + ::= { xPDUGroundMonitorPoint 1 } + +xPDUGroundCurrentThreshold OBJECT-TYPE + SYNTAX INTEGER (0..50) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold above which a ground current over current + condition will be generated. Measured in tenths of Amps." + ::= { xPDUGroundMonitorPoint 2 } + +-- System Breakers + +xPDUSystemBreakerTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of system breaker entries." + ::= { xPDUSystemBreakers 1 } + +xPDUSystemBreakerTable OBJECT-TYPE + SYNTAX SEQUENCE OF XPDUSystemBreakerTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of system breaker entries. + The number of entries is contained in the + xPDUSystemBreakerTableSize OID." + ::= { xPDUSystemBreakers 2 } + + xPDUSystemBreakerTableEntry OBJECT-TYPE + SYNTAX XPDUSystemBreakerTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular system breaker." + INDEX { xPDUSystemBreakerTableIndex } + ::= { xPDUSystemBreakerTable 1 } + + XPDUSystemBreakerTableEntry ::= SEQUENCE { + xPDUSystemBreakerTableIndex INTEGER, + xPDUSystemBreakerDescription DisplayString, + xPDUSystemBreakerPosition INTEGER + } + + xPDUSystemBreakerTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of system breaker entries in the table." + ::= { xPDUSystemBreakerTableEntry 1 } + +xPDUSystemBreakerDescription OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..79)) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A brief description of the system breakers." + ::= { xPDUSystemBreakerTableEntry 2 } + + xPDUSystemBreakerPosition OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether this breaker is open(1) or closed(2)." + ::= { xPDUSystemBreakerTableEntry 3 } + +-- Branch Breakers (Breaker Panel) + +xPDUNumOfBranchBreakers OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of branch breakers in the Panel." + ::= { xPDUBranchBreakers 1 } + +-- Branch Breakers Table + +xPDUBranchBreakerTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of branch breaker entries." + ::= { xPDUBranchBreakers 2 } + +xPDUBranchBreakerTable OBJECT-TYPE + SYNTAX SEQUENCE OF XPDUBranchBreakerEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of branch breaker table entries. The + number of entries is given by the value of xPDUBranchBreakerTableSize + The number of entries is contained in the + xPDUBranchBreakerTableSize OID." + ::= { xPDUBranchBreakers 3 } + + xPDUBranchBreakerEntry OBJECT-TYPE + SYNTAX XPDUBranchBreakerEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular branch breaker." + INDEX { xPDUBranchBreakerTableIndex } + ::= { xPDUBranchBreakerTable 1 } + + XPDUBranchBreakerEntry ::= SEQUENCE { + xPDUBranchBreakerTableIndex INTEGER, + xPDUBranchBreakerRating INTEGER, + xPDUBranchBreakerRDPFeed INTEGER, + xPDUBranchBreakerTieIndicator INTEGER, + xPDUBranchBreakerCurrent INTEGER, + xPDUBranchBreakerOverCurrentThreshold INTEGER, + xPDUBranchBreakerUnderCurrentThreshold INTEGER + } + + xPDUBranchBreakerTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of branch breaker entries in the table." + ::= { xPDUBranchBreakerEntry 1 } + + xPDUBranchBreakerRating OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Indicates current rating of this breaker. + 0=Breaker is not present. + 1=Earth leakage connection. + 2=Neutral connection. + A value greater than 2 indicates breaker current rating in Amps." + ::= { xPDUBranchBreakerEntry 2 } + + xPDUBranchBreakerRDPFeed OBJECT-TYPE + SYNTAX INTEGER { + remoteDistribution (1), + noRemoteDistribution (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Indicates that a breaker position is feeding a remote + distribution panel." + ::= { xPDUBranchBreakerEntry 3 } + + xPDUBranchBreakerTieIndicator OBJECT-TYPE + SYNTAX INTEGER { + breakerTied (1), + breakerUntied (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Indicates whether or not the breaker pole is physically + connected to the breaker immediately below." + ::= { xPDUBranchBreakerEntry 4 } + + xPDUBranchBreakerCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates the branch current in tenths of Amps or -1 when not available." + ::= { xPDUBranchBreakerEntry 5 } + + xPDUBranchBreakerOverCurrentThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold above which a branch circuit over current + condition will be generated. + Specified as a percent of the branch breaker rating." + ::= { xPDUBranchBreakerEntry 6 } + + xPDUBranchBreakerUnderCurrentThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which a branch circuit under current + condition will be generated. + Specified as a percent of the branch breaker rating." + ::= { xPDUBranchBreakerEntry 7 } + +-- the xPDUInputContacts group + +xPDUInputContactNumContacts OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of contacts supported by the PDU." + ::= { xPDUInputContacts 1 } + +xPDUInputContactTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input contact entries." + ::= { xPDUInputContacts 2 } + +xPDUInputContactTable OBJECT-TYPE + SYNTAX SEQUENCE OF XPDUInputContactEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of contacts supported by the PDU. + The number of entries is contained in the + xPDUInputContactTableSize OID." + ::= { xPDUInputContacts 3 } + +xPDUInputContactEntry OBJECT-TYPE + SYNTAX XPDUInputContactEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A contact entry containing information for a given contact." + INDEX { xPDUInputContactNumber } + ::= { xPDUInputContactTable 1 } + +XPDUInputContactEntry ::= + SEQUENCE { + xPDUInputContactNumber INTEGER, + xPDUInputContactName DisplayString, + xPDUInputContactNormalState INTEGER, + xPDUInputContactCurrentState INTEGER + } + +xPDUInputContactNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An index identifying the contact on the PDU." + ::= { xPDUInputContactEntry 1 } + +xPDUInputContactName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The description of the purpose/use of the contact." + ::= { xPDUInputContactEntry 2 } + +xPDUInputContactNormalState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The normal operating position of the contact." + ::= { xPDUInputContactEntry 3 } + +xPDUInputContactCurrentState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This value indicates the current state of the contact." + ::= { xPDUInputContactEntry 4 } + +-- the xPDUOutputRelays group + +xPDUOutputRelaysNumRelays OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output relays supported by the PDU." + ::= { xPDUOutputRelays 1 } + +xPDUOutputRelaysTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output relay entries." + ::= { xPDUOutputRelays 2 } + +xPDUOutputRelayTable OBJECT-TYPE + SYNTAX SEQUENCE OF XPDUOutputRelayEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of output relays supported by the PDU. + The number of entries is contained in the + xPDUOutputRelayTableSize OID." + ::= { xPDUOutputRelays 3 } + +xPDUOutputRelayEntry OBJECT-TYPE + SYNTAX XPDUOutputRelayEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A output relay entry containing information for a given contact." + INDEX { xPDUOutputRelayNumber } + ::= { xPDUOutputRelayTable 1 } + +XPDUOutputRelayEntry ::= + SEQUENCE { + xPDUOutputRelayNumber INTEGER, + xPDUOutputRelayName DisplayString, + xPDUOutputRelayNormalState INTEGER, + xPDUOutputRelayCurrentState INTEGER + } + +xPDUOutputRelayNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An index identifying the output relay on the PDU." + ::= { xPDUOutputRelayEntry 1 } + +xPDUOutputRelayName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The description of the purpose/use of the output relay." + ::= { xPDUOutputRelayEntry 2 } + +xPDUOutputRelayNormalState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The normal operating position of the output relay." + ::= { xPDUOutputRelayEntry 3 } + +xPDUOutputRelayCurrentState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This value indicates the current state of the output relay." + ::= { xPDUOutputRelayEntry 4 } + +-- the xPDUMiscGroup + +xPDUEPOMode OBJECT-TYPE + SYNTAX INTEGER { + armed (1), + disarmed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether the EPO System is armed(1) or disarmed(2)." + ::= { xPDUMiscGroup 1 } + +xPDUTransformTempStatus OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + overtemp (2), + noTransformerPresent (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates if the PDU's isolation transformer is over temperature." + ::= { xPDUMiscGroup 2 } + +xPDUCoolingFanStatus OBJECT-TYPE + SYNTAX INTEGER { + normal (1), + failed (2), + noCoolingFansPresent (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates if one or more of the PDU's cooling fans have failed." + ::= { xPDUMiscGroup 3 } + +-- The xATSIdent group + +xATSIdentProductName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the transfer switch unit." + ::= { xATSIdent 1 } + +xATSIdentHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the transfer switch. + This value is set at the factory." + ::= { xATSIdent 2 } + +xATSIdentFirmwareAppRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ID string identifying the application firmware revision of the transfer switch." + ::= { xATSIdent 3 } + +xATSIdentFirmwareAppOSRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ID string identifying the application operating system firmware revision of the transfer switch." + ::= { xATSIdent 4 } + +xATSIdentFirmwareControllerRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ID string identifying the transfer switch controller firmware revision." + ::= { xATSIdent 5 } + +xATSIdentDateOfManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date when the transfer switch was manufactured in mm/dd/yyyy format. + This value is set at the factory." + ::= { xATSIdent 6 } + +xATSIdentModelNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the model number of the transfer switch. + This value is set at the factory." + ::= { xATSIdent 7 } + +xATSIdentSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the serial number of the transfer switch. + This value is set at the factory." + ::= { xATSIdent 8 } + +-- The xATSDevice group + +xATSDeviceServiceType OBJECT-TYPE + SYNTAX INTEGER { + threeWire (1), + fourWire (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The type of utility input to the transfer switch. + Either 3 wires (delta), or 4 wires (wye)." + ::= { xATSDevice 1 } + +xATSDeviceNominalVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The nominal line-to-neutral system voltage. + Measured in Volts, line-to-line for a 3-wire service or + line-to-neutral for a 4-wire service. -1 if not available." + ::= { xATSDevice 2 } + +xATSDeviceNominalFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The nominal system frequency. Measured in tenths of Hertz. + -1 if not available." + ::= { xATSDevice 3 } + +xATSDeviceTransferSwitchRating OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The rating of the transfer switch. + Measured in Amps." + ::= { xATSDevice 4 } + +xATSDeviceDCBackUpPresent OBJECT-TYPE + SYNTAX INTEGER{ + yes (1), + no (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Indicates if a DC backup is present or not." + ::= { xATSDevice 5 } + +-- The xATS Switch Status group + +xATSSwitchStatusSelectedSource OBJECT-TYPE + SYNTAX INTEGER{ + none (1), + source1 (2), + source2 (3), + fault (4), + unknown (5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The source which is currently selected, i.e. supplying power to the load." + ::= { xATSSwitchStatus 1 } + +xATSSwitchStatusOperationalMode OBJECT-TYPE + SYNTAX INTEGER{ + automatic (1), + notInAutoAbnormal (2), + notInAuto (3), + unknown (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current operating mode of the transfer switch. When the ATS is in + automatic mode, generator starting and ATS transferring is all done automatically + as needed based on the state of source 1. Automatic operation is halted when the + ATS is in either of the notInAuto modes. + A mode of notInAuto indicates that the automatic operation switch is in the + disabled position, as indicated by the xATSSwitchStatusAutomaticOperationSwitch OID. + The notInAutoAbnormal condition indicates that an abnormal + condition has caused the transfer switch to halt automatic operation. + In this case, traps can indicate the exact problem. In the case of + notInAutoAbnormal, refer to the operation manual for details + on how debug the condition and restore automatic operation." + ::= { xATSSwitchStatus 2 } + +xATSSwitchStatusAutomaticOperationSwitch OBJECT-TYPE + SYNTAX INTEGER{ + disabled (1), + enabled (2), + unknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The position of the automatic operation switch on the front of the transfer switch." + ::= { xATSSwitchStatus 3 } + +xATSSwitchStatusEngineStartSignal OBJECT-TYPE + SYNTAX INTEGER{ + run (1), + stop (2), + unknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The position of the Start/Stop contact which signals the generator + engine to start/run. When the ATS is in automatic mode, + generator starting/stopping is under ATS control." + ::= { xATSSwitchStatus 4 } + +-- The xATS Switch Setting group + +xATSSwitchSettingsLowVoltageTransferPoint OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The lowest acceptable voltage condition at source 1. + When any phase of source 1 is lower than this voltage, + source quality is considered bad and the generator run signal + is asserted to begin generator operation. + Specified in volts, line-to-line for a 3-wire service or + line-to-neutral for a 4-wire service. + -1 if not available." + ::= { xATSSwitchSettings 1 } + +xATSSwitchSettingsHighVoltageTransferPoint OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The highest acceptable voltage condition at source 1. + When any phase of source 1 is greater than this voltage, + source quality is considered bad and the generator run signal + is asserted to begin generator operation. + Specified in volts, line-to-line for a 3-wire service or + line-to-neutral for a 4-wire service. + -1 if not available." + ::= { xATSSwitchSettings 2 } + +xATSSwitchSettingsMaxFrequencyDeviation OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The maximum acceptable frequency deviation condition from nominal at source 1. + When source 1 frequency is outside the specified range, + source quality is considered bad and the generator run signal + is asserted to begin generator operation. + Specified in tenths of Hertz above or below nominal. + A value of zero indicates that frequency is ignored when + determining source quality. + -1 if not available." + ::= { xATSSwitchSettings 3 } + +xATSSwitchSettingsMinPhaseBalance OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The minimum required phase balance at source 1. + When the percentage difference between the minimum and maximum + phase voltage measurements at source 1 is greater than this value, + source quality is considered bad and the generator run signal + is asserted to begin generator operation. + Specified as a percentage. A value of zero indicates that phase balance + is ignored when determining source quality. + -1 if not available." + ::= { xATSSwitchSettings 4 } + +xATSSwitchSettingsNominalRotation OBJECT-TYPE + SYNTAX INTEGER{ + abc (1), + cba (2), + any (3), + unknown (4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The nominal phase rotation (or phase sequence) required by the load. + For certain types of equipment, such as rotating machinery, phase rotation + is critical for proper operation as it determines the direction which motors + will rotate (clockwise or counterclockwise). + Source quality will be seen as bad if the rotation measured at that + ATS input does not match this setting. + If this setting is set to any, phase rotation is ignored." + ::= { xATSSwitchSettings 5 } + +xATSSwitchSettingsAllowClosedTransfer OBJECT-TYPE + SYNTAX INTEGER{ + yes (1), + no (2), + unknown (3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This setting enables seemless (closed) transfers between sources. + When possible, both source 1 and source 2 are closed to the output + for a brief time. If closed transfer is not possible within the amount + of time specified by the xATSSwitchSettingsMaxSyncTime OID, + an open transfer will be executed." + ::= { xATSSwitchSettings 6 } + +xATSSwitchSettingsMaxSyncTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "When attempting/seeking to perform a closed transfer, this setting defines + the maximum time allowed before the transfer switch will give up and perform + an open transfer. Specified in seconds. + -1 if not available." + ::= { xATSSwitchSettings 7 } + +xATSSwitchSettingsNeutralTransferTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This setting defines how long both source 1 and source 2 will be + disconnected from the output, during an open transfer. + Specified in seconds. + -1 if not available." + ::= { xATSSwitchSettings 8 } + +xATSSwitchSettingsClearLatchedAlarms OBJECT-TYPE + SYNTAX INTEGER{ + yes (1), + no (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Clears any latched alarm conditions." + ::= { xATSSwitchSettings 9 } + +xATSSwitchSettingsSetToFactoryDefaults OBJECT-TYPE + SYNTAX INTEGER{ + yes (1), + no (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Sets all transfer switch settings to factory default values." + ::= { xATSSwitchSettings 10 } + + +-- The xATSSwitchTimers group + + xATSSwitchTimersTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of transfer switch timer entries." + ::= { xATSSwitchTimers 1 } + + xATSSwitchTimersTable OBJECT-TYPE + SYNTAX SEQUENCE OF XATSSwitchTimersEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of timers supported by ATS. + The number of entries is contained in the xATSSwitchTimersTableSize OID." + ::= { xATSSwitchTimers 2 } + + xATSSwitchTimersEntry OBJECT-TYPE + SYNTAX XATSSwitchTimersEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information about an individual ATS timer." + INDEX { xATSSwitchTimersIndex } + ::= { xATSSwitchTimersTable 1 } + + XATSSwitchTimersEntry ::= + SEQUENCE { + xATSSwitchTimersIndex INTEGER, + xATSSwitchTimersName DisplayString, + xATSSwitchTimersAbort INTEGER, + xATSSwitchTimersStatus INTEGER, + xATSSwitchTimersRemainingTime INTEGER, + xATSSwitchTimersDelaySetting INTEGER + } + +xATSSwitchTimersIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of timer entries in the table." + ::= { xATSSwitchTimersEntry 1 } + +xATSSwitchTimersName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Name of the individual timer.Refer to ATS operation manual, + or on-line help, for detailed descriptions of ATS timers." + ::= { xATSSwitchTimersEntry 2 } + +xATSSwitchTimersAbort OBJECT-TYPE + SYNTAX INTEGER{ + yes (1), + no (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This aborts the individual timer." + ::= { xATSSwitchTimersEntry 3 } + +xATSSwitchTimersStatus OBJECT-TYPE + SYNTAX INTEGER{ + inactive (1), + active (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the individual timer. Designates whether this timer + entry is currently running or inactive." + ::= { xATSSwitchTimersEntry 4 } + +xATSSwitchTimersRemainingTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The time remaining for this timer entry. + Specified in seconds." + ::= { xATSSwitchTimersEntry 5 } + +xATSSwitchTimersDelaySetting OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The delay settings associated with this timer entry. + When this timer entry is active, the timer value must exceed this setting + before the ATS behavior associated with this timer is executed. + Refer to ATS operation manual, or on-line help, for detailed + descriptions of ATS timers." + ::= { xATSSwitchTimersEntry 6 } + +-- The xATSSwitchBlockMap group + + xATSSwitchBlockMapTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of blocking map entries, or how many ATS actions can be blocked." + ::= { xATSSwitchBlockMap 1 } + + xATSSwitchBlockMapTable OBJECT-TYPE + SYNTAX SEQUENCE OF XATSSwitchBlockMapEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of blocking maps supported by the ATS. + The number of entries is contained in the xATSSwitchBlockMapTableSize OID." + ::= { xATSSwitchBlockMap 2 } + + xATSSwitchBlockMapEntry OBJECT-TYPE + SYNTAX XATSSwitchBlockMapEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information about a specific ATS blocking map." + INDEX { xATSSwitchBlockMapIndex } + ::= { xATSSwitchBlockMapTable 1 } + + XATSSwitchBlockMapEntry ::= + SEQUENCE { + xATSSwitchBlockMapIndex INTEGER, + xATSSwitchBlockMapName DisplayString, + xATSSwitchBlockMapStatus INTEGER, + xATSSwitchBlockMapSetting INTEGER + } + + xATSSwitchBlockMapIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of blocking map entries in the table." + ::= { xATSSwitchBlockMapEntry 1 } + + xATSSwitchBlockMapName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A string describing the ATS action to be blocked." + ::= { xATSSwitchBlockMapEntry 2 } + + xATSSwitchBlockMapStatus OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Represents the status of this blocking map entry, in bit-mapped format. + A non-zero value indicates that this entry's ATS action is currently being blocked. + The bit(s) set indicate which input(s) are causing the blocking (bit0, bit1, etc). + + bit 0 - Contact 1 + bit 1 - Contact 2 + bit 2 - Contact 3 + bit 3 - Contact 4." + ::= { xATSSwitchBlockMapEntry 3 } + + xATSSwitchBlockMapSetting OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This setting designates the inputs that block the ATS action + The mapping is specified as a bit-field, where each bit set indicates + the input that blocks the ATS action associated with the entry. + + bit 0 - Contact 1 + bit 1 - Contact 2 + bit 2 - Contact 3 + bit 3 - Contact 4." + ::= { xATSSwitchBlockMapEntry 4 } + +-- The xATSSwitchStatistics group + + xATSSwitchStatisticsTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of transfer switch statistics entries." + ::= { xATSSwitchStatistics 1 } + + xATSSwitchStatisticsTable OBJECT-TYPE + SYNTAX SEQUENCE OF XATSSwitchStatisticsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of statistics supported by ATS. + The number of entries is contained in the xATSSwitchStatisticsTableSize OID." + ::= { xATSSwitchStatistics 2 } + + xATSSwitchStatisticsEntry OBJECT-TYPE + SYNTAX XATSSwitchStatisticsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information about an individual ATS statistic." + INDEX { xATSSwitchStatisticsIndex } + ::= { xATSSwitchStatisticsTable 1 } + + XATSSwitchStatisticsEntry ::= + SEQUENCE { + xATSSwitchStatisticsIndex INTEGER, + xATSSwitchStatisticsName DisplayString, + xATSSwitchStatisticsValue DisplayString, + xATSSwitchStatisticsReset INTEGER + } + + xATSSwitchStatisticsIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Index of ATS statistics entries in the table." + ::= { xATSSwitchStatisticsEntry 1 } + + xATSSwitchStatisticsName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This is the name of the ATS statistic associated with this entry." + ::= { xATSSwitchStatisticsEntry 2 } + + xATSSwitchStatisticsValue OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This is the value of the ATS statistic associated with this entry." + ::= { xATSSwitchStatisticsEntry 3 } + + xATSSwitchStatisticsReset OBJECT-TYPE + SYNTAX INTEGER{ + yes (1), + no (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This will reset the individual ATS statistic associated with this entry." + ::= { xATSSwitchStatisticsEntry 4 } + +-- The xATS Source 1 group + +xATSSource1Name OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "String used to identify source 1." + ::= { xATSSource1 1 } + +xATSSource1Position OBJECT-TYPE + SYNTAX INTEGER{ + open (1), + closed (2), + tripped (3), + unknown (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current position of the switch at source 1." + ::= { xATSSource1 2 } + +xATSSource1Frequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frequency at source 1 in tenths of Hertz. + -1 if unavailable." + ::= { xATSSource1 3 } + +xATSSource1Quality OBJECT-TYPE + SYNTAX INTEGER{ + sourceGood (1), + lowVoltage (2), + highVoltage (3), + phaseImbalance (4), + freqOutOfRange (5), + badRotation (6), + unknown (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current line quality of source 1." + ::= { xATSSource1 4 } + +xATSSource1Rotation OBJECT-TYPE + SYNTAX INTEGER{ + abc (1), + cba (2), + unknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The phase rotation measured at the source 1 input of the ATS. + The sequence is a reference to the order in which the three phases + pass the zero-crossing boundary in time." + ::= { xATSSource1 5 } + +xATSSource1TableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input voltage entries at the source 1 input of the ATS." + ::= { xATSSource1 6 } + + xATSSource1Table OBJECT-TYPE + SYNTAX SEQUENCE OF XATSSource1PhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of voltage table entries for source 1. The number of + entries are the phase entries. The number of entries is contained in the + xATSSource1TableSize OID." + ::= { xATSSource1 7 } + + xATSSource1PhaseEntry OBJECT-TYPE + SYNTAX XATSSource1PhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular input voltage phase at the source 1 input of the ATS." + INDEX { xATSSource1Index } + ::= { xATSSource1Table 1 } + + XATSSource1PhaseEntry ::= SEQUENCE { + xATSSource1Index INTEGER, + xATSSource1VoltageLtoL INTEGER, + xATSSource1VoltageLtoN INTEGER + } + + xATSSource1Index OBJECT-TYPE + SYNTAX INTEGER{ + phase1(1), + phase2(2), + phase3(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Description of each phase utilized at source 1." + ::= { xATSSource1PhaseEntry 1 } + + xATSSource1VoltageLtoL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Source 1 line-to-line input voltage. + Measured in tenths of Volts." + ::= { xATSSource1PhaseEntry 2 } + + xATSSource1VoltageLtoN OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Source 1 line-to-neutral input voltage. + Measured in tenths of Volts. -1 for a 3-wire service type." + ::= { xATSSource1PhaseEntry 3 } + +-- The xATS Source 2 group + +xATSSource2Name OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "String used to identify source 2." + ::= { xATSSource2 1 } + +xATSSource2Position OBJECT-TYPE + SYNTAX INTEGER{ + open (1), + closed (2), + tripped (3), + unknown (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current position of the switch at source 2." + ::= { xATSSource2 2 } + +xATSSource2Frequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frequency at source 2 in tenths of Hertz. + -1 if not available." + ::= { xATSSource2 3 } + +xATSSource2Quality OBJECT-TYPE + SYNTAX INTEGER{ + sourceGood (1), + lowVoltage (2), + highVoltage (3), + phaseImbalance (4), + freqOutOfRange (5), + badRotation (6), + unknown (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current line quality of source 2." + ::= { xATSSource2 4 } + +xATSSource2Rotation OBJECT-TYPE + SYNTAX INTEGER{ + abc (1), + cba (2), + unknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The phase rotation measured at the source 2 input of the ATS. + -1 if not available." + ::= { xATSSource2 5 } + +xATSSource2TableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input voltage entries at the source 2 input of the ATS." + ::= { xATSSource2 6 } + + xATSSource2Table OBJECT-TYPE + SYNTAX SEQUENCE OF XATSSource2PhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of voltage table entries for the source 2. The number of + entries are the phase entries. The number of entries is contained in the + xATSSource2TableSize OID." + ::= { xATSSource2 7 } + + xATSSource2PhaseEntry OBJECT-TYPE + SYNTAX XATSSource2PhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular input voltage phase at the source 2 input of the ATS." + INDEX { xATSSource2Index } + ::= { xATSSource2Table 1 } + + XATSSource2PhaseEntry ::= SEQUENCE { + xATSSource2Index INTEGER, + xATSSource2VoltageLtoL INTEGER, + xATSSource2VoltageLtoN INTEGER + } + + xATSSource2Index OBJECT-TYPE + SYNTAX INTEGER{ + phase1(1), + phase2(2), + phase3(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Description of each phase utilized at the source 2." + ::= { xATSSource2PhaseEntry 1 } + + xATSSource2VoltageLtoL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Source 2 line-to-line input voltage. + Measured in tenths of Volts." + ::= { xATSSource2PhaseEntry 2 } + + xATSSource2VoltageLtoN OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Source 2 line-to-neutral input voltage. + Measured in tenths of Volts. -1 for a 3-wire service type." + ::= { xATSSource2PhaseEntry 3 } + +-- The xATSSystemOutput + +xATSSystemOutputFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system output frequency in tenths of Hertz." + ::= { xATSSystemOutput 1 } + +xATSSystemOutputTotalPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Shows the total system output power in tenths of kW." + ::= { xATSSystemOutput 2 } + +xATSSystemOutputTotalApparentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Shows the total system output power in tenths of kVA." + ::= { xATSSystemOutput 3 } + +xATSSystemOutputTotalPowerFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates the total power factor of the system output. + A value of 100 representing a unity power factor (1.00) + Specified in hundredths." + ::= { xATSSystemOutput 4 } + +xATSSystemOutputFrequencyTolerance OBJECT-TYPE + SYNTAX INTEGER{ + freqToleranceOff (1), + freqTolerancePointTwo (2), + freqTolerancePointFive (3), + freqToleranceOne (4), + freqToleranceOnePointFive (5), + freqToleranceTwo (6), + freqToleranceThree (7), + freqToleranceFour (8), + freqToleranceFive (9), + freqToleranceNine (10) + + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Shows the panel output frequency tolerance in +/- Hertz." + ::= { xATSSystemOutput 5 } + +xATSSystemOutputOverVoltThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold above which an output over voltage condition will be generated. + Specified as tenths of percent deviation from nominal. + A value of zero indicates that the threshold is disabled." + ::= { xATSSystemOutput 6 } + +xATSSystemOutputUnderVoltThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which an output under voltage condition will be generated. + Specified as tenths of percent deviation from nominal. + A value of zero indicates that the threshold is disabled." + ::= { xATSSystemOutput 7 } + +xATSSystemOutputOverCurrentThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold above which an over current condition will be generated. + Specified as a percent of the transfer switch rating (xATSDeviceTransferSwitchRating OID). + A value of zero indicates that the threshold is disabled." + ::= { xATSSystemOutput 8 } + +xATSSystemOutputUnderCurrentThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which an under current condition will be generated. + Specified as a percent of the transfer switch rating (xATSDeviceTransferSwitchRating OID). + A value of zero indicates that the threshold is disabled." + ::= { xATSSystemOutput 9 } + +xATSSystemOutputAlarmDelayThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Delay the generation of an output alarm. + Specified in seconds." + ::= { xATSSystemOutput 10 } + +xATSSystemOutputTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of system output phase entries." + ::= { xATSSystemOutput 11 } + +xATSSystemOutputTable OBJECT-TYPE + SYNTAX SEQUENCE OF XATSSystemOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of system output table entries. + The number of entries is contained in the xATSSystemOutputTableSize OID." + ::= { xATSSystemOutput 12 } + + xATSSystemOutputPhaseEntry OBJECT-TYPE + SYNTAX XATSSystemOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular system output phase." + INDEX { xATSSystemOutputPhaseIndex } + ::= { xATSSystemOutputTable 1 } + + XATSSystemOutputPhaseEntry ::= SEQUENCE { + xATSSystemOutputPhaseIndex INTEGER, + xATSSystemOutputVoltageLtoL INTEGER, + xATSSystemOutputVoltageLtoN INTEGER, + xATSSystemOutputPhaseCurrent INTEGER, + xATSSystemOutputPower INTEGER, + xATSSystemOutputApparentPower INTEGER, + xATSSystemOutputPowerFactor INTEGER + } + + xATSSystemOutputPhaseIndex OBJECT-TYPE + SYNTAX INTEGER{ + phase1(1), + phase2(2), + phase3(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Description of each system output phase utilized in this device." + ::= { xATSSystemOutputPhaseEntry 1 } + + xATSSystemOutputVoltageLtoL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-line system output voltage, measured in tenths of Volts, available at the circuit panel. + -1 if not available." + ::= { xATSSystemOutputPhaseEntry 2 } + + xATSSystemOutputVoltageLtoN OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-neutral system output voltage, measured in tenths of Volts, available at the circuit panel. + -1 for a 3-wire service type or if not available." + ::= { xATSSystemOutputPhaseEntry 3 } + + xATSSystemOutputPhaseCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System load current per phase. Measured in Amps. + -1 if not available." + ::= { xATSSystemOutputPhaseEntry 4 } + + xATSSystemOutputPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System output power per phase. Measured in tenths of kW." + ::= { xATSSystemOutputPhaseEntry 5 } + + xATSSystemOutputApparentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "system output power per phase. Measured in tenths of kVA." + ::= { xATSSystemOutputPhaseEntry 6 } + + xATSSystemOutputPowerFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "indicates the power factor of the system output per phase. + A value of 100 representing a unity power factor (1.00). + Measured in hundredths." + ::= { xATSSystemOutputPhaseEntry 7 } + +-- xATS TestingStatus group + +xATSTestingStatusSelectTestProcess OBJECT-TYPE + SYNTAX INTEGER { + engineStartTest (1), + systemLoadTest (2), + generatorHoldTest (3), + cancelTest (4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Type of tests that can be selected when no test has been scheduled. + engineStartTest and systemLoadTest may be selected when no tests + are running. Tests that are selected may be cancelled manually." + ::= { xATSTestingStatus 1 } + +xATSTestingStatusTestStatus OBJECT-TYPE + SYNTAX INTEGER { + noTestInProcess (1), + testPending (2), + startingEngine (3), + engineWarmingUp (4), + awaitingTransferToS2 (5), + testingWithLoad (6), + awaitingRetransferToS1 (7), + testingWithoutLoad (8), + stoppingEngine (9), + holdingOnGenerator (10) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The present system test status/state." + ::= { xATSTestingStatus 2 } + +xATSTestingStatusProfileWarmupTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time that the generator will warm up during a test. + This is portion of the test when the xATSTestingStatusTestStatus + OID returns the value engineWarmingUp. + Specified in seconds." + ::= { xATSTestingStatus 3 } + +xATSTestingStatusProfileLoadedTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time that ATS will apply the system load to the generator + during a system load test. + This is portion of the test when the xATSTestingStatusTestStatus + OID returns the value testingWithLoad. + Specified in minutes." + ::= { xATSTestingStatus 4 } + +xATSTestingStatusProfileUnloadedTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time that the generator will run following the warm up + portion of a start test, or the loaded portion of a load test. + This is portion of the test when the xATSTestingStatusTestStatus + OID returns the value testingWithoutLoad. + Specified in seconds." + ::= { xATSTestingStatus 5 } + +-- xATS TestingResults group + +xATSTestingResultsLastDateOfTest OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Date of the last test that was performed, either scheduled or manual. + Test results are available in the xATSTestingResultsLastResult OID. + Specified in the dd/mm/yyyy format, or 'none' if not available." + ::= { xATSTestingResults 1 } + +xATSTestingResultsLastResult OBJECT-TYPE + SYNTAX INTEGER { + startTestPassed (1), + loadTestPassed (2), + startSignalFailure (3), + failedGenNotInAuto (4), + failedGenEmerStop (5), + failedGenShutdown (6), + failedGenDidNotStart (7), + failedS2NeverGood (8), + genFailedDuringWarmup (9), + failureOnXferToS1 (10), + genFailedLoaded (11), + failureOnRexferToS2 (12), + genFailedToStop (13), + failedAtsInternalFault (14), + failedAtsNotInAuto (15), + cancelledManualTest (16), + cancelledScheduledTest (17) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The result of the last ATS/generator system test." + ::= { xATSTestingResults 2 } + +xATSTestingResultsTestLastTestTime OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Time of day at which the last test was performed, either scheduled or manual. + Test results are available in the xATSTestingResultsLastResult OID. + Specified in the hh:mm:ss format, or 'none' if not available." + ::= { xATSTestingResults 3 } + +xATSTestingResultsLastCrankDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The time spent cranking the generator before it started during the last test. + Specified in seconds, or -1 if not available." + ::= { xATSTestingResults 4 } + +xATSTestingResultsLastWarmupDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The time spent in the engineWarmingUp state during the last system test. + Specified in seconds, or -1 if not available." + ::= { xATSTestingResults 5 } + +xATSTestingResultsLastLoadedDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The time spent in the testingWithLoad state during the last system test. + Specified in seconds, or -1 if not available." + ::= { xATSTestingResults 6 } + +xATSTestingResultsLastUnloadedDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The time spent in the testingWithoutLoad state during the last system test. + Specified in seconds, or -1 if not available." + ::= { xATSTestingResults 7 } + +-- xATS TestingSchedule group + +xATSTestingScheduleFrequency OBJECT-TYPE + SYNTAX INTEGER { + never (1), + daily (2), + weekly (3), + monthly (4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The frequency of running scheduled tests." + ::= { xATSTestingSchedule 1 } + +xATSTestingScheduleTestDay OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The desired day for the scheduled test. This object applies only + when the xATSTestingScheduleFrequency OID is set to weekly or monthly. + For weekly test frequency, the string is the day the test will be run. + For monthly test frequency, the string indicates the day, + and the instance within the month. + For example, for monthly frequency: 2nd sunday, 3rd monday, 4th tuesday, + for weekly frequency: sunday, monday, tuesday." + ::= { xATSTestingSchedule 2 } + +xATSTestingScheduleTestTime OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The time of day that the scheduled test will occur. + Specified in the format hh:mm." + ::= { xATSTestingSchedule 3 } + +xATSTestingScheduleTestWithLoadInterval OBJECT-TYPE + SYNTAX INTEGER { + applyLoadEveryTest (1), + neverApplyLoad (2), + applyLoadMonthly (3), + applyLoadMonthlyDetailed (4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This setting specifies which system tests should include applying the + load to the generator. The applyLoadMonthlyDetailed entry + in the list will apply load once, for each month represented in the + xATSTestingScheduleTestWithLoadSelectMonth OID." + ::= { xATSTestingSchedule 4 } + +xATSTestingScheduleTestWithLoadSelectMonth OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The detailed selection for testing with load on a month-by-month basis. + This object is applicable when the xATSTestingScheduleTestWithLoadInterval + is set to applyLoadMonthlyDetailed. Otherwise this selection will be ignored. + Format for this string is a comma-separated entry of months. + For example: Jan,Mar,Dec. + The string will return 'No Months Scheduled' if no months have been selected." + ::= { xATSTestingSchedule 5 } + +xATSTestingScheduleNextTestDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date of the next scheduled test, in the format dd-mmm-yyyy." + ::= { xATSTestingSchedule 6 } + +-- xATSTestingSimulatePowerFail group + +xATSTestingSimulatePowerFailTest OBJECT-TYPE + SYNTAX INTEGER{ + cancelSimulation (1), + fiveSecondsSimulation (2), + tenSecondsSimulation (3), + thirtySecondsSimulation (4), + oneMinuteSimulation (5), + threeMinutesSimulation (6), + fiveMinutesSimulation (7), + tenMinutesSimulation (8) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This object executes a simulated power failure for the duration indicated. + Simulation can be aborted by selecting cancelSimulation." + ::= { xATSTestingSimulatePowerFail 1 } + +xATSTestingSimulatePowerFailTimeRemaining OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates the time remaining in seconds, for a simulated power failure. + a value of zero indicates that simulated power failure is not active." + ::= { xATSTestingSimulatePowerFail 2 } + +-- The xATS Input Contact group + +xATSInputContactNumContacts OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of contacts supported by the ATS." + ::= { xATSInputContacts 1 } + +xATSInputContactTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input contact entries." + ::= { xATSInputContacts 2 } + +xATSInputContactTable OBJECT-TYPE + SYNTAX SEQUENCE OF XATSContactEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of contacts supported by the ATS. + The number of entries is contained in the + xATSInputContactTableSize OID." + ::= { xATSInputContacts 3 } + + xATSInputContactEntry OBJECT-TYPE + SYNTAX XATSContactEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A contact entry containing information for a given contact." + INDEX { xATSInputContactNumber } + ::= { xATSInputContactTable 1 } + + XATSContactEntry ::= + SEQUENCE { + xATSInputContactNumber INTEGER, + xATSInputContactName DisplayString, + xATSInputContactNormalState INTEGER, + xATSInputContactCurrentState INTEGER + } + + xATSInputContactNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An index identifying the contact on the ATS." + ::= { xATSInputContactEntry 1 } + + xATSInputContactName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The description of the purpose/use of the contact." + ::= { xATSInputContactEntry 2 } + + xATSInputContactNormalState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The normal operating position of the contact." + ::= { xATSInputContactEntry 3 } + + xATSInputContactCurrentState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This value indicates the current state of the contact." + ::= { xATSInputContactEntry 4 } + +-- the xATS OutputRelays group + + xATSOutputRelayNumRelays OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output relays supported by the ATS." + ::= { xATSOutputRelays 1 } + + xATSOutputRelayTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output relay entries." + ::= { xATSOutputRelays 2 } + + xATSOutputRelayTable OBJECT-TYPE + SYNTAX SEQUENCE OF XATSOutputRelayEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of output relays supported by the ATS. + The number of entries is contained in the + xATSOutputRelayTableSize OID." + ::= { xATSOutputRelays 3 } + + xATSOutputRelayEntry OBJECT-TYPE + SYNTAX XATSOutputRelayEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A output relay entry containing information for a given contact." + INDEX { xATSOutputRelayNumber } + ::= { xATSOutputRelayTable 1 } + + XATSOutputRelayEntry ::= + SEQUENCE { + xATSOutputRelayNumber INTEGER, + xATSOutputRelayName DisplayString, + xATSOutputRelayNormalState INTEGER, + xATSOutputRelayCurrentState INTEGER + } + + xATSOutputRelayNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An index identifying the output relay on the ATS." + ::= { xATSOutputRelayEntry 1 } + + xATSOutputRelayName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The description of the purpose/use of the output relay." + ::= { xATSOutputRelayEntry 2 } + + xATSOutputRelayNormalState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The normal operating position of the output relay." + ::= { xATSOutputRelayEntry 3 } + + xATSOutputRelayCurrentState OBJECT-TYPE + SYNTAX INTEGER { + open (1), + closed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This value indicates the current state of the output relay." + ::= { xATSOutputRelayEntry 4 } + +-- The xATS Generator Ident group + +xATSGeneratorIdentModelNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the model number of the generator. + This value is set at the factory." + ::= { xATSGeneratorIdent 1 } + +xATSGeneratorIdentSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the serial number of the generator. + This value is set at the factory." + ::= { xATSGeneratorIdent 2 } + +xATSGeneratorIdentDateofManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying when the generator was manufactured in mm/dd/yyyy format. + This value is set at the factory." + ::= { xATSGeneratorIdent 3 } + +xATSGeneratorIdentVoltageConfiguration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The voltage for which the generator's alternator is designed. + Specified in Volts line-to-line." + ::= { xATSGeneratorIdent 4 } + +xATSGeneratorIdentMaxPowerRating OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The max power rating of the generator. Specified in kW." + ::= { xATSGeneratorIdent 5 } + +xATSGeneratorIdentAlternatorFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frequency for which the generator's alternator is designed. + Specified in Hertz." + ::= { xATSGeneratorIdent 6 } + +-- The xATS Generator Status group + +xATSGeneratorStatusGeneratorName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name or label for the generator connected to the source 2 of the ATS." + ::= { xATSGeneratorStatus 1 } + +xATSGeneratorStatusOperational OBJECT-TYPE + SYNTAX INTEGER{ + nocomm (1), + off (2), + ready (3), + starting (4), + idle (5), + running (6), + normalStop (7), + emergencyStop (8), + notInAuto (9), + shutdown (10), + unknown (11) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The operational status of the generator. unavailable when unrecognized status is received." + ::= { xATSGeneratorStatus 2 } + +xATSGeneratorStatusModeSwitchPosition OBJECT-TYPE + SYNTAX INTEGER{ + off (1), + manual (2), + automatic (3), + unknown (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The position of the generator's auto-mode switch. + In automatic mode, the generator is started and stopped via the + remote start contact, which has state indicated in the + xATSGeneratorStatusRemoteStart OID. + In manual mode generator start/stop control is via local command only. + Off prevents the generator from running." + ::= { xATSGeneratorStatus 3 } + +xATSGeneratorStatusRemoteStart OBJECT-TYPE + SYNTAX INTEGER{ + stop (1), + run (2), + unknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the generator's remote start contact, which is + provided as an output from the transfer switch to start/stop the + generator when in automatic mode." + ::= { xATSGeneratorStatus 4 } + +-- The xATS Generator Advanced Status group + +xATSGeneratorAdvStatusBatteryVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The voltage of the generator's starting battery. + Measured in tenths of VDC, or -1 if not available." + ::= { xATSGeneratorAdvStatus 1 } + +xATSGeneratorAdvStatusOilPressure OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The generator's engine oil pressure. + Measured in tenths of Psi or kPa, based on the + value of the xATSGeneratorSettingsMetricUnit OID, + or -1 if not available." + ::= { xATSGeneratorAdvStatus 2 } + +xATSGeneratorAdvStatusCoolantTemperature OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Current coolant temperature in the generator. + Measured in degrees Celsius or Fahrenheit, based on the + value of the xATSGeneratorSettingsMetricUnit OID, + or -1 if not available." + ::= { xATSGeneratorAdvStatus 3 } + +xATSGeneratorAdvStatusEngineRPM OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Current engine speed of the generator. + Measured in RPM, or -1 if not available." + ::= { xATSGeneratorAdvStatus 4 } + +xATSGeneratorAdvStatusOilLevel OBJECT-TYPE + SYNTAX INTEGER{ + ok (1), + low (2), + unknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates adequate oil level in the generator." + ::= { xATSGeneratorAdvStatus 5 } + +xATSGeneratorAdvStatusCoolantLevel OBJECT-TYPE + SYNTAX INTEGER{ + ok (1), + low (2), + unknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates adequate coolant level in the generator." + ::= { xATSGeneratorAdvStatus 6 } + +-- The xATS Generator Output group + +xATSGeneratorOutputFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output frequency of the generator. + Measured in tenths of Hertz, or -1 if not avaialble." + ::= { xATSGeneratorOutput 1 } + +xATSGeneratorOutputTotalPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total output power of the generator. + Measured in tenths of tenths of kW, or -1 if not avaialble." + ::= { xATSGeneratorOutput 2 } + +xATSGeneratorOutputTotalApparentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total output power of the generator. + Measured in tenths of kVA, or -1 if not avaialble." + ::= { xATSGeneratorOutput 3 } + +xATSGeneratorOutputTotalPowerFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates the total load power factor of the generator. + A value of 100 representing a unity power factor (1.00), + or -1 when if not avaialble." + ::= { xATSGeneratorOutput 4 } + +xATSGeneratorOutputTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of generator output phase entries." + ::= { xATSGeneratorOutput 5 } + + xATSGeneratorOutputTable OBJECT-TYPE + SYNTAX SEQUENCE OF XATSGeneratorOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of generator output table entries. + The number of entries is contained in the xATSGeneratorOutputTableSize OID." + ::= { xATSGeneratorOutput 6 } + + xATSGeneratorOutputPhaseEntry OBJECT-TYPE + SYNTAX XATSGeneratorOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular generator output phase." + INDEX { xATSGeneratorOutputPhaseIndex } + ::= { xATSGeneratorOutputTable 1 } + + XATSGeneratorOutputPhaseEntry ::= SEQUENCE { + xATSGeneratorOutputPhaseIndex INTEGER, + xATSGeneratorOutputVoltageLtoL INTEGER, + xATSGeneratorOutputVoltageLtoN INTEGER, + xATSGeneratorOutputPhaseCurrent INTEGER, + xATSGeneratorOutputPower INTEGER, + xATSGeneratorOutputApparentPower INTEGER, + xATSGeneratorOutputPowerFactor INTEGER + } + + xATSGeneratorOutputPhaseIndex OBJECT-TYPE + SYNTAX INTEGER{ + phase1(1), + phase2(2), + phase3(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Description of each generator output phase utilized in this device." + ::= { xATSGeneratorOutputPhaseEntry 1 } + + xATSGeneratorOutputVoltageLtoL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-line generator output voltage. + Measured in Volts, or -1 if not available." + ::= { xATSGeneratorOutputPhaseEntry 2 } + + xATSGeneratorOutputVoltageLtoN OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Line-to-neutral generator output voltage. + Measured in volts, or -1 if not avaialble." + ::= { xATSGeneratorOutputPhaseEntry 3 } + + xATSGeneratorOutputPhaseCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Generator load current per phase. + Measured in Amps, or -1 if not avaialble." + ::= { xATSGeneratorOutputPhaseEntry 4 } + + xATSGeneratorOutputPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Generator output power per phase. + Measured in tenths of kW, or -1 if not avaialble." + ::= { xATSGeneratorOutputPhaseEntry 5 } + + xATSGeneratorOutputApparentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Generator output power per phase. + Measured in tenths of kVA, or -1 if not available." + ::= { xATSGeneratorOutputPhaseEntry 6 } + + xATSGeneratorOutputPowerFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates the load power factor of the generator output per phase. + A value of 100 representing a unity power factor (1.00), + or -1 if not avaialble." + ::= { xATSGeneratorOutputPhaseEntry 7 } + +-- xATS Generator Settings group + +xATSGeneratorSettingsVoltageAdjust OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The voltage adjust of the generator. + Specified in volts line-to-line, + or -1 if not available." + ::= { xATSGeneratorSettings 1 } + +xATSGeneratorSettingsFrequencyAdjust OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frequency adjust of the generator. + Specified in tenths of Hertz." + ::= { xATSGeneratorSettings 2 } + +xATSGeneratorSettingsStartDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The delay, in seconds, after the remote run signal is activated + before the generator's engine will be cranked to start, + or -1 if not available." + ::= { xATSGeneratorSettings 3 } + +xATSGeneratorSettingsStopDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The delay, in seconds, before the generator will stop + after the remote run signal is deactivated, + or -1 if not available." + ::= { xATSGeneratorSettings 4 } + +xATSGeneratorSettingsCrankCycleEnable OBJECT-TYPE + SYNTAX INTEGER{ + disabled (1), + enabled (2), + unknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "When Crank Cycle is enabled, the engine will be cranked up to the time + specified by the xATSGeneratorSettingsCrankTime OID. + If the generator's engine does not start, there will be a pause as + specified by the xATSGeneratorSettingsCrankRestTime OID before the + engine will be cranked again. This cycle is repeated as specified by + the xATSGeneratorSettingsNumberCrank OID. + When crank cycle is disabled, the generator's engine will be + cranked continuously until it starts." + ::= { xATSGeneratorSettings 5 } + +xATSGeneratorSettingsCrankTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The duration of engine cranking, in seconds, when starting the generator. + Applicable when the xATSGeneratorSettingsCrankCycleEnable OID is enabled. + -1 if not available." + ::= { xATSGeneratorSettings 6 } + +xATSGeneratorSettingsCrankRestTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The pause duration, in seconds, following an unsuccessful attempt to start the generator. + Applicable when the xATSGeneratorSettingsCrankCycleEnable OID is enabled. + -1 if not available." + ::= { xATSGeneratorSettings 7 } + +xATSGeneratorSettingsNumberCrank OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of failed crank attempts before giving up on starting the generator. + Applicable when the xATSGeneratorSettingsCrankCycleEnable OID is enabled. + -1 if not available." + ::= { xATSGeneratorSettings 8 } + +xATSGeneratorSettingsMetricUnit OBJECT-TYPE + SYNTAX INTEGER{ + disabled (1), + enabled (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Specifies the use of metric units in generator related OIDs, as well + as on all other interfaces including the generator's local interface." + ::= { xATSGeneratorSettings 9 } + +-- xATS generator service group + +xATSGeneratorServiceTotalRunHoursLifetime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Total time that the generator engine has been run, + over the life of the generator. Measured in hours. + -1 if not available." + ::= { xATSGeneratorService 1 } + +xATSGeneratorServiceEngineStartsLifetime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Number of engine starts over the life of the generator. + -1 if not available." + ::= { xATSGeneratorService 2 } + +xATSGeneratorServiceTotalkWhLifetime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Total kWh of operation over the life of the generator. + -1 if not available." + ::= { xATSGeneratorService 3 } + +xATSGeneratorServiceTotalRunHoursSinceMaintanence OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Total time that the generator engine has been run, + since last service maintenance. Measured in tenths of hours. + -1 if not available." + ::= { xATSGeneratorService 4 } + +xATSGeneratorServiceEngineStartsSinceMaintanence OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Number of engine starts since last service maintenance. + -1 if not available." + ::= { xATSGeneratorService 5 } + +xATSGeneratorServiceTotalkWhMaintanence OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Total kWh of operation since last service maintenance. + -1 if not available." + ::= { xATSGeneratorService 6 } + +xATSGeneratorServiceResetRecord OBJECT-TYPE + SYNTAX INTEGER{ + yes (1), + no (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Resets the engine start counter, engine run-hours, and kWh values that have + accumulated in the generator since last maintenance. + Also, the last service date will be reset to the current system date, and + any service alarms will be cleared." + ::= { xATSGeneratorService 7 } + +xATSGeneratorServiceRecordResetDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Date at which the generator's service record was reset, in dd-mmm-yyyy format." + ::= { xATSGeneratorService 8 } + +xATSGeneratorServiceNextServiceDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Date at which the next generator service is due in dd-mmm-yyyy format. + Based on the xATSGeneratorServiceCalendarIntervalThreshold OID + or '' if the calander-based threshold is set to off." + ::= { xATSGeneratorService 9 } + +xATSGeneratorServiceRunHoursUntilServiceDate OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Runhours until the next generator service is due, in hours. + Based on the xATSGeneratorServiceRunHoursThreshold OID + or -1 if the runhour-based threshold is set to off." + ::= { xATSGeneratorService 10 } + +xATSGeneratorServiceRunHoursThreshold OBJECT-TYPE + SYNTAX INTEGER{ + disabled (1), + runThreshold100Hours (2), + runThreshold150Hours (3), + runThreshold200Hours (4), + runThreshold250Hours (5), + runThreshold300Hours (6), + runThreshold400Hours (7), + runThreshold500Hours (8) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Runhour-based service interval. When the run-hours since + service surpasses this threshold, generator service is due." + ::= { xATSGeneratorService 11 } + +xATSGeneratorServiceCalendarIntervalThreshold OBJECT-TYPE + SYNTAX INTEGER{ + disabled (1), + interval1month (2), + interval2month (3), + interval3month (4), + interval6month (5), + intervalyearly (6) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Calander-based service interval. When the next service date, + as indicated by the xATSGeneratorServiceNextServiceDate OID + is in the past, generator is due for service." + ::= { xATSGeneratorService 12 } + +-- The xATS Generator Fuel system group + +xATSGeneratorFuelSystemType OBJECT-TYPE + SYNTAX INTEGER{ + diesel (1), + propane (2), + naturalGas (3), + unknown (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The type of fuel used by the generator." + ::= { xATSGeneratorFuelSystem 1 } + +xATSGeneratorFuelSystemTankSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Size of the generator's fuel tank. + Specified in gallons or liters, based on the value of the + xATSGeneratorSettingsMetricUnit OID, or -1 if not available." + ::= { xATSGeneratorFuelSystem 2 } + +xATSGeneratorFuelSystemFuelLevel OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Fuel remaining in the generator tank. + Measured in percent of tank fill, or -1 if if not available." + ::= { xATSGeneratorFuelSystem 3 } + +xATSGeneratorFuelSystemRuntimePower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The power value used in the runtime remaining calculation. + Measured in tenths of kW, or -1 if not available." + ::= { xATSGeneratorFuelSystem 4 } + +xATSGeneratorFuelSystemEstimatedRunTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An estimate of available runtime for the generator, based on + available fuel as specified in the xATSGeneratorFuelSystemFuelLevel OID + and kW load as specified in the xATSGeneratorFuelSystemRuntimePower OID. + Measured in tenths of hours, or -1 if not available." + ::= { xATSGeneratorFuelSystem 5 } + +xATSGeneratorFuelSystemLowRunTimeThreshold OBJECT-TYPE + SYNTAX INTEGER{ + disabled (1), + oneHour (2), + twoHours (3), + threeHours (4), + fourHours (5), + fiveHours (6), + sixHours (7), + twelveHours (8), + oneDay (9), + twoDays (10), + threeDays (11), + fourDays (12), + fiveDays (13), + sixDays (14), + sevenDays (15) + + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which a low runtime alarm will exist." + ::= { xATSGeneratorFuelSystem 6 } + +xATSGeneratorFuelSystemVeryLowRunTimeThreshold OBJECT-TYPE + SYNTAX INTEGER{ + disabled (1), + oneHour (2), + twoHours (3), + threeHours (4), + fourHours (5), + fiveHours (6), + sixHours (7), + twelveHours (8), + oneDay (9), + twoDays (10), + threeDays (11), + fourDays (12), + fiveDays (13), + sixDays (14), + sevenDays (15) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which a very low runtime alarm will exist." + ::= { xATSGeneratorFuelSystem 7 } + +xATSGeneratorFuelSystemLowFuelLevelThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which a low fuel alarm will exist, with a value of 0 indicating disabled. + Specified as percent of tank fill." + ::= { xATSGeneratorFuelSystem 8 } + +xATSGeneratorFuelSystemVeryLowFuelLevelThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold below which a very low fuel alarm will exist, with a value of 0 indicating disabled. + Specified as percent of tank fill." + ::= { xATSGeneratorFuelSystem 9 } + +-- the software group +-- the powerNetSubAgent group +-- the powerNetSoftwareSystem group + +powerNetSoftwareSystemDescription OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..79)) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A brief description of the PowerNet sub-agent." + ::= { powerNetSoftwareSystem 1 } + +powerNetSoftwareOid OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The object identifier of the PowerNet sub-agent." + ::= { powerNetSoftwareSystem 2 } + +-- powerNetSmuxPeer OBJECT IDENTIFIER ::= { powerNetSoftwareOid 1 } +-- powerNetDPIPeer OBJECT IDENTIFIER ::= { powerNetSoftwareOid 2 } + +powerNetSoftwareSystemUpTime OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The time that the sub-agent has been running." + ::= { powerNetSoftwareSystem 3 } + + +-- powerNetSoftwareConfig group + +powerNetSoftwareTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of software modules supporting the UPS." + ::= { powerNetSoftwareConfig 1 } + +powerNetSoftwareTable OBJECT-TYPE + SYNTAX SEQUENCE OF SoftwareEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of the software monitoring the UPS." + ::= { powerNetSoftwareConfig 2 } + +powerNetSoftwareEntry OBJECT-TYPE + SYNTAX SoftwareEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information on a software module." + INDEX { moduleNumber } + ::= { powerNetSoftwareTable 1 } + +SoftwareEntry ::= + SEQUENCE { + moduleNumber + INTEGER, + moduleName + DisplayString, + moduleVersion + DisplayString, + moduleDate + DisplayString + } + +moduleNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index into the Software Entry Table" + ::= { powerNetSoftwareEntry 1 } + +moduleName OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..79)) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the software module." + ::= { powerNetSoftwareEntry 2 } + +moduleVersion OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..8)) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The version of the software module." + ::= { powerNetSoftwareEntry 3 } + +moduleDate OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..9)) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date of the software module represented as mm-dd-yy." + ::= { powerNetSoftwareEntry 4 } + + +-- the ups group +-- the upsIdent group +-- the upsBasicIdent + +upsBasicIdentModel OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The UPS model name (e.g. 'APC Smart-UPS 600')." + ::= { upsBasicIdent 1 } + +upsBasicIdentName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An 8 byte ID string identifying the UPS. This object + can be set by the administrator." + ::= { upsBasicIdent 2 } + + +-- the upsAdvIdent group + +upsAdvIdentFirmwareRevision OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the UPS system's microprocessor." + ::= { upsAdvIdent 1 } + +upsAdvIdentDateOfManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date when the UPS was manufactured in mm/dd/yy format." + ::= { upsAdvIdent 2 } + +upsAdvIdentSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An 8-character string identifying the serial number of + the UPS internal microprocessor. This number is set at + the factory. NOTE: This number does NOT correspond to + the serial number on the rear of the UPS." + ::= { upsAdvIdent 3 } + + + +-- the upsBattery group +-- the upsBasicBattery group + +upsBasicBatteryStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + batteryNormal(2), + batteryLow(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the UPS batteries. A batteryLow(3) + value indicates the UPS will be unable to sustain the + current load, and its services will be lost if power is + not restored. The amount of run time in reserve at the + time of low battery can be configured by the + upsAdvConfigLowBatteryRunTime." + ::= { upsBasicBattery 1 } + +upsBasicBatteryTimeOnBattery OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The elapsed time since the UPS has switched to battery + power." + ::= { upsBasicBattery 2 } + +upsBasicBatteryLastReplaceDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The date when the UPS system's batteries were last replaced + in mm/dd/yy format. For Smart-UPS models, this value + is originally set in the factory. When the UPS batteries + are replaced, this value should be reset by the administrator." + ::= { upsBasicBattery 3 } + + + +-- the upsAdvBattery group + +upsAdvBatteryCapacity OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The remaining battery capacity expressed in + percent of full capacity." + ::= { upsAdvBattery 1 } + +upsAdvBatteryTemperature OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current internal UPS temperature expressed in + Celsius." + ::= { upsAdvBattery 2 } + +upsAdvBatteryRunTimeRemaining OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The UPS battery run time remaining before battery + exhaustion." + ::= { upsAdvBattery 3 } + +upsAdvBatteryReplaceIndicator OBJECT-TYPE + SYNTAX INTEGER { + noBatteryNeedsReplacing(1), + batteryNeedsReplacing(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Indicates whether the UPS batteries need replacing." + ::= { upsAdvBattery 4 } + +upsAdvBatteryNumOfBattPacks OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of external battery packs connected to the UPS. If + the UPS does not use smart cells then the agent reports + ERROR_NO_SUCH_NAME." + ::= { upsAdvBattery 5 } + +upsAdvBatteryNumOfBadBattPacks OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of external battery packs connected to the UPS that + are defective. If the UPS does not use smart cells then the + agent reports ERROR_NO_SUCH_NAME." + ::= { upsAdvBattery 6 } + +upsAdvBatteryNominalVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The nominal battery voltage in Volts." + ::= { upsAdvBattery 7 } + +upsAdvBatteryActualVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The actual battery bus voltage in Volts." + ::= { upsAdvBattery 8 } + +upsAdvBatteryCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery current in Amps." + ::= { upsAdvBattery 9 } + +upsAdvTotalDCCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total DC current in Amps." + ::= { upsAdvBattery 10 } + + +-- the upsBasicInput group + +upsBasicInputPhase OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current AC input phase." + ::= { upsBasicInput 1 } + + +-- the upsAdvInput group + +upsAdvInputLineVoltage OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current utility line voltage in VAC." + ::= { upsAdvInput 1 } + +upsAdvInputMaxLineVoltage OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum utility line voltage in VAC over the + previous 1 minute period." + ::= { upsAdvInput 2 } + +upsAdvInputMinLineVoltage OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum utility line voltage in VAC over the + previous 1 minute period." + ::= { upsAdvInput 3 } + +upsAdvInputFrequency OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current input frequency to the UPS system in Hz." + ::= { upsAdvInput 4 } + + +upsAdvInputLineFailCause OBJECT-TYPE + SYNTAX INTEGER { + noTransfer(1), + highLineVoltage(2), + brownout(3), + blackout(4), + smallMomentarySag(5), + deepMomentarySag(6), + smallMomentarySpike(7), + largeMomentarySpike(8), + selfTest(9), + rateOfVoltageChnage(10) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The reason for the occurrence of the last transfer to UPS + battery power. The variable is set to: + - noTransfer(1) -- if there is no transfer yet. + - highLineVoltage(2) -- if the transfer to battery is caused + by an over voltage greater than the high transfer voltage. + - brownout(3) -- if the duration of the outage is greater than + five seconds and the line voltage is between 40% of the + rated output voltage and the low transfer voltage. + - blackout(4) -- if the duration of the outage is greater than five + seconds and the line voltage is between 40% of the rated + output voltage and ground. + - smallMomentarySag(5) -- if the duration of the outage is less + than five seconds and the line voltage is between 40% of the + rated output voltage and the low transfer voltage. + - deepMomentarySag(6) -- if the duration of the outage is less + than five seconds and the line voltage is between 40% of the + rated output voltage and ground. The variable is set to + - smallMomentarySpike(7) -- if the line failure is caused by a + rate of change of input voltage less than ten volts per cycle. + - largeMomentarySpike(8) -- if the line failure is caused by + a rate of change of input voltage greater than ten volts per cycle. + - selfTest(9) -- if the UPS was commanded to do a self test. + - rateOfVoltageChange(10) -- if the failure is due to the rate of change of + the line voltage." + ::= { upsAdvInput 5 } + + +-- the upsBasicOutput group + +upsBasicOutputStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + onLine(2), + onBattery(3), + onSmartBoost(4), + timedSleeping(5), + softwareBypass(6), + off(7), + rebooting(8), + switchedBypass(9), + hardwareFailureBypass(10), + sleepingUntilPowerReturn(11), + onSmartTrim(12) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current state of the UPS. If the UPS is unable + to determine the state of the UPS this variable is set + to unknown(1)." + ::= { upsBasicOutput 1 } + +upsBasicOutputPhase OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current output phase." + ::= { upsBasicOutput 2 } + + +-- the upsAdvOutput group + +upsAdvOutputVoltage OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output voltage of the UPS system in VAC." + ::= { upsAdvOutput 1 } + +upsAdvOutputFrequency OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current output frequency of the UPS system in Hz." + ::= { upsAdvOutput 2 } + +upsAdvOutputLoad OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current UPS load expressed in percent + of rated capacity." + ::= { upsAdvOutput 3 } + +upsAdvOutputCurrent OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current in amperes drawn by the load on the UPS." + ::= { upsAdvOutput 4 } + + +-- the upsBasicConfig group + +upsBasicConfigNumDevices OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of devices that are plugged into the UPS." + ::= { upsBasicConfig 1 } + +upsBasicConfigDeviceTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsBasicConfigDeviceEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of devices that are plugged into the UPS. + The number of entries is given by the value of + upsBasicConfigNumDevices." + ::= { upsBasicConfig 2 } + +upsBasicConfigDeviceEntry OBJECT-TYPE + SYNTAX UpsBasicConfigDeviceEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The devices plugged in to the UPS." + INDEX { deviceIndex } + ::= { upsBasicConfigDeviceTable 1 } + +UpsBasicConfigDeviceEntry ::= + SEQUENCE { + deviceIndex + INTEGER, + deviceName + DisplayString, + vaRating + INTEGER, + acceptThisDevice + INTEGER + } + +deviceIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the device that is plugged into the UPS." + ::= { upsBasicConfigDeviceEntry 1 } + +deviceName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name/description of the device plugged into the UPS." + ::= { upsBasicConfigDeviceEntry 2 } + +vaRating OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The volt-amp rating of the device plugged into the UPS." + ::= { upsBasicConfigDeviceEntry 3 } + +acceptThisDevice OBJECT-TYPE + SYNTAX INTEGER { + yes(1), + no(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An entry is added if yes, the entry is deleted if no." + ::= { upsBasicConfigDeviceEntry 4 } + + + + +-- the upsAdvConfig group + +upsAdvConfigRatedOutputVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The nominal output voltage from the UPS in VAC. + + For a list of allowed values supported by your UPS model, + see the UPS User's Manual. + + If a value other than a supported value is provided in a + set request, the UPS interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used." + ::= { upsAdvConfig 1 } + +upsAdvConfigHighTransferVolt OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The maximum line voltage in VAC allowed before the + UPS system transfers to battery backup. + + For a list of allowed values supported by your UPS model, + see the UPS User's Manual. + + If a value other than a supported value is provided in a + set request, the UPS interprets it as a the next higher + acceptable value. If the provided value is higher than + the highest acceptable value, the highest acceptable + value is used." + ::= { upsAdvConfig 2 } + +upsAdvConfigLowTransferVolt OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The minimum line voltage in VAC allowed before the + UPS system transfers to battery backup. + + For a list of allowed values supported by your UPS model, + see the UPS User's Manual. + + If a value other than a supported value is provided in a + set request, the UPS interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used." + ::= { upsAdvConfig 3 } + +upsAdvConfigAlarm OBJECT-TYPE + SYNTAX INTEGER { + timed(1), + atLowBattery(2), + never(3), + mute(4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A flag indicating how the UPS should handle audible + line fail alarms: + timed(1): UPS alarm will sound after a preset timed duration starting + from the line fail condition (see OID upsAdvConfigAlarmTimer for the + alarm timer value) + atLowBattery(2): UPS alarm will sound when the UPS has reached a Low + Battery condition during a line fail + never(3): Disables the UPS audible alarm + mute(4): Mutes the current alarm for some UPSs only when it is in an + alarm state and will return to the previously configured option when + the UPS recovers from the alarm condition" + ::= { upsAdvConfig 4 } + +upsAdvConfigAlarmTimer OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The time after initial line failure at which the UPS + begins emitting audible alarms (beeping). This timer is + observed only if the value of extControlAlarm is timed(2). + Allowed values are 0 or 30 seconds. + + If a value other than a supported value is provided in a + set request, the UPS interprets it as a the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used." + ::= { upsAdvConfig 5 } + +upsAdvConfigMinReturnCapacity OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The minimum battery capacity required before the UPS will + return from a low battery shutdown condition. The capacity is + measured from 0% battery capacity (or Low Battery) as a percent + of full capacity (100%). In other words, the UPS will not re-energize + the output until the battery has charged so that its' capacity is equal + to this value. + + For a list of allowed values supported by your UPS model, + see the UPS User's Manual. + + If a value other than a supported value is provided in a + set request, the UPS interprets it as a the next higher + acceptable value. If the provided value is higher than + the highest acceptable value, the highest acceptable + value is used." + ::= { upsAdvConfig 6 } + +upsAdvConfigSensitivity OBJECT-TYPE + SYNTAX INTEGER { + auto(1), + low(2), + medium(3), + high(4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The sensitivity of the UPS to utility line abnormalities + or noises." + ::= { upsAdvConfig 7 } + +upsAdvConfigLowBatteryRunTime OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The desired run time of the UPS, in seconds, once the + low battery condition is reached. During this time the UPS will + produce a constant warning tone which can not be disabled. + + For a list of allowed values supported by your UPS model, + see the UPS User's Manual. + + If a value other than a supported value is provided in a set + request, the UPS interprets the value as the next higher + acceptable value. If the provided value is higher than the + highest acceptable value, the highest acceptable value is used." + ::= { upsAdvConfig 8 } + +upsAdvConfigReturnDelay OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The delay in seconds after utility line power returns + before the UPS will turn on. This value is also used + when the UPS comes out of a reboot and before the UPS + wakes up from 'sleep' mode. + + For a list of allowed values supported by your UPS model, + see the UPS User's Manual. + + If a value other than a supported value is provided in a + set request, the UPS interprets it as a the next higher + acceptable value. If the provided value is higher than + the highest acceptable value, the highest acceptable + value is used." + ::= { upsAdvConfig 9 } + +upsAdvConfigShutoffDelay OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The delay in seconds the UPS remains on after being told + to turn off. + + For a list of allowed values supported by your UPS model, + see the UPS User's Manual. + + If a value other than a supported value is provided in a + set request, the UPS interprets it as a the next higher + acceptable value. If the provided value is higher than + the highest acceptable value, the highest acceptable + value is used." + ::= { upsAdvConfig 10 } + +upsAdvConfigUpsSleepTime OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The time in seconds for the UPS to go to 'sleep' when + instructed. When in sleep mode, the UPS will not provide + output power regardless of the input line state. Once the + specified time has elapsed, output power will be restored. + + This is a configuration setting. The UPS will not go to + sleep until told to do so by the manager from a management + station. + + Any input value is allowed, however the UPS only recognizes + 1/10 of an hour increments. The provided value will be + rounded to the closest 1/10 of an hour with one exception: + Any value entered between 1 and 540 seconds will be rounded + to 360 seconds (or 6 minutes)." + ::= { upsAdvConfig 11 } + + +upsAdvConfigSetEEPROMDefaults OBJECT-TYPE + SYNTAX INTEGER { + noSetEEPROMDefaults(1), + setEEPROMDefaults(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "WRITE: Resets the UPS EEPROM variables to default values. + READ: returns 0" + ::= { upsAdvConfig 12 } + +upsAdvConfigDipSwitchSetting OBJECT-TYPE + SYNTAX SEQUENCE OF UpsAdvConfigDipSwitchEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Current settings of UPS dip switches." + ::= { upsAdvConfig 13 } + +upsAdvConfigDipSwitchEntry OBJECT-TYPE + SYNTAX UpsAdvConfigDipSwitchEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The current setting of one dip switch." + INDEX { dipSwitchIndex } + ::= { upsAdvConfigDipSwitchSetting 1 } + +UpsAdvConfigDipSwitchEntry ::= + SEQUENCE { + dipSwitchIndex + INTEGER, + dipSwitchStatus + INTEGER + } + +dipSwitchIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of a UPS dip switch." + ::= { upsAdvConfigDipSwitchEntry 1 } + +dipSwitchStatus OBJECT-TYPE + SYNTAX INTEGER { + on(1), + off(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The setting of a UPS dip switch." + ::= { upsAdvConfigDipSwitchEntry 2 } + +upsAdvConfigBattExhaustThresh OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The number of seconds prior to battery exhaustion when the + UPS will switch off power to its load." + ::= { upsAdvConfig 14 } + +upsAdvConfigPassword OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The password entered at the UPS front panel to enable local + configuration of the EEProm. If the password is disabled or + is not supported, then the agent returns a null string." + ::= { upsAdvConfig 15 } + +upsAdvConfigAllowedSetTable OBJECT-TYPE + SYNTAX SEQUENCE OF ApcUpsConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The table listing the allowed values for all discrete + configurable UPS variables." + ::= { upsAdvConfig 16 } + +apcUpsConfigEntry OBJECT-TYPE + SYNTAX ApcUpsConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The table entry for a configurable UPS variable." + INDEX { apcUpsConfigFieldIndex } + ::= { upsAdvConfigAllowedSetTable 1 } + +ApcUpsConfigEntry ::= SEQUENCE { + apcUpsConfigFieldIndex INTEGER, + apcUpsConfigFieldOID OBJECT IDENTIFIER, + apcUpsConfigFieldValueRange DisplayString + } + +apcUpsConfigFieldIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to an eeprom field entry." + ::= { apcUpsConfigEntry 1 } + +apcUpsConfigFieldOID OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The OID of the current configurable value." + ::= { apcUpsConfigEntry 2 } + +apcUpsConfigFieldValueRange OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The discrete set of allowed values of a configurable + register. Individual values are delimited by a comma." + ::= { apcUpsConfigEntry 3 } + +upsAdvConfigBattCabAmpHour OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure settings of UPS battery cabinet amp hour setting." + ::= { upsAdvConfig 17 } + +upsAdvConfigPositionSelector OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + rack (2), + tower (3) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure UPS position selector. If the UPS doesn't + support this configuration it will report unknown (1). + The positions are either rack (2) for rack mounted or + tower (3) for tower unit." + ::= { upsAdvConfig 18 } + +upsAdvConfigOutputFreqRange OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + freqRangeAUTO (2), + freqRange60Var1 (3), + freqRange60Var3 (4), + freqRange50Var1 (5), + freqRange50Var3 (6), + freqRange60Var10 (7), + freqRange50Var10 (8) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure the output frequency tolerance range. + unknown(1) indicates the output frequency is unknown. + freqRangeAUTO(2) configure the output frequency range for automatic. + freqRange60Var1(3) configure the output frequency range for 60 +/- 0.1 Hz + freqRange60Var3(4) configure the output frequency range for 60 +/- 3.0 Hz + freqRange50Var1(5) configure the output frequency range for 50 +/- 0.1 Hz + freqRange50Var3(6) configure the output frequency range for 50 +/- 3.0 Hz + freqRange60Var10(7) configure the output frequency range for 60 +/- 10 Hz + freqRange50Var10(8) configure the output frequency range for 50 +/- 10 Hz" + ::= { upsAdvConfig 19 } + +upsAdvConfigUPSFail OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + gotoBypass (2), + dropLoad (3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure the UPS fail action. If UPS fails, + and frequency or voltage is out of range it will either + GotoBypass (2) or DropLoad (3). This OID will report + unknown (1) if it is not supported feature or option." + ::= { upsAdvConfig 20 } + +upsAdvConfigAlarmRedundancy OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure settings of UPS alarm if the redundancy is + under the current redundancy. Use -1 for never." + ::= { upsAdvConfig 21 } + +upsAdvConfigAlarmLoadOver OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure settings of UPS alarm if the load is + over the current load in kVA. Use -1 for never." + ::= { upsAdvConfig 22 } + +upsAdvConfigAlarmRuntimeUnder OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure settings of UPS alarm if the runtime is + under the current time of minutes. Use -1 for never." + ::= { upsAdvConfig 23 } + +upsAdvConfigVoutReporting OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + voutAUTO (2), + vout208 (3), + vout240 (4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure the way the UPS scales its output voltage readings. + unknown(1) indicates the Vout Reporting is unknown. + voutAUTO(2) configure the Vout Reporting for automatic scalling. + vout208(3) configure the Vout Reporting for 208 Volts. + vout240(4) configure the Vout Reporting for 240 Volts." + ::= { upsAdvConfig 24 } + +upsAdvConfigNumExternalBatteries OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure the number of external batteries connected to the UPS." + ::= { upsAdvConfig 25 } + +upsAdvConfigSimpleSignalShutdowns OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + disabled (2), + enabled (3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Configure Simple Signal shutdown commands from the Simple Signal + port to be issued to the UPS. + unknown(1) indicates the Simple Signal Shutdown setting is unknown. + disabled(2) configure to disable Simple Signal Shutdowns. + enabled(3) configure to enable Simple Signal Shutdowns." + ::= { upsAdvConfig 26 } + + +-- the upsSyncCtrlGroupConfig group + +upsSCGMembershipGroupNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The SCG Membership Group number (MGN) is a 16-bit number allowing + up to 65534 separate groups that can be identified and distinguished + per IP subnet. Zero and 65535 are not used. The MGN is used in all + communication between members of the SCG and a Network Management Card + (NMC) will listen and only respond to commands sent to it using its + configured SCG ID." + ::= { upsSyncCtrlGroupConfig 1 } + +upsSCGActiveMembershipStatus OBJECT-TYPE + SYNTAX INTEGER { + enabledSCG (1), + disabledSCG (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Membership in the configured SCG can be enabled and + disabled. If an NMC is configured for an SCG, but + has its membership disabled, all synchronized control commands + received will be ignored." + ::= { upsSyncCtrlGroupConfig 2 } + +upsSCGPowerSynchronizationDelayTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The Power Synchronization Delay Time (PSD) setting is the maximum + number of seconds an SCG Initiator will wait for all SCG members to + recover utility power before completing the reboot sequence of a + reboot or sleep command. If all SCG members are ready to proceed, + no additional delay is introduced." + ::= { upsSyncCtrlGroupConfig 3 } + +upsSCGReturnBatteryCapacityOffset OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A reboot command uses the Initiator’s Return battery Capacity (RBC) to control + when the SCG completes this operation. In a Normal Control Operation (NCC) the + UPS will only complete the reboot if RBC is reached. Due to normal battery + charge rate variations it may be desirable for the Followers to complete the + reboot if they are within some range of the Initiator’s RBC when the Initiator + is prepared (charged to RBC) to complete the reboot. The Return Battery + Capacity Offset (RBCO) defines a percent battery capacity subtracted from an + RBC above which a Follower’s battery must be charged for it to complete a + reboot. For example, if the Initiator’s RBC is 50% and the Initiator’s RBCO is + 5% then a Follower’s battery capacity is within range if it is greater or equal + to 45% (50% - 5%) at the time when the Initiator tries to complete the reboot + command. The default RBCO is 10%. " + ::= { upsSyncCtrlGroupConfig 4 } + +upsSCGMultiCastIP OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The MultiCast IP address of the SCG Group." + ::= { upsSyncCtrlGroupConfig 5 } + +-- the upsSyncCtrlGroupStatus group + +upsSCGNumOfGroupMembers OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of active, communicating members in the Sync Control Group (SCG). + This variable indicates the number of rows in the SCG Status Table." + ::= { upsSyncCtrlGroupStatus 1 } + +-- Sync Control Group Status Table + +upsSCGStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsSCGStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of SCG status table entries. The number of entries + is given by the value of upsSCGNumOfGroupMembers." + ::= { upsSyncCtrlGroupStatus 2 } + + upsSCGStatusEntry OBJECT-TYPE + SYNTAX UpsSCGStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular SCG Member." + INDEX { upsSCGStatusTableIndex } + ::= { upsSCGStatusTable 1 } + + UpsSCGStatusEntry ::= SEQUENCE { + upsSCGStatusTableIndex INTEGER, + upsSCGMemberIP IpAddress, + upsSCGACInputStatus INTEGER, + upsSCGACOutputStatus INTEGER + } + + upsSCGStatusTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of a status entry for an active, communicating SCG member." + ::= { upsSCGStatusEntry 1 } + + upsSCGMemberIP OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The IP address of an active, communicating SCG Member." + ::= { upsSCGStatusEntry 2 } + + upsSCGACInputStatus OBJECT-TYPE + SYNTAX INTEGER { + acInGood(1), + acInBad(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID indicates the AC Input Status of the SCG Member. + acInGood(1) indicates the AC Input is within tolerance. + acInBad(2) indicates the AC Input is not within tolerance." + ::= { upsSCGStatusEntry 3 } + + upsSCGACOutputStatus OBJECT-TYPE + SYNTAX INTEGER { + acOutOn(1), + acOutOff(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID indicates the AC Output Status of the SCG Member. + acOutOn(1) indicates the UPS output is providing power to the load. + acOutOff(2) indicates the UPS output is not providing power to the load. " + ::= { upsSCGStatusEntry 4 } + +-- the upsBasicState group + +upsBasicStateOutputState OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ASCII string containing the 64 flags representing + the current state(s) of the UPS. If the Network Card + is unable to determine the state of the UPS, this + variable is set to ‘UNKNOWN’. + + The flags are numbered 1 to 64, read from left to + right. The flags are defined as follows: + + Flag 1: Abnormal Condition Present + Flag 2: On Battery + Flag 3: Low Battery + Flag 4: On Line + + Flag 5: Replace Battery + Flag 6: Serial Communication Established + Flag 7: AVR Boost Active* + Flag 8: AVR Trim Active* + + Flag 9: Overload + Flag 10: Runtime Calibration + Flag 11: Batteries Discharged + Flag 12: Manual Bypass + + Flag 13: Software Bypass + Flag 14: In Bypass due to Internal Fault + Flag 15: In Bypass due to Supply Failure* + Flag 16: In Bypass due to Fan Failure* + + Flag 17: Sleeping on a Timer + Flag 18: Sleeping until Utility Power Returns + Flag 19: On + Flag 20: Rebooting + + Flag 21: Battery Communication Lost* + Flag 22: Graceful Shutdown Initiated + Flag 23: Smart Boost or Smart Trim Fault* + Flag 24: Bad Output Voltage* + + Flag 25: Battery Charger Failure* + Flag 26: High Battery Temperature + Flag 27: Self Test In Progress + Flag 28: Low Battery / On Battery + + Flag 29: Graceful Shutdown Issued by Upstream Device + Flag 30: Graceful Shutdown Issued by Downstream Device + Flag 31: No Batteries Attached* + Flag 32: Synchronized command is in progress + + Flag 33: <Not Used> + Flag 34: <Not Used> + Flag 35: <Not Used> + Flag 36: <Not Used> + + Flag 37: <Not Used> + Flag 38: <Not Used> + Flag 39: <Not Used> + Flag 40: <Not Used> + + Flag 41: <Not Used> + Flag 42: <Not Used> + Flag 43: <Not Used> + Flag 44: <Not Used> + + Flag 45: <Not Used> + Flag 46: <Not Used> + Flag 47: <Not Used> + Flag 48: <Not Used> + + Flag 49: <Not Used> + Flag 50: <Not Used> + Flag 51: <Not Used> + Flag 52: <Not Used> + + Flag 53: <Not Used> + Flag 54: <Not Used> + Flag 55: <Not Used> + Flag 56: <Not Used> + + Flag 57: <Not Used> + Flag 58: <Not Used> + Flag 59: <Not Used> + Flag 60: <Not Used> + + Flag 61: <Not Used> + Flag 62: <Not Used> + Flag 63: <Not Used> + Flag 64: <Not Used>" + + ::= { upsBasicState 1 } + +-- the upsAdvState group + +upsAdvStateAbnormalConditions OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ASCII string containing the 32 flags representing + the current active UPS faults. If the Network Card + is unable to determine the values of the flags, this + variable is set to ‘UNKNOWN’. If this variable is not + supported by the connected UPS, this variable is set to + ‘NOT SUPPORTED’. + + The flags are numbered from 1 to 32, and read from left to + right. The flags are defined as follows: + + Flag 1: Power Module Failure + Flag 2: Main Intelligence Module Failure + Flag 3: Redundant Intelligence Module Failure + Flag 4: Battery Failure + + Flag 5: Load(kVA) Alarm Threshold Violation + Flag 6: Redundancy Lost + Flag 7: Redundancy Below Alarm Threshold + Flag 8: Bypass notin Range; Either Frequency or Voltage + + Flag 9: Bypass Contactor Stuck in Bypass Condition + Flag 10: Bypass Contactor Stuck in On-Line Condition + Flag 11: In Bypass due to an Internal Fault + Flag 12: In Bypass due to an Overload + + Flag 13: In Maintanence Bypass + Flag 14: Input Circuit Braker Tripped Open + Flag 15: System Level Fan Failure + Flag 16: Redundant Intelligent Module in Control + + Flag 17: IIC Inter-Module Communication Failure + Flag 18: No Working Power Modules + Flag 19: Load Shutdown From Bypass; Input Frequency + Flag 20: Runtime Below Alarm Threshold + + Flag 21: Extended Run Frame Fault + Flag 22: Output Voltage out of Range + Flag 23: UPS Not Synchronized + Flag 24: No Batteries Installed + + Flag 25: Battery Voltage High + Flag 26: UPS Specific Fault Detected + Flag 27: Site Wiring Fault + Flag 28: Backfeed Protection Relay Opened + + Flag 29: <Not Used> + Flag 30: <Not Used> + Flag 31: <Not Used> + Flag 32: <Not Used>" + ::= { upsAdvState 1 } + +upsAdvStateSymmetra3PhaseSpecificFaults OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ASCII string containing the 64 flags representing + the current active UPS specific faults for the Symmetra + 3-Phase UPS models. If the Network Card is unable to + determine the values of the flags, this variable is set + to ‘UNKNOWN’. If the connected UPS does not use this + variable, it is set to ‘NOT SUPPORTED’. + + The flags are numbered from 1 to 64, and read from left + to right. The bits are defined as follows: + + Flag 1: External Switch Gear Failure + Flag 2: External Transformer Over Temperature + Flag 3: External DC Circuit Breaker Tripped + Flag 4: System Power Supply Failure + + Flag 5: Battery Monitor Card Failure + Flag 6: Battery Monitor Card Removed + Flag 7: XR Communication Card Failure + Flag 8: XR Communication Card Removed + + Flag 9: External Switch Gear Monitoring Card Failure + Flag 10: External Switch Gear Monitoring Card Removed + Flag 11: Internal DC Circiut Breaker Tripped + Flag 12: Static Bypass Switch Failure + + Flag 13: System EEPROM Removed + Flag 14: System EEPROM Failure + Flag 15: UPS in Forced Bypass + Flag 16: <Not Used> + + Flag 17: <Not Used> + Flag 18: <Not Used> + Flag 19: <Not Used> + Flag 20: <Not Used> + + Flag 21: <Not Used> + Flag 22: <Not Used> + Flag 23: <Not Used> + Flag 24: <Not Used> + + Flag 25: <Not Used> + Flag 26: <Not Used> + Flag 27: <Not Used> + Flag 28: <Not Used> + + Flag 29: <Not Used> + Flag 30: <Not Used> + Flag 31: <Not Used> + Flag 32: <Not Used> + + Flag 33: <Not Used> + Flag 34: <Not Used> + Flag 35: <Not Used> + Flag 36: <Not Used> + + Flag 37: <Not Used> + Flag 38: <Not Used> + Flag 39: <Not Used> + Flag 40: <Not Used> + + Flag 41: <Not Used> + Flag 42: <Not Used> + Flag 43: <Not Used> + Flag 44: <Not Used> + + Flag 45: <Not Used> + Flag 46: <Not Used> + Flag 47: <Not Used> + Flag 48: <Not Used> + + Flag 49: <Not Used> + Flag 50: <Not Used> + Flag 51: <Not Used> + Flag 52: <Not Used> + + Flag 53: <Not Used> + Flag 54: <Not Used> + Flag 55: <Not Used> + Flag 56: <Not Used> + + Flag 57: <Not Used> + Flag 58: <Not Used> + Flag 59: <Not Used> + Flag 60: <Not Used> + + Flag 61: <Not Used> + Flag 62: <Not Used> + Flag 63: <Not Used> + Flag 64: <Not Used>" + ::= { upsAdvState 2 } + +upsAdvStateDP300ESpecificFaults OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ASCII string containing the 64 flags representing + the current active UPS specific faults for the Silcon + DP300E UPS models. If the Network Card is unable to + determine the values of the flags, this variable is set + to ‘UNKNOWN’. If the connected UPS does not use this + variable, it is set to ‘NOT SUPPORTED’. + + The flags are numbered from 1 to 64, and read from left + to right. The bits are defined as follows: + + Flag 1: Peak Current Limiter Avtive + Flag 2: Bypass Power Supply Fault + Flag 3: Delta Current LImiter Active + Flag 4: Fan Fault + + Flag 5: High DC warning + Flag 6: Inverter Voltage Error + Flag 7: Parallel Synchronization Error + Flag 8: Second Power Supply Fault + + Flag 9: Internal Power Supply Fault + Flag 10: <Not Used> + Flag 11: <Not Used> + Flag 12: <Not Used> + + Flag 13: <Not Used> + Flag 14: Bypass Static Switch High Temperature + Flag 15: High Battery Temperature + Flag 16: Battery Weak + + Flag 17: <Not Used> + Flag 18: System Locked in Operation Mode + Flag 19: RAM1 Memory Write Error + Flag 20: Memory Write Error + + Flag 21: Communication to VQ Bypass Lost + Flag 22: Communication to VQ Output Lost + Flag 23: Communication to DMU Lost + Flag 24: Communication to Controller Lost + + Flag 25: Communication to Parallel IF Lost + Flag 26: External Shutdown Accepted + Flag 27: DC Capacitor Charge Error + Flag 28: Communication to VQ Mains Lost + + Flag 29: Bypass Synchronization Error + Flag 30: Charge Error + Flag 31: <Not Used> + Flag 32: <Not Used> + + Flag 33: <Not Used> + Flag 34: <Not Used> + Flag 35: <Not Used> + Flag 36: <Not Used> + + Flag 37: <Not Used> + Flag 38: <Not Used> + Flag 39: <Not Used> + Flag 40: <Not Used> + + Flag 41: <Not Used> + Flag 42: <Not Used> + Flag 43: <Not Used> + Flag 44: <Not Used> + + Flag 45: <Not Used> + Flag 46: <Not Used> + Flag 47: <Not Used> + Flag 48: <Not Used> + + Flag 49: <Not Used> + Flag 50: <Not Used> + Flag 51: <Not Used> + Flag 52: <Not Used> + + Flag 53: <Not Used> + Flag 54: <Not Used> + Flag 55: <Not Used> + Flag 56: <Not Used> + + Flag 57: <Not Used> + Flag 58: <Not Used> + Flag 59: <Not Used> + Flag 60: <Not Used> + + Flag 61: <Not Used> + Flag 62: <Not Used> + Flag 63: <Not Used> + Flag 64: <Not Used>" + ::= { upsAdvState 3 } + + +-- the upsBasicControl group + +upsBasicControlConserveBattery OBJECT-TYPE + SYNTAX INTEGER { + noTurnOffUps(1), + turnOffUpsToConserveBattery(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to turnUpsOffToConserveBattery(2) + causes a UPS on battery to be put into 'sleep' mode. The + UPS will turn back on when utility power is restored. + Attempting to turn off a UPS that is not on battery will + result in a badValue error. + + Setting this value to noTurnOffUps(1) has no + effect. + + The value noTurnOffUps(1) will always be returned + when the variable is read." +::= { upsBasicControl 1 } + + + +-- the upsAdvControl group + +upsAdvControlUpsOff OBJECT-TYPE + SYNTAX INTEGER { + noTurnUpsOff(1), + turnUpsOff(2), + turnUpsOffGracefully(3), + turnUpsSyncGroupOff(4), + turnUpsSyncGroupOffAfterDelay(5), + turnUpsSyncGroupOffGracefully(6) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to turnUpsOff(2) causes + the UPS to shut off. When in this state, the UPS + will not provide output power regardless of the input + line state. + + Setting this variable to turnUpsOffGracefully(3) causes + the UPS to shut off after a delay period. This allows the + host to shut down in a graceful manner. When in this state, + the UPS will not provide output power regardless of the + input line state. + + If this UPS is an active member of a Synchronized + Control Group (SCG) the turnUpsSyncGroupOff(4) command + will perform a Synchronized Turn Off of all active Group + members regardless of their current AC output status. + + If this UPS is an active member of a Synchronized + Control Group (SCG) the turnUpsSyncGroupOffAfterDelay(5) + command will perform a Synchronized Turn Off After Delay + of all active Group members regardless of their current + AC output status. This unit's Shutdown Delay will be used + to execute the Turn Off After Delay command. + + If this UPS is an active member of an SCG, the + turnUpsSyncGroupOffGracefully(6) command will perform a + Synchronized Turn Off Gracefully of all active Group + members regardless of their current AC output status. + This unit's Maximum Shutdown Time and Shutdown Delay will + be used to execute the Turn Off Gracefully command. + + Setting this value to noTurnUpsOff(1) has no + effect. + + The value noTurnUpsOff(1) will always be returned + when the variable is read." + ::= { upsAdvControl 1 } + +upsAdvControlRebootUps OBJECT-TYPE + SYNTAX INTEGER { + noRebootUps(1), + rebootUps(2), + rebootUpsGracefully(3), + rebootSyncGroupUps(4), + rebootSyncGroupUpsGracefully(5) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to rebootUps(2) causes the + UPS to shut off and turn back on. + + Setting this variable to rebootUpsGracefully(3) causes the + UPS to shut off and turn back on after a delay period. + This allows the host to shut down in a graceful manner. + + If this UPS is an active member of a Synchronized Control + Group (SCG) the rebootSyncGroupUps(4) command will perform + a Synchronized Reboot of all active Group members regardless + of their current AC output status. This unit's Power + Synchronization Delay, Shutdown Delay, Return Delay, + Return Battery Capacity, and Return Battery Capacity Offset + will be used to execute the Reboot command. + + If this UPS is an active member of a SCG the + rebootSyncGroupUpsGracefully(5) command will perform a + Synchronized Reboot of all active Group members regardless + of their current AC output status. This unit's Power + Synchronization Delay, Maximum Shutdown Time, + Shutdown Delay, Return Delay, Return Battery Capacity, and + Return Battery Capacity Offset will be used + to execute the Reboot command. + + Setting this value to noRebootUps(1) has no effect. + + The value noRebootUps(1) will always be returned + when the variable is read." + ::= { upsAdvControl 2 } + +upsAdvControlUpsSleep OBJECT-TYPE + SYNTAX INTEGER { + noPutUpsToSleep(1), + putUpsToSleep(2), + putUpsToSleepGracefully(3), + putUpsSyncGroupToSleep(4), + putUpsSyncGroupToSleepGracefully(5) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to putUpsToSleep(2) causes + the UPS to go to sleep for the time specified by + upsAdvConfigUpsSleepTime. + + Setting this variable to putUpsToSleepGracefully(3) + causes the UPS to go to sleep for the time specified + by upsAdvConfigUpsSleepTime after a delay period. + This allows the host to shut down in a graceful manner. + + If this UPS is an active member of a Synchronized Control + Group (SCG), the putUpsSyncGroupToSleep(4) command will perform + a Synchronized Sleep of all active Group members regardless + of their current AC output status. This unit's Power + Synchronization Delay, Shutdown Delay, Sleep Time, + and Return Delay will be used to execute the sleep command. + + If this UPS is an active member of a SCG the + putUpsSyncGroupToSleepGracefully(5) command will perform a + Synchronized Sleep Gracefully of all active Group members + regardless of their current AC output status. This unit's + Power Synchronization Delay, Maximum Shutdown Time, Shutdown + Delay, Sleep Time, and Return Delay to execute the sleep + command. + + When in sleep mode, the UPS will not provide output + power regardless of the input line state. Once the + specified time has elapsed, output power will be + restored. + + Setting this value to noPutUpsToSleep(1) has no + effect. + + The value noPutUpsToSleep(1) will always be returned + when the variable is read." + ::= { upsAdvControl 3 } + + +upsAdvControlSimulatePowerFail OBJECT-TYPE + SYNTAX INTEGER { + noSimulatePowerFailure(1), + simulatePowerFailure(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to simulatePowerFailure(2) causes + the UPS switch to battery power. + + Setting this value to noSimulatePowerFailure(1) has no + effect. + + The value noSimulatePowerFailure(1) will always be returned + when the variable is read." + ::= { upsAdvControl 4 } + + +upsAdvControlFlashAndBeep OBJECT-TYPE + SYNTAX INTEGER { + noFlashAndBeep(1), + flashAndBeep(2), + flashAndBeepSyncGroup(3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to flashAndBeep(2) causes the + UPS to beep and simultaneously turn on the UPS front + panel lights (Smart-UPS only). + + If this UPS is an active member of a Synchronized Control + Group (SCG), the flashAndBeepSyncGroup(3) command will + Flash and Beep all active Group members regardless of + current AC output status. + + Setting this value to noFlashAndBeep(1) has no + effect. + + The value noFlashAndBeep(1) will always be returned + when the variable is read." + ::= { upsAdvControl 5 } + + +upsAdvControlTurnOnUPS OBJECT-TYPE + SYNTAX INTEGER { + noTurnOnUPS(1), + turnOnUPS(2), + turnOnUPSSyncGroup(3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to turnOnUPS(2) causes the + UPS to be turned on immediately. + + If this UPS is an active member of a Synchronized Control + Group (SCG), the turnOnUPSSyncGroup(3) command will perform + a Synchronized Turn On of all active Group members + regardless of their current AC output status. + + Setting this value to noTurnOnUPS(1) has no + effect. + + The value noTurnOnUPS(1) will always be returned + when the variable is read." + ::= { upsAdvControl 6 } + +upsAdvControlBypassSwitch OBJECT-TYPE + SYNTAX INTEGER { + noBypassSwitch (1), + switchToBypass (2), + switchOutOfBypass(3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This switch puts the UPS in or out of bypass mode." + ::= { upsAdvControl 7 } + + +-- the upsTest group + +-- the upsBasicTest group + +-- the upsAdvTest group + +upsAdvTestDiagnosticSchedule OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + biweekly(2), + weekly(3), + atTurnOn(4), + never(5) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The UPS system's automatic battery test schedule." + ::= { upsAdvTest 1 } + + +upsAdvTestDiagnostics OBJECT-TYPE + SYNTAX INTEGER { + noTestDiagnostics(1), + testDiagnostics(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to testDiagnostics(2) causes + the UPS to perform a diagnostic self test. + + Setting this value to noTestDiagnostics(1) has no + effect. + + The value noTestDiagnostics(1) will always be returned + when the variable is read." + ::= { upsAdvTest 2 } + +upsAdvTestDiagnosticsResults OBJECT-TYPE + SYNTAX INTEGER { + ok(1), + failed(2), + invalidTest(3), + testInProgress(4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The results of the last UPS diagnostics test performed." + ::= { upsAdvTest 3 } + +upsAdvTestLastDiagnosticsDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date the last UPS diagnostics test was performed in + mm/dd/yy format." + ::= { upsAdvTest 4 } + +upsAdvTestRuntimeCalibration OBJECT-TYPE + SYNTAX INTEGER { + noPerformCalibration(1), + performCalibration(2), + cancelCurrentCalibration(3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to performCalibration(2) causes + the UPS to discharge to calibrate the UPS. + The test will only start if the battery capacity is 100%. + The test runs until capacity is less than 25%. + + Setting this variable to cancelCurrentCalibration(3) + after setting performCalibration(2) will cancel the + current discharge. + + Setting this variable to noPerformCalibration(1) + will have no effect. + + The value noPerformCalibration(1) will always be returned + when the variable is read. + + The result of the calibration will be saved in + upsAdvTestCalibrationResult." + ::= { upsAdvTest 5 } + +upsAdvTestCalibrationResults OBJECT-TYPE + SYNTAX INTEGER { + ok(1), + invalidCalibration(2), + calibrationInProgress(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The results of the last runtime calibration. + + Value ok(1) means a successful runtime calibration. + + Value invalidCalibration(2) indicates last calibration did + not take place since the battery capacity was below + 100%. + + Value calibrationInProgress(3) means a calibration + is occurring now. " + ::= { upsAdvTest 6 } + +upsAdvTestCalibrationDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date the last UPS runtime calibration was + performed in mm/dd/yy format." + ::= { upsAdvTest 7 } + +-- the upsComm group + +upsCommStatus OBJECT-TYPE + SYNTAX INTEGER { + ok(1), + noComm(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of agent's communication with UPS. " + ::= { upsComm 1 } + + +-- the measureUps group +-- the Environ group + +mUpsEnvironAmbientTemperature OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The ambient temperature in Celsius for Probe 1." + ::= { mUpsEnviron 1 } + +mUpsEnvironRelativeHumidity OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The relative humidity as a percentage for Probe 1." + ::= { mUpsEnviron 2 } + + +mUpsEnvironAmbientTemperature2 OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The ambient temperature in Celsius for Probe 2." + ::= { mUpsEnviron 3 } + +mUpsEnvironRelativeHumidity2 OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The relative humidity as a percentage for Probe 2." + ::= { mUpsEnviron 4 } + +-- the mUpsContact group + +mUpsContactNumContacts OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of contacts supported by the Measure-UPS." + ::= { mUpsContact 1 } + +mUpsContactTable OBJECT-TYPE + SYNTAX SEQUENCE OF ContactEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of contacts supported by the Measure-UPS." + ::= { mUpsContact 2 } + +mUpsContactEntry OBJECT-TYPE + SYNTAX ContactEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A contact entry containing information for a given contact." + INDEX { contactNumber } + ::= { mUpsContactTable 1 } + +ContactEntry ::= + SEQUENCE { + contactNumber + INTEGER, + normalState + INTEGER, + description + DisplayString, + monitoringStatus + INTEGER, + currentStatus + INTEGER + } + +contactNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An index identifying the contact on the Measure-UPS." + ::= { mUpsContactEntry 1 } + +normalState OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + open(2), + closed(3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The normal operating position of the contact. If the normal + operating position cannot be set then it is controlled via the + dip switch on the Measure-UPS and is therefore read-only." + ::= { mUpsContactEntry 2 } + +description OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The description of the purpose/use of the contact." + ::= { mUpsContactEntry 3 } + +monitoringStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + enabled(2), + disabled(3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A flag indicating whether this contact is + monitored, or not." + ::= { mUpsContactEntry 4 } + +currentStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + noFault(2), + fault(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This value indicates the current state of the contact. + If the contact is not in its normal state. This value + is set to fault(2)." + ::= { mUpsContactEntry 5 } + +-- Three Phase Group + +-- +-- Reset Max/Min Values Group +-- + + upsPhaseResetMaxMinValues OBJECT-TYPE + SYNTAX INTEGER { + none (1), + reset (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Reset the maximum and minimum UPS values: + upsPhaseInputMaxVoltage, upsPhaseInputMinVoltage, + upsPhaseInputMaxCurrent, upsPhaseInputMinCurrent, + upsPhaseInputMaxPower, upsPhaseInputMinPower, + upsPhaseOutputMaxCurrent, upsPhaseOutputMinCurrent, + upsPhaseOutputMaxLoad, upsPhaseOutputMinLoad, + upsPhaseOutputMaxPercentLoad, upsPhaseOutputMinPercentLoad, + upsPhaseOutputMaxPower, upsPhaseOutputMinPower, + upsPhaseOutputMaxPercentPower, upsPhaseOutputMinPercentPower." + ::= { upsPhaseResetValues 1 } + +-- +-- Input Group +-- + +-- Number of Inputs + + upsPhaseNumInputs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input feeds to this device. + This variable indicates the number of rows in the + input table." + ::= { upsPhaseInput 1 } + +-- Input Table + + upsPhaseInputTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsPhaseInputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of input table entries. The number of entries + is given by the value of upsPhaseNumInputs." + ::= { upsPhaseInput 2 } + + upsPhaseInputEntry OBJECT-TYPE + SYNTAX UpsPhaseInputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular input." + INDEX { upsPhaseInputTableIndex } + ::= { upsPhaseInputTable 1 } + + UpsPhaseInputEntry ::= SEQUENCE { + upsPhaseInputTableIndex INTEGER, + upsPhaseNumInputPhases INTEGER, + upsPhaseInputVoltageOrientation INTEGER, + upsPhaseInputFrequency INTEGER, + upsPhaseInputType INTEGER, + upsPhaseInputName DisplayString + } + + upsPhaseInputTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input identifier." + ::= { upsPhaseInputEntry 1 } + + upsPhaseNumInputPhases OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input phases utilized in this + device. The sum of all the upsPhaseNumInputPhases + variable indicates the number of rows in the + input phase table." + ::= { upsPhaseInputEntry 2 } + + upsPhaseInputVoltageOrientation OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + singlePhase(2), + splitPhase(3), + threePhasePhaseToNeutral(4), + threePhasePhaseToPhase(5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input voltage orientation: + 1: unknown for this UPS + 2: singlePhase - phase 1 voltage is between Phase 1 + and Neutral. + 3: splitPhase - phase 1 voltage is between Phase 1 and + Neutral; phase 2 voltage is between Phase 2 and Neutral; + phase 3 voltage is between Phase 1 and Phase2. + 4: threePhasePhaseToNeutral - phase 1 voltage is between + Phase 1 and Neutral; phase 2 voltage is between Phase 2 + and Neutral; phase 3 voltage is between Phase3 and + Neutral. + 5: threePhasePhaseToPhase - phase 1 voltage is between + Phase 1 and Phase 2; phase 2 voltage is between Phase 2 + and Phase 3; phase 3 voltage is between Phase 3 and + Phase 1." + ::= { upsPhaseInputEntry 3 } + + upsPhaseInputFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input frequency in 0.1 Hertz, or -1 if it's unsupported + by this UPS." + ::= { upsPhaseInputEntry 4 } + + upsPhaseInputType OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + main(2), + bypass(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input type." + ::= { upsPhaseInputEntry 5 } + + upsPhaseInputName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A name given to a particular input." + ::= { upsPhaseInputEntry 6 } + +-- Input Phase Table + + upsPhaseInputPhaseTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsPhaseInputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of input table entries. The number of entries + is given by the sum of the upsPhaseNumInputPhases." + ::= { upsPhaseInput 3 } + + upsPhaseInputPhaseEntry OBJECT-TYPE + SYNTAX UpsPhaseInputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular input phase." + INDEX { upsPhaseInputPhaseTableIndex, upsPhaseInputPhaseIndex } + ::= { upsPhaseInputPhaseTable 1 } + + UpsPhaseInputPhaseEntry ::= SEQUENCE { + upsPhaseInputPhaseTableIndex INTEGER, + upsPhaseInputPhaseIndex INTEGER, + upsPhaseInputVoltage INTEGER, + upsPhaseInputMaxVoltage INTEGER, + upsPhaseInputMinVoltage INTEGER, + upsPhaseInputCurrent INTEGER, + upsPhaseInputMaxCurrent INTEGER, + upsPhaseInputMinCurrent INTEGER, + upsPhaseInputPower INTEGER, + upsPhaseInputMaxPower INTEGER, + upsPhaseInputMinPower INTEGER + } + + upsPhaseInputPhaseTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input identifier." + ::= { upsPhaseInputPhaseEntry 1 } + + upsPhaseInputPhaseIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input phase identifier." + ::= { upsPhaseInputPhaseEntry 2 } + + upsPhaseInputVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input voltage in VAC, or -1 if it's unsupported + by this UPS." + ::= { upsPhaseInputPhaseEntry 3 } + + upsPhaseInputMaxVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum input voltage in VAC measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseInputPhaseEntry 4 } + + upsPhaseInputMinVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum input voltage in VAC measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseInputPhaseEntry 5 } + + upsPhaseInputCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input current in 0.1 amperes, or -1 if it's + unsupported by this UPS." + ::= { upsPhaseInputPhaseEntry 6 } + + upsPhaseInputMaxCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum input current in 0.1 amperes measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseInputPhaseEntry 7 } + + upsPhaseInputMinCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum input current in 0.1 amperes measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseInputPhaseEntry 8 } + + upsPhaseInputPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input power in Watts, or -1 if it's unsupported + by this UPS." + ::= { upsPhaseInputPhaseEntry 9 } + + upsPhaseInputMaxPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum input power in Watts measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseInputPhaseEntry 10 } + + upsPhaseInputMinPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum input power in Watts measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseInputPhaseEntry 11 } + + -- + -- The Output group. + -- + + -- Number of Outputs + + upsPhaseNumOutputs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output feeds to this device. + This variable indicates the number of rows in the + output table." + ::= { upsPhaseOutput 1 } + + -- Output Table + + upsPhaseOutputTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsPhaseOutputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of output table entries. The number of entries + is given by the value of upsOutputNumPhases." + ::= { upsPhaseOutput 2 } + + upsPhaseOutputEntry OBJECT-TYPE + SYNTAX UpsPhaseOutputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular output." + INDEX { upsPhaseOutputTableIndex } + ::= { upsPhaseOutputTable 1 } + + UpsPhaseOutputEntry ::= SEQUENCE { + upsPhaseOutputTableIndex INTEGER, + upsPhaseNumOutputPhases INTEGER, + upsPhaseOutputVoltageOrientation INTEGER, + upsPhaseOutputFrequency INTEGER + } + + upsPhaseOutputTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output identifier." + ::= { upsPhaseOutputEntry 1 } + + upsPhaseNumOutputPhases OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output phases utilized in this + device. The sum of all the upsPhaseNumOutputPhases + variable indicates the number of rows in the + output phase table." + ::= { upsPhaseOutputEntry 2 } + + upsPhaseOutputVoltageOrientation OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + singlePhase(2), + splitPhase(3), + threePhasePhaseToNeutral(4), + threePhasePhaseToPhase(5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output voltage orientation: + 1: unknown for this UPS + 2: singlePhase - phase 1 voltage is between Phase 1 + and Neutral. + 3: splitPhase - phase 1 voltage is between Phase 1 and + Neutral; phase 2 voltage is between Phase 2 and Neutral; + phase 3 voltage is between Phase 1 and Phase2. + 4: threePhasePhaseToNeutral - phase 1 voltage is between + Phase 1 and Neutral; phase 2 voltage is between Phase 2 + and Neutral; phase 3 voltage is between Phase3 and + Neutral. + 5: threePhasePhaseToPhase - phase 1 voltage is between + Phase 1 and Phase 2; phase 2 voltage is between Phase 2 + and Phase 3; phase 3 voltage is between Phase 3 and + Phase 1." + ::= { upsPhaseOutputEntry 3 } + + upsPhaseOutputFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output frequency in 0.1 Hertz, or -1 if it's + unsupported by this UPS." + ::= { upsPhaseOutputEntry 4 } + + -- Output Phase Table + + upsPhaseOutputPhaseTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsPhaseOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of output table entries. The number of + entries is given by the sum of the upsPhaseNumOutputPhases." + ::= { upsPhaseOutput 3 } + + upsPhaseOutputPhaseEntry OBJECT-TYPE + SYNTAX UpsPhaseOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular output phase." + INDEX { upsPhaseOutputPhaseTableIndex, upsPhaseOutputPhaseIndex } + ::= { upsPhaseOutputPhaseTable 1 } + + UpsPhaseOutputPhaseEntry ::= SEQUENCE { + upsPhaseOutputPhaseTableIndex INTEGER, + upsPhaseOutputPhaseIndex INTEGER, + upsPhaseOutputVoltage INTEGER, + upsPhaseOutputCurrent INTEGER, + upsPhaseOutputMaxCurrent INTEGER, + upsPhaseOutputMinCurrent INTEGER, + upsPhaseOutputLoad INTEGER, + upsPhaseOutputMaxLoad INTEGER, + upsPhaseOutputMinLoad INTEGER, + upsPhaseOutputPercentLoad INTEGER, + upsPhaseOutputMaxPercentLoad INTEGER, + upsPhaseOutputMinPercentLoad INTEGER, + upsPhaseOutputPower INTEGER, + upsPhaseOutputMaxPower INTEGER, + upsPhaseOutputMinPower INTEGER, + upsPhaseOutputPercentPower INTEGER, + upsPhaseOutputMaxPercentPower INTEGER, + upsPhaseOutputMinPercentPower INTEGER + } + + upsPhaseOutputPhaseTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output identifier." + ::= { upsPhaseOutputPhaseEntry 1 } + + upsPhaseOutputPhaseIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output phase identifier." + ::= { upsPhaseOutputPhaseEntry 2 } + + upsPhaseOutputVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output voltage in VAC, or -1 if it's unsupported + by this UPS." + ::= { upsPhaseOutputPhaseEntry 3 } + + upsPhaseOutputCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output current in 0.1 amperes drawn + by the load on the UPS, or -1 if it's unsupported + by this UPS." + ::= { upsPhaseOutputPhaseEntry 4 } + + upsPhaseOutputMaxCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum output current in 0.1 amperes measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 5 } + + upsPhaseOutputMinCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum output current in 0.1 amperes measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 6 } + + upsPhaseOutputLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output load in VA, or -1 if it's unsupported + by this UPS." + ::= { upsPhaseOutputPhaseEntry 7 } + + upsPhaseOutputMaxLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum output load in VA measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 8 } + + upsPhaseOutputMinLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum output load in VA measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 9 } + + upsPhaseOutputPercentLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The percentage of the UPS load capacity in VA at + redundancy @ (n + x) presently being used on this + output phase, or -1 if it's unsupported by this UPS." + ::= { upsPhaseOutputPhaseEntry 10 } + + upsPhaseOutputMaxPercentLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum percentage of the UPS load capacity in + VA measured at redundancy @ (n + x) presently + being used on this output phase since the last reset + (upsPhaseResetMaxMinValues), or -1 if it's unsupported + by this UPS. Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 11 } + + upsPhaseOutputMinPercentLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum percentage of the UPS load capacity in + VA measured at redundancy @ (n + x) presently + being used on this output phase since the last reset + (upsPhaseResetMaxMinValues), or -1 if it's unsupported + by this UPS. Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 12 } + + upsPhaseOutputPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output power in Watts, or -1 if it's + unsupported by this UPS." + ::= { upsPhaseOutputPhaseEntry 13 } + + upsPhaseOutputMaxPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum output power in Watts measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 14 } + + upsPhaseOutputMinPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum output power in Watts measured + since the last reset (upsPhaseResetMaxMinValues), or + -1 if it's unsupported by this UPS. + Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 15 } + + upsPhaseOutputPercentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The percentage of the UPS power capacity in Watts at + redundancy @ (n + x) presently being used on this + output phase, or -1 if it's unsupported by this UPS." + ::= { upsPhaseOutputPhaseEntry 16 } + + upsPhaseOutputMaxPercentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum percentage of the UPS power capacity + in Watts measured at redundancy @ (n + x) presently + being used on this output phase since the last + reset (upsPhaseResetMaxMinValues), or -1 if it's + unsupported by this UPS. Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 17 } + + upsPhaseOutputMinPercentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum percentage of the UPS power capacity + in Watts measured at redundancy @ (n + x) presently + being used on this output phase since the last + reset (upsPhaseResetMaxMinValues), or -1 if it's + unsupported by this UPS. Sampled every 30 seconds." + ::= { upsPhaseOutputPhaseEntry 18 } + +-- the upsOutletGroupStatus group + +upsOutletGroupStatusTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of outlet groups for the UPS." + ::= { upsOutletGroupStatus 1 } + +upsOutletGroupStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsOutletGroupStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting status of the outlet groups. The number of + entries is contained in the upsOutletGroupStatusTableSize OID." + ::= { upsOutletGroupStatus 2 } + +upsOutletGroupStatusEntry OBJECT-TYPE + SYNTAX UpsOutletGroupStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlet group status to get." + INDEX { upsOutletGroupStatusIndex} + ::= { upsOutletGroupStatusTable 1 } + +UpsOutletGroupStatusEntry ::= + SEQUENCE { + upsOutletGroupStatusIndex INTEGER, + upsOutletGroupStatusName DisplayString, + upsOutletGroupStatusGroupState INTEGER, + upsOutletGroupStatusCommandPending INTEGER + } + +upsOutletGroupStatusIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet group entry." + ::= { upsOutletGroupStatusEntry 1 } + +upsOutletGroupStatusName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet group. This OID is provided + for informational purposes only. This value is set + by the upsOutletGroupConfigName OID." + ::= { upsOutletGroupStatusEntry 2 } + +upsOutletGroupStatusGroupState OBJECT-TYPE + SYNTAX INTEGER { + upsOutletGroupStatusOn (1), + upsOutletGroupStatusOff (2), + upsOutletGroupStatusUnknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet group state. If the outlet + group is on, the upsOutletGroupStatusOn (1) value will be returned. If + the outlet group is off, the upsOutletGroupStatusOff (2) value will be + returned. If the state of the outlet group cannot be determined, the + upsOutletGroupStatusUnknown (3) value will be returned." + + ::= { upsOutletGroupStatusEntry 3 } + +upsOutletGroupStatusCommandPending OBJECT-TYPE + SYNTAX INTEGER { + upsOutletGroupCommandPending (1), + upsOutletGroupNoCommandPending (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the command pending + state of the outlet group. If a command is pending on the + outlet group, the upsOutletGroupCommandPending (1) value + will be returned. If there is not a command pending + on the outlet group, the upsOutletGroupNoCommandPending (2) + will be returned." + ::= { upsOutletGroupStatusEntry 4 } + +-- the upsOutletGroupConfig group + +upsOutletGroupConfigTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of outlet groups for the UPS." + ::= { upsOutletGroupConfig 1 } + +upsOutletGroupConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsOutletGroupConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The list of outlet groups to configure. The number of entries + is defined by the upsOutletGroupConfigTableSize OID." + ::= { upsOutletGroupConfig 2 } + +upsOutletGroupConfigEntry OBJECT-TYPE + SYNTAX UpsOutletGroupConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlet groups to configure." + INDEX { upsOutletGroupConfigIndex} + ::= { upsOutletGroupConfigTable 1 } + +UpsOutletGroupConfigEntry ::= + SEQUENCE { + upsOutletGroupConfigIndex INTEGER, + upsOutletGroupConfigName DisplayString, + upsOutletGroupConfigPowerOnDelay INTEGER, + upsOutletGroupConfigPowerOffDelay INTEGER, + upsOutletGroupConfigRebootDuration INTEGER + } + +upsOutletGroupConfigIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet group entry." + ::= { upsOutletGroupConfigEntry 1 } + +upsOutletGroupConfigName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the outlet group." + ::= { upsOutletGroupConfigEntry 2 } + +upsOutletGroupConfigPowerOnDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time (in seconds) the outlet group will delay + powering on when the delayed on or reboot command is applied. + Allowed values are -1 (for Never) or 0 to 600 seconds." + ::= { upsOutletGroupConfigEntry 3 } + +upsOutletGroupConfigPowerOffDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time (in seconds) the outlet group will delay + powering off when the delayed off command is applied. + Allowed values are 0 to 600 seconds." + ::= { upsOutletGroupConfigEntry 4 } + +upsOutletGroupConfigRebootDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "During a reboot sequence, power is turned off and then + back on. This OID defines the amount of time to wait, + in seconds, after turning the power off, at the start + of the sequence, before initiating the power on sequence. + Allowed values are 0 to 600 seconds." + ::= { upsOutletGroupConfigEntry 5 } + +-- the upsOutletGroupControl group + +upsOutletGroupControlTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of outlet groups for the UPS." + ::= { upsOutletGroupControl 1 } + +upsOutletGroupControlTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsOutletGroupControlEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of individual outlet groups. The number of + entries is contained in the upsOutletGroupControlTableSize OID." + ::= { upsOutletGroupControl 2 } + +upsOutletGroupControlEntry OBJECT-TYPE + SYNTAX UpsOutletGroupControlEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlet group to control." + INDEX { upsOutletGroupControlIndex} + ::= { upsOutletGroupControlTable 1 } + +UpsOutletGroupControlEntry ::= + SEQUENCE { + upsOutletGroupControlIndex INTEGER, + upsOutletGroupControlName DisplayString, + upsOutletGroupControlCommand INTEGER + } + +upsOutletGroupControlIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet group entry." + ::= { upsOutletGroupControlEntry 1 } + +upsOutletGroupControlName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet group. This OID is provided + for informational purposes only. This value is set + by the upsOutletGroupConfigName OID." + ::= { upsOutletGroupControlEntry 2 } + +upsOutletGroupControlCommand OBJECT-TYPE + SYNTAX INTEGER { + upsOutletGroupImmediateOn (1), + upsOutletGroupImmediateOff (2), + upsOutletGroupImmediateReboot (3), + upsOutletGroupDelayedOn (4), + upsOutletGroupDelayedOff (5), + upsOutletGroupDelayedReboot (6), + upsOutletGroupCancelPendingCommand (7), + upsOutletGroupControlUnknown (8) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet group state. If the outlet + group is on, the upsOutletGroupImmediateOn (1) value will be returned. If + the outlet group is off, the upsOutletGroupImmediateOff (2) value will be + returned. + + If the state of the outlet group cannot be determined, the + upsOutletGroupControlUnknown (8) value will be returned. + + Setting this variable to upsOutletGroupImmediateOn (1) will turn the + outlet group on. + + Setting this variable to upsOutletGroupImmediateOff (2) will turn the + outlet group off. + + Setting this variable to upsOutletGroupImmediateReboot (3) will turn the outlet + group off, wait the upsOutletGroupConfigRebootDuration OID time, wait the + upsOutletGroupConfigPowerOnDelay OID, and then turn the outlet group on. + + Setting this variable to upsOutletGroupDelayedOn (4) will turn the outlet + group on after the upsOutletGroupConfigPowerOnDelay OID has elapsed. + + Setting this variable to upsOutletGroupDelayedOff (5) will turn the outlet + group off after the upsOutletGroupConfigPowerOffDelay OID has elapsed. + + Setting this variable to upsOutletGroupDelayedReboot (6) will turn the outlet + group off after the upsOutletGroupConfigPowerOffDelay OID has elapsed, wait the + upsOutletGroupConfigRebootDuration OID time, wait the + upsOutletGroupConfigPowerOnDelay OID, and then turn the outlet group on. + + Setting this variable to upsOutletGroupCancelPendingCommand (7) will + cause any pending command to this outlet group to be canceled." + ::= { upsOutletGroupControlEntry 3 } + +-- the upsDiagnosticIM group + +upsDiagIMTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of Intelligence Modules in or attached to the UPS." + ::= { upsDiagnosticIM 1 } + +upsDiagIMTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagIMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of individual Intelligence Modules. The number of + entries is contained in the upsDiagIMTableSize OID." + ::= { upsDiagnosticIM 2 } + +upsDiagIMEntry OBJECT-TYPE + SYNTAX UpsDiagIMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics and information of an Intelligence Module." + INDEX { upsDiagIMIndex} + ::= { upsDiagIMTable 1 } + +UpsDiagIMEntry ::= + SEQUENCE { + upsDiagIMIndex INTEGER, + upsDiagIMType INTEGER, + upsDiagIMStatus INTEGER, + upsDiagIMFirmwareRev DisplayString, + upsDiagIMSlaveFirmwareRev DisplayString, + upsDiagIMHardwareRev DisplayString, + upsDiagIMSerialNum DisplayString, + upsDiagIMManufactureDate DisplayString + } + +upsDiagIMIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the Intelligence Module entry." + ::= { upsDiagIMEntry 1 } + +upsDiagIMType OBJECT-TYPE + SYNTAX INTEGER { + imUnknown (1), + imMIM (2), + imRIM (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The type of the Intelligence Module. + imUnknown(1) indicates the IM type is unknown. + imMIM(2) indicates the IM type is a Main Intelligence Module. + imRIM(3) indicates the IM type is Redundant Intelligence Module." + ::= { upsDiagIMEntry 2 } + +upsDiagIMStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Intelligence Module. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagIMEntry 3 } + +upsDiagIMFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the Intelligence Module." + ::= { upsDiagIMEntry 4 } + +upsDiagIMSlaveFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The slave firmware revision of the Intelligence Module." + ::= { upsDiagIMEntry 5 } + +upsDiagIMHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the Intelligence Module." + ::= { upsDiagIMEntry 6 } + +upsDiagIMSerialNum OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The serial number of the Intelligence Module." + ::= { upsDiagIMEntry 7 } + +upsDiagIMManufactureDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The manufacture date of the Intelligence Module." + ::= { upsDiagIMEntry 8 } + +-- the upsDiagnosticPowerModules group + +upsDiagPMTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of Power Modules in or attached to the UPS." + ::= { upsDiagnosticPowerModules 1 } + +upsDiagPMTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagPMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of Individual Power modules. The number of + entries is contained in the upsDiagPMTableSize OID." + ::= { upsDiagnosticPowerModules 2 } + +upsDiagPMEntry OBJECT-TYPE + SYNTAX UpsDiagPMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of an Power Module." + INDEX { upsDiagPMIndex} + ::= { upsDiagPMTable 1 } + +UpsDiagPMEntry ::= + SEQUENCE { + upsDiagPMIndex INTEGER, + upsDiagPMStatus INTEGER, + upsDiagPMFirmwareRev DisplayString, + upsDiagPMHardwareRev DisplayString, + upsDiagPMSerialNum DisplayString, + upsDiagPMManufactureDate DisplayString + } + +upsDiagPMIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the Power Module entry." + ::= { upsDiagPMEntry 1 } + +upsDiagPMStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Power Module. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagPMEntry 2 } + +upsDiagPMFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the Power Module." + ::= { upsDiagPMEntry 3 } + +upsDiagPMHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the Power Module." + ::= { upsDiagPMEntry 4 } + +upsDiagPMSerialNum OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The serial number of the Power Module." + ::= { upsDiagPMEntry 5 } + +upsDiagPMManufactureDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The manufacture date of the Power Module." + ::= { upsDiagPMEntry 6 } + +-- the upsDiagnosticBatteries group + +upsDiagBatteryTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of batteries in or attached to the UPS." + ::= { upsDiagnosticBatteries 1 } + +upsDiagBatteryTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagBatteryEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of individual batteries. The number of + entries is contained in the upsDiagBattTableSize OID." + ::= { upsDiagnosticBatteries 2 } + +upsDiagBatteryEntry OBJECT-TYPE + SYNTAX UpsDiagBatteryEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of a battery." + INDEX { upsDiagBatteryIndex} + ::= { upsDiagBatteryTable 1 } + +UpsDiagBatteryEntry ::= + SEQUENCE { + upsDiagBatteryFrameIndex INTEGER, + upsDiagBatteryIndex INTEGER, + upsDiagBatteryStatus INTEGER, + upsDiagBatterySerialNumber DisplayString, + upsDiagBatteryFirmwareRev DisplayString, + upsDiagBatteryManufactureDate DisplayString, + upsDiagBatteryType DisplayString + } + +upsDiagBatteryFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the battery frame entry. + Frame 0 indicates the Main frame. Extended Run (XR) frames + start from index 1." + ::= { upsDiagBatteryEntry 1 } + +upsDiagBatteryIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the battery entry." + ::= { upsDiagBatteryEntry 2 } + +upsDiagBatteryStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + ok (3), + failed (4), + highTemperature (5), + replaceImmediately (6), + lowCapacity (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the battery. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + ok(3) indicates the battery status is OK. + failed(4) indicates the battery status is failed. + highTemperature(5) indicates the battery has a high temperature condition. + replaceImmediately(6) indicates the battery must be replaced immediately. + lowCapacity(7) indicates the battery has a low capacity." + ::= { upsDiagBatteryEntry 3 } + +upsDiagBatterySerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The serial number of the battery." + ::= { upsDiagBatteryEntry 4 } + +upsDiagBatteryFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the battery." + ::= { upsDiagBatteryEntry 5 } + +upsDiagBatteryManufactureDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The manufacture date of the battery." + ::= { upsDiagBatteryEntry 6 } + +upsDiagBatteryType OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The battery type or rating for the battery." + ::= { upsDiagBatteryEntry 7 } + +-- the upsDiagnosticSubsystem group + +upsDiagSubSysFrameTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of frames attached to the UPS including the Main frame." + ::= { upsDiagnosticSubsystem 1 } + +upsDiagSubSysFrameTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysFrameEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of individual XR Frames." + ::= { upsDiagnosticSubsystem 2 } + +upsDiagSubSysFrameEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysFrameEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of an XR Frame." + INDEX { upsDiagSubSysFrameIndex} + ::= { upsDiagSubSysFrameTable 1 } + +UpsDiagSubSysFrameEntry ::= + SEQUENCE { + upsDiagSubSysFrameIndex INTEGER, + upsDiagSubSysFrameType INTEGER, + upsDiagSubSysFrameFirmwareRev DisplayString, + upsDiagSubSysFrameHardwareRev DisplayString, + upsDiagSubSysFrameSerialNum DisplayString, + upsDiagSubSysFrameManufactureDate DisplayString + } + +upsDiagSubSysFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysFrameEntry 1 } + +upsDiagSubSysFrameType OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + frameTypeMain (3), + frameTypeXR (4), + frameTypeLXR (5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The type of Frame. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + frameTypeMain(3) indicates the the frame type is the Main Frame. + frameTypeXR(4) indicates the frame type is an XR Frame. + frameTypeLXR(5) indicates the frame type is an LXR Frame." + ::= { upsDiagSubSysFrameEntry 2 } + +upsDiagSubSysFrameFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the frame." + ::= { upsDiagSubSysFrameEntry 3 } + +upsDiagSubSysFrameHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the frame." + ::= { upsDiagSubSysFrameEntry 4 } + +upsDiagSubSysFrameSerialNum OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The serial number of the frame." + ::= { upsDiagSubSysFrameEntry 5 } + +upsDiagSubSysFrameManufactureDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The manufacture date of the frame." + ::= { upsDiagSubSysFrameEntry 6 } + +upsDiagSubSysIntBypSwitchTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of Internal Bypass switches attached to the UPS." + ::= { upsDiagnosticSubsystem 3 } + +upsDiagSubSysIntBypSwitchTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysIntBypSwitchEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of the Internal Bypass Switch." + ::= { upsDiagnosticSubsystem 4 } + +upsDiagSubSysIntBypSwitchEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysIntBypSwitchEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of the Internal Bypass Switch." + INDEX { upsDiagSubSysIntBypSwitchIndex} + ::= { upsDiagSubSysIntBypSwitchTable 1 } + +UpsDiagSubSysIntBypSwitchEntry ::= + SEQUENCE { + upsDiagSubSysIntBypSwitchFrameIndex INTEGER, + upsDiagSubSysIntBypSwitchIndex INTEGER, + upsDiagSubSysIntBypSwitchStatus INTEGER, + upsDiagSubSysIntBypSwitchFirmwareRev DisplayString, + upsDiagSubSysIntBypSwitchHardwareRev DisplayString, + upsDiagSubSysIntBypSwitchSerialNum DisplayString, + upsDiagSubSysIntBypSwitchManufactureDate DisplayString + } + +upsDiagSubSysIntBypSwitchFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysIntBypSwitchEntry 1 } + +upsDiagSubSysIntBypSwitchIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Internal Bypass Switch index entry." + ::= { upsDiagSubSysIntBypSwitchEntry 2 } + +upsDiagSubSysIntBypSwitchStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Internal Bypass Switch status. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagSubSysIntBypSwitchEntry 3 } + +upsDiagSubSysIntBypSwitchFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the Internal Bypass Switch." + ::= { upsDiagSubSysIntBypSwitchEntry 4 } + +upsDiagSubSysIntBypSwitchHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the Internal Bypass Switch." + ::= { upsDiagSubSysIntBypSwitchEntry 5 } + +upsDiagSubSysIntBypSwitchSerialNum OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The serial number of the Internal Bypass Switch." + ::= { upsDiagSubSysIntBypSwitchEntry 6 } + +upsDiagSubSysIntBypSwitchManufactureDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The manufacture date of the Internal Bypass Switch." + ::= { upsDiagSubSysIntBypSwitchEntry 7 } + +upsDiagSubSysBattMonitorTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of Battery Monitor Boards attached to the UPS." + ::= { upsDiagnosticSubsystem 5 } + +upsDiagSubSysBattMonitorTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysBattMonitorEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of the Battery Monitor Board." + ::= { upsDiagnosticSubsystem 6 } + +upsDiagSubSysBattMonitorEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysBattMonitorEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of the Battery Monitor Board." + INDEX { upsDiagSubSysBattMonitorIndex} + ::= { upsDiagSubSysBattMonitorTable 1 } + +UpsDiagSubSysBattMonitorEntry ::= + SEQUENCE { + upsDiagSubSysBattMonitorFrameIndex INTEGER, + upsDiagSubSysBattMonitorIndex INTEGER, + upsDiagSubSysBattMonitorStatus INTEGER, + upsDiagSubSysBattMonitorFirmwareRev DisplayString, + upsDiagSubSysBattMonitorHardwareRev DisplayString, + upsDiagSubSysBattMonitorSerialNum DisplayString, + upsDiagSubSysBattMonitorManufactureDate DisplayString + } + +upsDiagSubSysBattMonitorFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysBattMonitorEntry 1 } + +upsDiagSubSysBattMonitorIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the Battery Monitor Board." + ::= { upsDiagSubSysBattMonitorEntry 2 } + +upsDiagSubSysBattMonitorStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Battery Monitor Board. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagSubSysBattMonitorEntry 3 } + +upsDiagSubSysBattMonitorFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the Battery Monitor Board." + ::= { upsDiagSubSysBattMonitorEntry 4 } + +upsDiagSubSysBattMonitorHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the Battery Monitor Board." + ::= { upsDiagSubSysBattMonitorEntry 5 } + +upsDiagSubSysBattMonitorSerialNum OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The serial number of the Battery Monitor Board." + ::= { upsDiagSubSysBattMonitorEntry 6 } + +upsDiagSubSysBattMonitorManufactureDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date of the manufacture for the Battery Monitor Board." + ::= { upsDiagSubSysBattMonitorEntry 7 } + +upsDiagSubSysExternalSwitchGearTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of External Switch Gears attached to the UPS." + ::= { upsDiagnosticSubsystem 7 } + +upsDiagSubSysExternalSwitchGearTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysExternalSwitchGearEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of the individual External Switch Gear." + ::= { upsDiagnosticSubsystem 8 } + +upsDiagSubSysExternalSwitchGearEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysExternalSwitchGearEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of an individual External Switch Gear." + INDEX { upsDiagSubSysExternalSwitchGearIndex} + ::= { upsDiagSubSysExternalSwitchGearTable 1 } + +UpsDiagSubSysExternalSwitchGearEntry ::= + SEQUENCE { + upsDiagSubSysExternalSwitchGearFrameIndex INTEGER, + upsDiagSubSysExternalSwitchGearIndex INTEGER, + upsDiagSubSysExternalSwitchGearStatus INTEGER, + upsDiagSubSysExternalSwitchGearFirmwareRev DisplayString, + upsDiagSubSysExternalSwitchGearHardwareRev DisplayString, + upsDiagSubSysExternalSwitchGearSerialNum DisplayString, + upsDiagSubSysExternalSwitchGearManufactureDate DisplayString + } + +upsDiagSubSysExternalSwitchGearFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysExternalSwitchGearEntry 1 } + +upsDiagSubSysExternalSwitchGearIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the External Switch Gear." + ::= { upsDiagSubSysExternalSwitchGearEntry 2 } + +upsDiagSubSysExternalSwitchGearStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the External Switch Gear. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagSubSysExternalSwitchGearEntry 3 } + +upsDiagSubSysExternalSwitchGearFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the External Switch Gear monitor card." + ::= { upsDiagSubSysExternalSwitchGearEntry 4 } + +upsDiagSubSysExternalSwitchGearHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the External Switch Gear monitor card." + ::= { upsDiagSubSysExternalSwitchGearEntry 5 } + +upsDiagSubSysExternalSwitchGearSerialNum OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The serial number of the External Switch Gear monitor card." + ::= { upsDiagSubSysExternalSwitchGearEntry 6 } + +upsDiagSubSysExternalSwitchGearManufactureDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date of the manufacture for the External Switch Gear monitor card." + ::= { upsDiagSubSysExternalSwitchGearEntry 7 } + +upsDiagSubSysDisplayInterfaceCardTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of Display Interface Cards attached to the UPS." + ::= { upsDiagnosticSubsystem 9 } + +upsDiagSubSysDisplayInterfaceCardTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysDisplayInterfaceCardEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of individual Display Interface Cards." + ::= { upsDiagnosticSubsystem 10 } + +upsDiagSubSysDisplayInterfaceCardEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysDisplayInterfaceCardEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of a Display Interface Card." + INDEX { upsDiagSubSysDisplayInterfaceCardIndex} + ::= { upsDiagSubSysDisplayInterfaceCardTable 1 } + +UpsDiagSubSysDisplayInterfaceCardEntry ::= + SEQUENCE { + upsDiagSubSysDisplayInterfaceCardFrameIndex INTEGER, + upsDiagSubSysDisplayInterfaceCardIndex INTEGER, + upsDiagSubSysDisplayInterfaceCardStatus INTEGER + } + +upsDiagSubSysDisplayInterfaceCardFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysDisplayInterfaceCardEntry 1 } + +upsDiagSubSysDisplayInterfaceCardIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the Display Interface Card." + ::= { upsDiagSubSysDisplayInterfaceCardEntry 2 } + +upsDiagSubSysDisplayInterfaceCardStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Display Interface Card. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagSubSysDisplayInterfaceCardEntry 3 } + +upsDiagSubSysDCCircuitBreakerTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC Circuit Breakers attached to the UPS." + ::= { upsDiagnosticSubsystem 11 } + +upsDiagSubSysDCCircuitBreakerTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysDCCircuitBreakerEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of individual DC Circuit Breakers." + ::= { upsDiagnosticSubsystem 12 } + +upsDiagSubSysDCCircuitBreakerEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysDCCircuitBreakerEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of a DC Circuit Breaker." + INDEX { upsDiagSubSysDCCircuitBreakerIndex} + ::= { upsDiagSubSysDCCircuitBreakerTable 1 } + +UpsDiagSubSysDCCircuitBreakerEntry ::= + SEQUENCE { + upsDiagSubSysDCCircuitBreakerFrameIndex INTEGER, + upsDiagSubSysDCCircuitBreakerIndex INTEGER, + upsDiagSubSysDCCircuitBreakerStatus INTEGER + } + +upsDiagSubSysDCCircuitBreakerFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysDCCircuitBreakerEntry 1 } + +upsDiagSubSysDCCircuitBreakerIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the DC Circuit Breaker." + ::= { upsDiagSubSysDCCircuitBreakerEntry 2 } + +upsDiagSubSysDCCircuitBreakerStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + opened (3), + closed (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the DC Circuit Breaker. + unknown(1) indicates the circuit breaker status is unknown. + notInstalled(2) indicates the circuit breaker is not installed. + opened(3) indicates the circuit breaker is opened. + closed(4) indicates the circuit breaker is closed." + ::= { upsDiagSubSysDCCircuitBreakerEntry 3 } + +upsDiagSubSysSystemPowerSupplyTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of System Power Supplies attached to the UPS." + ::= { upsDiagnosticSubsystem 13 } + +upsDiagSubSysSystemPowerSupplyTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysSystemPowerSupplyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of individual System Power Supplies." + ::= { upsDiagnosticSubsystem 14 } + +upsDiagSubSysSystemPowerSupplyEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysSystemPowerSupplyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of a System Power Supply." + INDEX { upsDiagSubSysSystemPowerSupplyIndex} + ::= { upsDiagSubSysSystemPowerSupplyTable 1 } + +UpsDiagSubSysSystemPowerSupplyEntry ::= + SEQUENCE { + upsDiagSubSysSystemPowerSupplyFrameIndex INTEGER, + upsDiagSubSysSystemPowerSupplyIndex INTEGER, + upsDiagSubSysSystemPowerSupplyStatus INTEGER + } + +upsDiagSubSysSystemPowerSupplyFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysSystemPowerSupplyEntry 1 } + +upsDiagSubSysSystemPowerSupplyIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of a System Power Supply." + ::= { upsDiagSubSysSystemPowerSupplyEntry 2 } + +upsDiagSubSysSystemPowerSupplyStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the System Power Supply. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagSubSysSystemPowerSupplyEntry 3 } + +upsDiagSubSysXRCommunicationCardTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of XR Communication Cards attached to the UPS." + ::= { upsDiagnosticSubsystem 15 } + +upsDiagSubSysXRCommunicationCardTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysXRCommunicationCardEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of individual XR Communication Cards." + ::= { upsDiagnosticSubsystem 16 } + +upsDiagSubSysXRCommunicationCardEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysXRCommunicationCardEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of an XR Communication Card." + INDEX { upsDiagSubSysXRCommunicationCardIndex} + ::= { upsDiagSubSysXRCommunicationCardTable 1 } + +UpsDiagSubSysXRCommunicationCardEntry ::= + SEQUENCE { + upsDiagSubSysXRCommunicationCardFrameIndex INTEGER, + upsDiagSubSysXRCommunicationCardIndex INTEGER, + upsDiagSubSysXRCommunicationCardStatus INTEGER + } + +upsDiagSubSysXRCommunicationCardFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysXRCommunicationCardEntry 1 } + +upsDiagSubSysXRCommunicationCardIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of an XR Communication Card." + ::= { upsDiagSubSysXRCommunicationCardEntry 2 } + +upsDiagSubSysXRCommunicationCardStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the XR Communication Card. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagSubSysXRCommunicationCardEntry 3 } + +upsDiagSubSysExternalPowerFrameBoardTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of External Power Frame Boards attached to the UPS." + ::= { upsDiagnosticSubsystem 17 } + +upsDiagSubSysExternalPowerFrameBoardTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysExternalPowerFrameBoardEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of individual External Power Frame Boards." + ::= { upsDiagnosticSubsystem 18 } + +upsDiagSubSysExternalPowerFrameBoardEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysExternalPowerFrameBoardEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of an External Power Frame Board." + INDEX { upsDiagSubSysExternalPowerFrameBoardIndex} + ::= { upsDiagSubSysExternalPowerFrameBoardTable 1 } + +UpsDiagSubSysExternalPowerFrameBoardEntry ::= + SEQUENCE { + upsDiagSubSysExternalPowerFrameBoardFrameIndex INTEGER, + upsDiagSubSysExternalPowerFrameBoardIndex INTEGER, + upsDiagSubSysExternalPowerFrameBoardStatus INTEGER + } + +upsDiagSubSysExternalPowerFrameBoardFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysExternalPowerFrameBoardEntry 1 } + +upsDiagSubSysExternalPowerFrameBoardIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of an External Power Frame Board." + ::= { upsDiagSubSysExternalPowerFrameBoardEntry 2 } + +upsDiagSubSysExternalPowerFrameBoardStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the External Power Frame Board. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagSubSysExternalPowerFrameBoardEntry 3 } + +upsDiagSubSysChargerTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of Chargers attached to the UPS." + ::= { upsDiagnosticSubsystem 19 } + + upsDiagSubSysChargerTable OBJECT-TYPE + SYNTAX SEQUENCE OF UpsDiagSubSysChargerEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for diagnostics of individual chargers." + ::= { upsDiagnosticSubsystem 20 } + +upsDiagSubSysChargerEntry OBJECT-TYPE + SYNTAX UpsDiagSubSysChargerEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The diagnostics of a charger." + INDEX { upsDiagSubSysChargerIndex} + ::= { upsDiagSubSysChargerTable 1 } + +UpsDiagSubSysChargerEntry ::= + SEQUENCE { + upsDiagSubSysChargerFrameIndex INTEGER, + upsDiagSubSysChargerIndex INTEGER, + upsDiagSubSysChargerStatus INTEGER + } + +upsDiagSubSysChargerFrameIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The frame index entry." + ::= { upsDiagSubSysChargerEntry 1 } + +upsDiagSubSysChargerIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of a charger." + ::= { upsDiagSubSysChargerEntry 2 } + +upsDiagSubSysChargerStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + offOk (3), + onOk (4), + offFail (5), + onFail (6), + lostComm (7) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Charger. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + offOk(3) indicates the device status is off and OK. + onOk(4) indicates the device status is on and OK. + offFail(5) indicates the device status is off and failed. + onFail(6) indicates the device status is on and failed. + lostComm(7) indicates the device has lost communication." + ::= { upsDiagSubSysChargerEntry 3 } + +-- the upsDiagnosticExternalDevices group + +upsDiagSwitchGearStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + ok (3), + fail (4), + lostComm (5), + overtemp (6) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Switch Gear. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + ok(3) indicates the device status is OK. + fail(4) indicates the device status has failed. + lostComm(5) indicates the device has lost communication. + overtemp(6) indicates the device has an over temperature condition." + ::= { upsDiagSwitchGear 1 } + +upsDiagSwitchGearInputSwitchStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + opened (3), + closed (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Switch Gear Input Switch. + unknown(1) indicates the switch status is unknown. + notInstalled(2) indicates the switch is not installed. + opened(3) indicates the switch is opened. + closed(4) indicates the switch is closed." + ::= { upsDiagSwitchGear 2 } + +upsDiagSwitchGearOutputSwitchStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + opened (3), + closed (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Switch Gear Output Switch. + unknown(1) indicates the switch status is unknown. + notInstalled(2) indicates the switch is not installed. + opened(3) indicates the switch is opened. + closed(4) indicates the switch is closed." + ::= { upsDiagSwitchGear 3 } + +upsDiagSwitchGearBypassSwitchStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + opened (3), + closed (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Switch Gear Bypass Switch. + unknown(1) indicates the switch status is unknown. + notInstalled(2) indicates the switch is not installed. + opened(3) indicates the switch is opened. + closed(4) indicates the switch is closed." + ::= { upsDiagSwitchGear 4 } + +upsDiagMCCBBoxStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + opened (3), + closed (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the MCCB Box (Molded Case Circuit Breaker Box) external device. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + opened(3) indicates the circuit is opened. + closed(4) indicates the circuit is closed." + ::= { upsDiagMCCBBox 1 } + +upsDiagTransformerStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + ok (3), + fail (4), + lostComm (5), + overtemp (6), + opened (7), + closed (8) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the External Transformer. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + ok(3) indicates the device status is OK. + fail(4) indicates the device status has failed. + lostComm(5) indicates the device has lost communication. + overtemp(6) indicates the device has an over temperature condition. + opened(7) indicates the circuit is opened. + closed(8) indicates the circuit is closed." + ::= { upsDiagTransformer 1 } + +-- the upsDiagnosticComBus group + +upsDiagComBusInternalMIMStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + ok (3), + lostComm (4), + rxFailure (5), + txFailure (6) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the internal MIM communication bus. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + ok(3) indicates the device status is OK. + lostComm(4) indicates the device has lost communication. + rxFailure(5) indicates the device has a receive failure. + txFailure(6) indicates the device has a transmit failure." + ::= { upsDiagnosticComBus 1 } + +upsDiagComBusInternalRIMStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + ok (3), + lostComm (4), + rxFailure (5), + txFailure (6) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the internal RIM communication bus. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + ok(3) indicates the device status is OK. + lostComm(4) indicates the device has lost communication. + rxFailure(5) indicates the device has a receive failure. + txFailure(6) indicates the device has a transmit failure." + ::= { upsDiagnosticComBus 2 } + +upsDiagComBusMIMtoRIMStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + ok (3), + lostComm (4), + rxFailure (5), + txFailure (6) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the MIM to RIM communication bus. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + ok(3) indicates the device status is OK. + lostComm(4) indicates the device has lost communication. + rxFailure(5) indicates the device has a receive failure. + txFailure(6) indicates the device has a transmit failure." + ::= { upsDiagnosticComBus 3 } + +upsDiagComBusExternalMIMStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + ok (3), + lostComm (4), + rxFailure (5), + txFailure (6) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the external MIM communication bus. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + ok(3) indicates the device status is OK. + lostComm(4) indicates the device has lost communication. + rxFailure(5) indicates the device has a receive failure. + txFailure(6) indicates the device has a transmit failure." + ::= { upsDiagnosticComBus 4 } + +upsDiagComBusExternalRIMStatus OBJECT-TYPE + SYNTAX INTEGER { + unknown (1), + notInstalled (2), + ok (3), + lostComm (4), + rxFailure (5), + txFailure (6) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the external RIM communication bus. + unknown(1) indicates the device status is unknown. + notInstalled(2) indicates the device is not installed. + ok(3) indicates the device status is OK. + lostComm(4) indicates the device has lost communication. + rxFailure(5) indicates the device has a receive failure. + txFailure(6) indicates the device has a transmit failure." + ::= { upsDiagnosticComBus 5 } + +-- the serialPort2Config group + +serialPort2Mode OBJECT-TYPE + SYNTAX INTEGER { + localConsole(1), + passthrough(2) + } + ACCESS read-write + STATUS obsolete + DESCRIPTION + "Setting this variable to passthrough will enable mini's port2 + behave like a UPS port. Choosing localConsole will enable the port + to be used as local console." + ::= { serialPort2Config 1 } +-- the serialPort2Control group + +setPulseOnTXD OBJECT-TYPE + SYNTAX INTEGER { + noSetPulseOnTXD(1), + setPulseOnTXD(2), + setTXDLow(3), + setTXDHigh(4) + + } + ACCESS read-write + STATUS obsolete + DESCRIPTION + "Setting this variable to setPulseOnTXD(2) + causes adapter to generate a PULSE on TXD pin of serial port 2. + The duration in the prototype implementation will be 1 second. + + Setting this value to noSetPulseOnTXD(1) has no + effect. + + The value noSetPulseOnTXD(1) will always be returned + when the variable is read. + + Setting this value to setTXDLow(3), or setTXDHigh(4) will keep TXD + always low or high respectively." + ::= { serialPort2Control 1 } + +-- the sPDUIdent group + +sPDUIdentHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the PDU. This value + is set at the factory." + ::= { sPDUIdent 1 } + +sPDUIdentFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An 8 byte ID string identifying the PDU firmware revision. + This value is set at the factory." + ::= { sPDUIdent 2 } + + +sPDUIdentDateOfManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date when the PDU was manufactured in mm/dd/yy format. + This value is set at the factory. The year 2000 will be + represented by 00." + ::= { sPDUIdent 3 } + +sPDUIdentModelNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 10-character string identifying the model number of + the PDU internal. This value is set at the factory." + ::= { sPDUIdent 4 } + +sPDUIdentSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 12-character string identifying the serial number of + the PDU internal microprocessor. This value is set at + the factory." + ::= { sPDUIdent 5 } + + +-- the sPDUMasterControl group + +sPDUMasterControlSwitch OBJECT-TYPE + SYNTAX INTEGER { + turnAllOnNow (1), + turnAllOnSequence (2), + turnAllOffNow (3), + rebootAllNow (4), + rebootAllSequence (5), + noCommand (6), + turnAllOffSequence (7) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to turnAllOnNow (1) will turn all outlets + on immediately. + + Setting this OID to turnAllOnSequence (2) will turn all outlets + on as defined by each outlet's sPDUOutletPowerOnTime OID value. + + Setting this OID to turnAllOff (3) will turn all outlets + off immediately. + + Setting this OID to rebootAllNow (4) will reboot all outlets + immediately. + + For MasterSwitch firmware version 1.X, setting this OID to + rebootAllSequence (5) reboots all outlets, with power returned + to the outlets in the sequence defined by each outlet's + sPDUOutletPowerOnTime OID value. + + For MasterSwitch firmware version 2.X, setting this OID to + rebootAllSequence (5) will cause a turnAllOffSequence to be performed. + Once all outlets are off, the MasterSwitch will then delay the + sPDUMasterConfigReboot OID time, and then perform a turnAllOnSequence. + + For MasterSwitch firmware version 2.X, setting this OID to + turnAllOffSequence (7) will turn all outlets off as defined by + each outlet's sPDUOutletPowerOffTime OID value. + + For MasterSwitch firmware version 1.X, setting this OID to + turnAllOffSequence (7) will have no effect. + + Getting this OID will return the noCommand (6) value." + + ::= { sPDUMasterControl 1 } + + +sPDUMasterState OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will cause the status of all outlets to be + returned. This OID is provided for informational purposes only. + To change the outlet state, the user should use the sPDUOutletCtl + OID in the sPDUOutletControlTable. + + The format of the data returned is a character string consisting + of the word 'On' if the outlet is on or 'Off' if the outlet is + off. At least one space will delimit each outlet entry in the + string. + + If the outlet states are unknown, the character string 'Unknown' + will be returned. This signifies that there is an inconsistancy + in the PDU. In the rare case that this should happen, the user + is advised to shut down all equipment powered by the PDU and + then cycle the PDU's power. This will put the PDU in a consistent + state." + + ::= { sPDUMasterControl 2 } + +sPDUMasterPending OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will cause the command pending status of all outlets to be returned. + + The format of the data returned is a character string consisting + of the word 'Yes' if a command is pending for the outlet or 'No' + if there is no command pending for the outlet. At least one + space will delimit each outlet entry in the string. + + If the pending states are unknown, the character string 'Unknown' + will be returned. This signifies that there is an inconsistancy + in the PDU. In the rare case that this should happen, the user + is advised to shut down all equipment powered by the PDU and then + cycle the PDU's power. This will put the PDU in a consistent state." + ::= { sPDUMasterControl 3 } + + +-- the sPDUMasterConfig group + +sPDUMasterConfigPowerOn OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The amount of delay, in seconds, between when + power is provided to the PDU and when the PDU + provides basic master power to the outlets. + + Allowed values are: + + -1 never apply power automatically. + 0 apply power immediately. + 15 apply power in 15 seconds. + 30 apply power in 30 seconds. + 45 apply power in 45 seconds. + 60 apply power in 60 seconds (1 minute). + 120 apply power in 120 seconds (2 minutes). + 300 apply power in 300 seconds (5 minutes). + + If a value other than a supported value is provided in a + set request, the PDU interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used." + + ::= { sPDUMasterConfig 1 } + +sPDUMasterConfigReboot OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "During a reboot sequence, power is turned off and then + back on. This OID defines the amount of time to wait, + in seconds, after turning the power off, at the start + of the sequence, before turning power back on, at the + end of the reboot sequence. + + Allowed values are: + + 5 wait 5 seconds between off/on. + 10 wait 10 seconds between off/on. + 15 wait 15 seconds between off/on. + 20 wait 20 seconds between off/on. + 30 wait 30 seconds between off/on. + 45 wait 45 seconds between off/on. + 60 wait 60 seconds (1 minute) between off/on. + + If a value other than a supported value is provided in a + set request, the PDU interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used. + + This OID is read-only for the MasterSwitch version 2.X and is the + maximum sPDUOutletRebootDuration OID of the individual outlets." + + ::= { sPDUMasterConfig 2 } + +sPDUMasterConfigPDUName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the PDU. The maximum value is 20 characters." + ::= { sPDUMasterConfig 3 } + + + +-- the sPDUOutletControl group +sPDUOutletControlTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of outlets for the PDU." + ::= { sPDUOutletControl 1 } + + +sPDUOutletControlTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletControlEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of individual outlet switches. The number of + entries is contained in the sPDUOutletControlTableSize OID." + ::= { sPDUOutletControl 2 } + +sPDUOutletControlEntry OBJECT-TYPE + SYNTAX OutletControlEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to control." + INDEX { sPDUOutletControlIndex} + ::= { sPDUOutletControlTable 1 } + +OutletControlEntry ::= + SEQUENCE { + sPDUOutletControlIndex INTEGER, + sPDUOutletPending INTEGER, + sPDUOutletCtl INTEGER, + sPDUOutletCtlName DisplayString + } + +sPDUOutletControlIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletControlEntry 1 } + +sPDUOutletPending OBJECT-TYPE + SYNTAX INTEGER{ + commandPending (1), + noCommandPending (2), + commandPendingUnknown (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Reports whether the current outlet has a pending command. + + If the commandPendingUnknown (3) value is returned, all + devices powered by the PDU should be shut down. The PDU's + power should then be cycled to clear this condition." + + ::= { sPDUOutletControlEntry 2 } + +sPDUOutletCtl OBJECT-TYPE + SYNTAX INTEGER { + outletOn (1), + outletOff (2), + outletReboot (3), + outletUnknown (4), + outletOnWithDelay (5), + outletOffWithDelay (6), + outletRebootWithDelay (7) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet state. If + the outlet is on, the outletOn (1) value will be returned. + If the outlet is off, the outletOff (2) value will be + returned. + + If the state of the outlet cannot be determined, the + outletUnknown (4) value will be returned. If the + outletUnknown condition should occur, all devices + powered by the PDU should be shut down. The PDU's power + should then be cycled to clear this condition. + + Setting this variable to outletOn (1) will turn the outlet on. + + Setting this variable to outletOff (2) will turn the outlet off. + + Setting this variable to outletReboot (3) will reboot the outlet. + + Setting this variable to outletOnWithDelay (5) will turn the outlet on + after the sPDUOutletPowerOnTime OID has elapsed. This option is not + valid for MasterSwitch firmware version 1.X. + + Setting this variable to outletOffWithDelay (6) will turn the outlet off + after the sPDUOutletPowerOffTime OID has elapsed. This option is not valid + for MasterSwitch firmware version 1.X. + + Setting this variable to outletRebootWithDelay (7) will turn the outlet off + after the sPDUOutletPowerOffTime OID has elapsed, wait the sPDUOutletRebootDuration + OID time, then turn the outlet back on. + This option is not valid for MasterSwitch firmware version 1.X." + + ::= { sPDUOutletControlEntry 3 } + +sPDUOutletCtlName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. Maximum size is 20 characters. + This OID is provided for informational purposes only. + This value is set by the sPDUOutletName OID." + + ::= { sPDUOutletControlEntry 4 } + +-- the sPDUOutletConfig group +sPDUOutletConfigTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of outlets for the PDU." + ::= { sPDUOutletConfig 1 } + +sPDUOutletConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF SPDUOutletConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The list of outlets to configure. The number of + entries is defined by the sPDUOutletConfigTableSize + OID." + + ::= { sPDUOutletConfig 2 } + +sPDUOutletConfigEntry OBJECT-TYPE + SYNTAX SPDUOutletConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to control." + INDEX { sPDUOutletConfigIndex} + ::= { sPDUOutletConfigTable 1 } + +SPDUOutletConfigEntry ::= + SEQUENCE { + sPDUOutletConfigIndex INTEGER, + sPDUOutletPowerOnTime INTEGER, + sPDUOutletName DisplayString, + sPDUOutletPowerOffTime INTEGER, + sPDUOutletRebootDuration INTEGER + } + +sPDUOutletConfigIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletConfigEntry 1 } + +sPDUOutletPowerOnTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time (in seconds) the outlet will delay + powering on when the MasterSwitch is powered on. + + Allowed values are: + + -1 never power on automatically. + 0 power on with the Master Switch. + 15 power on 15 seconds after the MasterSwitch has power applied. + 30 power on 30 seconds after the MasterSwitch has power applied. + 45 power on 45 seconds after the MasterSwitch has power applied. + 60 power on 60 seconds (1 minute) after the MasterSwitch has power applied. + 120 power on 120 seconds (2 minutes) after the MasterSwitch has power applied. + 300 power on 300 seconds (5 minutes) after the MasterSwitch has power applied. + + If a value other than a supported value is provided in a + set request, the PDU interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used." + + ::= { sPDUOutletConfigEntry 2 } + +sPDUOutletName OBJECT-TYPE + SYNTAX DisplayString ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the outlet. Maximum size is 20 characters." + + ::= { sPDUOutletConfigEntry 3 } + +sPDUOutletPowerOffTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time (in seconds) the outlet will delay + powering off. + + Allowed values are: + + -1 never power off automatically. + 0 power off with the MasterSwitch. + 15 power off 15 seconds after being commanded. + 30 power off 30 seconds after being commanded. + 45 power off 45 seconds after being commanded. + 60 power off 60 seconds (1 minute) after being commanded. + 120 power off 120 seconds (2 minutes) after being commanded. + 300 power off 300 seconds (5 minutes) after being commanded. + + If a value other than a supported value is provided in a + set request, the PDU interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used. + + This OID is not available for MasterSwitch firmware version 1.X." + + ::= { sPDUOutletConfigEntry 4 } + +sPDUOutletRebootDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "During a reboot sequence, power is turned off and then + back on. This OID defines the amount of time to wait, + in seconds, after turning the power off, at the start + of the sequence, before turning power back on, at the + end of the reboot sequence. + + Allowed values are: + + 5 wait 5 seconds between off/on. + 10 wait 10 seconds between off/on. + 15 wait 15 seconds between off/on. + 20 wait 20 seconds between off/on. + 30 wait 30 seconds between off/on. + 45 wait 45 seconds between off/on. + 60 wait 60 seconds (1 minute) between off/on. + + If a value other than a supported value is provided in a + set request, the PDU interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used. + + This OID is not available for MasterSwitch firmware version 1.X." + + ::= { sPDUOutletConfigEntry 5 } + + +-- the sPDUIdentVM group + +sPDUIdentVMTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of MasterSwitch VMs controllable + by this IP address." + ::= { sPDUIdentVM 1 } + + +sPDUIdentVMTable OBJECT-TYPE + SYNTAX SEQUENCE OF IdentVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for query of the individual MasterSwitch VMs. + The number of entries is contained in the + sPDUIdentVMTableSize OID." + ::= { sPDUIdentVM 2 } + +sPDUIdentVMEntry OBJECT-TYPE + SYNTAX IdentVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The MasterSwitch VMs to query." + INDEX { sPDUIdentVMIndex} + ::= { sPDUIdentVMTable 1 } + +IdentVMEntry ::= + SEQUENCE { + sPDUIdentVMIndex INTEGER, + sPDUIdentNameVM DisplayString, + sPDUIdentHardwareRevVM DisplayString, + sPDUIdentFirmwareRevVM DisplayString, + sPDUIdentDateOfManufactureVM DisplayString, + sPDUIdentModelNumberVM DisplayString, + sPDUIdentSerialNumberVM DisplayString + } + +sPDUIdentVMIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch VM entry." + ::= { sPDUIdentVMEntry 1 } + +sPDUIdentNameVM OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 23-character string identifying the + MasterSwitch VM. " + ::= { sPDUIdentVMEntry 2 } + +sPDUIdentHardwareRevVM OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware version of the MasterSwitch VM. + This value is set at the factory." + ::= { sPDUIdentVMEntry 3 } + +sPDUIdentFirmwareRevVM OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An 6-character ID string identifying the MasterSwitch VM + firmware version. This value is set at the factory." + ::= { sPDUIdentVMEntry 4 } + + +sPDUIdentDateOfManufactureVM OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date when the MasterSwitch VM was manufactured in mm/dd/yyyy format. + This value is set at the factory. " + ::= { sPDUIdentVMEntry 5 } + +sPDUIdentModelNumberVM OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 17-character string identifying the model number of + the MasterSwitch VM. This value is set at the factory." + ::= { sPDUIdentVMEntry 6 } + +sPDUIdentSerialNumberVM OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 17-character string identifying the serial number of + the MasterSwitch VM. This value is set at the factory." + ::= { sPDUIdentVMEntry 7 } + + +-- the sPDUMasterControlVM group + +sPDUMasterControlVMTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of MasterSwitch VMs controllable + by this IP address." + ::= { sPDUMasterControlVM 1 } + + +sPDUMasterControlVMTable OBJECT-TYPE + SYNTAX SEQUENCE OF MasterControlVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of the individual MasterSwitch VMs. + The number of entries is contained in the + sPDUMasterControlVMTableSize OID." + ::= { sPDUMasterControlVM 2 } + +sPDUMasterControlVMEntry OBJECT-TYPE + SYNTAX MasterControlVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The MasterSwitch VMs to control." + INDEX { sPDUMasterControlVMIndex} + ::= { sPDUMasterControlVMTable 1 } + +MasterControlVMEntry ::= + SEQUENCE { + sPDUMasterControlVMIndex INTEGER, + sPDUMasterControlVMName DisplayString, + sPDUMasterControlVMCommand INTEGER + } + +sPDUMasterControlVMIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch VM entry." + ::= { sPDUMasterControlVMEntry 1 } + +sPDUMasterControlVMName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch VM. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigVMName OID." + ::= { sPDUMasterControlVMEntry 2 } + +sPDUMasterControlVMCommand OBJECT-TYPE + SYNTAX INTEGER { + noCommandAllVM (1), + immediateAllOnVM (2), + immediateAllOffVM (3), + immediateAllRebootVM (4), + delayedAllOnVM (5), + delayedAllOffVM (6), + sequencedAllRebootVM (7), + delayedAllRebootVM (8), + delayedSequenceAllRebootVM (9), + cancelAllPendingCommandsVM (10), + audioAlarmMute (11) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to immediateAllOnVM (2) will turn all outlets + on immediately. + + Setting this OID to immediateAllOffVM (3) will turn all outlets + off immediately. + + Setting this OID to immediateAllRebootVM (4) will reboot all outlets + immediately. + + Setting this OID to delayedAllOnVM (5) will turn all outlets on as + defined by each outlet's sPDUOutletConfigVMPowerOnTime OID value. + + Setting this OID to delayedAllOffVM (6) will turn all outlets + off as defined by each outlet's sPDUOutletConfigVMPowerOffTime OID value. + + Setting this OID to sequencedAllRebootVM (7) will cause a + immediateAllOffVM command to be performed. The MasterSwitch VM will + then delay the sPDUMasterStatusVMRebootDuration OID time, and then + perform a delayedAllOnVM command. + + Setting this OID to delayedAllRebootVM (8) will cause a delayedAllOffVM + command to be performed. Each outlet will then wait its + sPDUOutletConfigVMRebootDuration before returning power to the outlet. + + Setting this OID to delayedSequenceAllRebootVM (9) will cause a + delayedAllOffVM command to be performed. Once all outlets are off, + the MasterSwitch VM will then delay the sPDUMasterStatusVMRebootDuration + OID time, and then perform a delayedAllOnVM command. + + Setting this OID to cancelAllPendingCommandsVM (10) will cause all pending + commands on the MasterSwitch VM to be canceled. + + + Setting this OID to audioAlarmMute (11) will temporarily silence the audible + alarm for the duration of the current overload condition. The audible alarm + will be activated on subsequent overload alarms. + + Getting this OID will return the noCommandAllVM (1) value." + ::= { sPDUMasterControlVMEntry 3 } + + +-- the sPDUMasterConfigVM group + +sPDUMasterConfigVMTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of MasterSwitch VMs configurable + by this IP address." + ::= { sPDUMasterConfigVM 1 } + + +sPDUMasterConfigVMTable OBJECT-TYPE + SYNTAX SEQUENCE OF MasterConfigVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of the individual MasterSwitch VMs. + The number of entries is contained in the + sPDUMasterConfigVMTableSize OID." + ::= { sPDUMasterConfigVM 2 } + +sPDUMasterConfigVMEntry OBJECT-TYPE + SYNTAX MasterConfigVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The MasterSwitch VMs to configure." + INDEX { sPDUMasterConfigVMIndex} + ::= { sPDUMasterConfigVMTable 1 } + +MasterConfigVMEntry ::= + SEQUENCE { + sPDUMasterConfigVMIndex INTEGER, + sPDUMasterConfigVMName DisplayString, + sPDUMasterConfigVMColdstartDelay INTEGER, + sPDUMasterConfigVMAudioAlarmActivated INTEGER, + sPDUMasterConfigVMHighLoadWarningThreshold INTEGER, + sPDUMasterConfigVMLowLoadWarningThreshold INTEGER, + sPDUMasterConfigVMOverloadRestriction INTEGER + } + +sPDUMasterConfigVMIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch VM entry." + ::= { sPDUMasterConfigVMEntry 1 } + + +sPDUMasterConfigVMName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch VM. Maximum size is 23 characters." + ::= { sPDUMasterConfigVMEntry 2 } + +sPDUMasterConfigVMColdstartDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The amount of delay, in seconds, between when + power is provided to the MasterSwitch VM and + when the MasterSwitch VM provides basic master + power to the outlets. + + Allowed values are: + + -1 never apply power automatically. + 0 apply power immediately. + 15 apply power in 15 seconds. + 30 apply power in 30 seconds. + 45 apply power in 45 seconds. + 60 apply power in 60 seconds (1 minute). + 120 apply power in 120 seconds (2 minutes). + 300 apply power in 300 seconds (5 minutes). + + If a value other than a supported value is provided in a + set request, the MasterSwitch VM interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used." + ::= { sPDUMasterConfigVMEntry 3 } + +sPDUMasterConfigVMAudioAlarmActivated OBJECT-TYPE + SYNTAX INTEGER { + audioAlarmActiveNever (1), + audioAlarmActiveOnOverload (2), + audioAlarmActiveOnOverloadImminent (3) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to audioAlarmActiveNever (1) will disable + the audio alarm on the MasterSwitch VM. + + Setting this OID to audioAlarmActiveOnOverload (2) will + activate the audio alarm on the MasterSwitch VM when an + overload condition is present. + + Setting this OID to audioAlarmActiveOnOverloadImminent (3) + will activate the audio alarm on the MasterSwitch VM when + the load on the MasterSwitch VM has surpassed the + sPDUMasterConfigVMHighLoadWarningThreshold OID value." + ::= { sPDUMasterConfigVMEntry 4 } + +sPDUMasterConfigVMHighLoadWarningThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A threshold that indicates the power consumption of + the load is nearing an overload condition. It is + represented as a percentage of full load." + ::= { sPDUMasterConfigVMEntry 5 } + +sPDUMasterConfigVMLowLoadWarningThreshold OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A threshold that indicates the power consumption of + the load is nearing a low consumption condition. It is + represented as a percentage of full load." + ::= { sPDUMasterConfigVMEntry 6 } + +sPDUMasterConfigVMOverloadRestriction OBJECT-TYPE + SYNTAX INTEGER { + alwaysAllowTurnON (1), + restrictOnWarning (2), + restrictOnOverload (3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This OID controls the behavior of the MasterSwitch VM + when an overload condition is possible and additional + outlets are requested to be turned on. + + Setting this OID to alwaysAllowTurnON (1) will always allow + the outlets to turn on. + + Setting this OID to restrictOnWarning (2) will not allow + outlets to turn on if the sPDUMasterConfigVMHighLoadWarningThreshold + OID is exceeded. + + Setting this OID to restrictOnOverload (3) will not allow + outlets to turn on if the MasterSwitch Vm is in an + overload condition." + ::= { sPDUMasterConfigVMEntry 7 } + +-- the sPDUMasterStatusVM group + +sPDUMasterStatusVMTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of MasterSwitch VMs at + this IP address." + ::= { sPDUMasterStatusVM 1 } + + +sPDUMasterStatusVMTable OBJECT-TYPE + SYNTAX SEQUENCE OF MasterStatusVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for gathering of status from the individual + MasterSwitch VMs. The number of entries is contained + in the sPDUMasterStatusVMTableSize OID." + ::= { sPDUMasterStatusVM 2 } + +sPDUMasterStatusVMEntry OBJECT-TYPE + SYNTAX MasterStatusVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The MasterSwitch VMs to gather status from." + INDEX { sPDUMasterStatusVMIndex} + ::= { sPDUMasterStatusVMTable 1 } + +MasterStatusVMEntry ::= + SEQUENCE { + sPDUMasterStatusVMIndex INTEGER, + sPDUMasterStatusVMName DisplayString, + sPDUMasterStatusVMCommandPending INTEGER, + sPDUMasterStatusVMOverloadCondition INTEGER, + sPDUMasterStatusVMLowLoadCondition INTEGER, + sPDUMasterStatusVMCurrentLoad INTEGER, + sPDUMasterStatusVMMaxLoad INTEGER, + sPDUMasterStatusVMOutletCount INTEGER, + sPDUMasterStatusVMRebootDuration INTEGER + } + +sPDUMasterStatusVMIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch VM entry." + ::= { sPDUMasterStatusVMEntry 1 } + +sPDUMasterStatusVMName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch VM. Maximum size is 23 characters." + ::= { sPDUMasterStatusVMEntry 2 } + +sPDUMasterStatusVMCommandPending OBJECT-TYPE + SYNTAX INTEGER { + commandPendingMasterTrueVM (1), + commandPendingMasterFalseVM (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return commandPendingMasterTrueVM (1) + if the MasterSwitch VM has a pending command on any of its + outlets. + + commandPendingMasterFalseVM (2) will be returned if there are + no pending commands." + ::= { sPDUMasterStatusVMEntry 3 } + +sPDUMasterStatusVMOverloadCondition OBJECT-TYPE + SYNTAX INTEGER { + overloadConditionTrueVM (1), + overloadConditionFalseVM (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return overloadConditionTrueVM (1) + if the sPDUMasterConfigVMHighLoadWarningThreshold OID is + violated. + + overloadConditionFalseVM (2) will be returned if the + sPDUMasterConfigVMHighLoadWarningThreshold OID is not + violated." + ::= { sPDUMasterStatusVMEntry 4 } + +sPDUMasterStatusVMLowLoadCondition OBJECT-TYPE + SYNTAX INTEGER { + lowLoadConditionTrueVM (1), + lowLoadConditionFalseVM (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return lowLoadConditionTrueVM (1) + if the sPDUMasterConfigVMLowLoadWarningThreshold OID is + violated. + + lowLoadConditionFalseVM (2) will be returned if the + sPDUMasterConfigVMHighLoadWarningThreshold OID is not + violated. " + ::= { sPDUMasterStatusVMEntry 5 } + +sPDUMasterStatusVMCurrentLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the total amount of power + being consumed by the load. It is represented as a + percentage of full load." + ::= { sPDUMasterStatusVMEntry 6 } + +sPDUMasterStatusVMMaxLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the total amount of power + that this MasterSwitch VM can provide. It is represented + in Amps." + ::= { sPDUMasterStatusVMEntry 7 } + +sPDUMasterStatusVMOutletCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the number of controllable + outlets for this MasterSwitch VM." + ::= { sPDUMasterStatusVMEntry 8 } + +sPDUMasterStatusVMRebootDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the largest + sPDUOutletConfigVMRebootDuration OID time + for this MasterSwitch VM." + ::= { sPDUMasterStatusVMEntry 9 } + +-- the sPDUOutletControlVM group + + +sPDUOutletControlVMTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletControlVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of individual outlet switches. The number of + entries is contained in the sPDUMasterStatusOutletCount OID." + ::= { sPDUOutletControlVM 1 } + +sPDUOutletControlVMEntry OBJECT-TYPE + SYNTAX OutletControlVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to control." + INDEX { sPDUOutletControlVMIndex, sPDUOutletControlVMOutletIndex } + ::= { sPDUOutletControlVMTable 1 } + +OutletControlVMEntry ::= + SEQUENCE { + sPDUOutletControlVMIndex INTEGER, + sPDUOutletControlVMName DisplayString, + sPDUOutletControlVMOutletIndex INTEGER, + sPDUOutletControlVMOutletName DisplayString, + sPDUOutletControlVMOutletCommand INTEGER + } + +sPDUOutletControlVMIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch VM." + ::= { sPDUOutletControlVMEntry 1 } + +sPDUOutletControlVMName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch VM. Maximum size is 23 characters. + This OID is provided for informational purposes only." + ::= { sPDUOutletControlVMEntry 2 } + +sPDUOutletControlVMOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletControlVMEntry 3 } + +sPDUOutletControlVMOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. Maximum size is 23 characters. + This OID is provided for informational purposes only." + ::= { sPDUOutletControlVMEntry 4 } + +sPDUOutletControlVMOutletCommand OBJECT-TYPE + SYNTAX INTEGER { + immediateOnVM (1), + immediateOffVM (2), + immediateRebootVM (3), + delayedOnVM (4), + delayedOffVM (5), + delayedRebootVM (6), + cancelPendingCommandVM (7) + + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet state. If + the outlet is on, the immediateOnVM (1) value will be returned. + If the outlet is off, the immediateOffVM (2) value will be + returned. + + + Setting this variable to immediateOnVM (1) will immediately turn the outlet on. + + Setting this variable to immediateOffVM (2) will immediately turn the outlet off. + + Setting this variable to immediateRebootVM (3) will immediately reboot the outlet. + + Setting this variable to delayedOnVM (4) will turn the outlet on + after the sPDUOutletConfigVMPowerOnTime OID time has elapsed. + + Setting this variable to delayedOffVM (5) will turn the outlet off + after the sPDUOutletConfigVMPowerOffTime OID time has elapsed. + + Setting this variable to delayedRebootVM (6) will cause the + MasterSwitch VM to perform a delayedOffVM command, wait the + sPDUOutletConfigVMRebootDuration OID time, and then perform the + immediateOnVM command. + + Setting this variable to cancelPendingCommandVM (7) will cause any + pending command to this outlet to be canceled." + ::= { sPDUOutletControlVMEntry 5 } + +-- the sPDUOutletConfigVM group + +sPDUOutletConfigVMTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletConfigVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual outlets. The number of + entries is contained in the sPDUMasterStatusOutletCount OID." + ::= { sPDUOutletConfigVM 1 } + +sPDUOutletConfigVMEntry OBJECT-TYPE + SYNTAX OutletConfigVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to configure." + INDEX { sPDUOutletConfigVMIndex, sPDUOutletConfigVMOutletIndex } + ::= { sPDUOutletConfigVMTable 1 } + +OutletConfigVMEntry ::= + SEQUENCE { + sPDUOutletConfigVMIndex INTEGER, + sPDUOutletConfigVMName DisplayString, + sPDUOutletConfigVMOutletIndex INTEGER, + sPDUOutletConfigVMOutletName DisplayString, + sPDUOutletConfigVMPowerOnTime INTEGER, + sPDUOutletConfigVMPowerOffTime INTEGER, + sPDUOutletConfigVMRebootDuration INTEGER + } + +sPDUOutletConfigVMIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch VM." + ::= { sPDUOutletConfigVMEntry 1 } + +sPDUOutletConfigVMName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch VM. Maximum size is 23 characters." + ::= { sPDUOutletConfigVMEntry 2 } + +sPDUOutletConfigVMOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletConfigVMEntry 3 } + + +sPDUOutletConfigVMOutletName OBJECT-TYPE + SYNTAX DisplayString ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the outlet. Maximum size is 23 characters." + ::= { sPDUOutletConfigVMEntry 4 } + +sPDUOutletConfigVMPowerOnTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time (in seconds) the outlet will delay + powering on at coldstart or when a command that requires + a turn-on delay is issued. + + Allowed values are: + + -1 never power on. + 0 power on immediately. + 15 power on 15 seconds after being commanded. + 30 power on 30 seconds after being commanded. + 45 power on 45 seconds after being commanded. + 60 power on 60 seconds (1 minute) after being commanded. + 120 power on 120 seconds (2 minutes) after being commanded. + 300 power on 300 seconds (5 minutes) after being commanded. + + If a value other than a supported value is provided in a + set request, the MasterSwitch VM interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used." + ::= { sPDUOutletConfigVMEntry 5 } + + +sPDUOutletConfigVMPowerOffTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time (in seconds) the outlet will delay + powering off when a command that requires + a turn-off delay is issued. + + + Allowed values are: + + -1 never power off automatically. + 0 power off immediately. + 15 power off 15 seconds after being commanded. + 30 power off 30 seconds after being commanded. + 45 power off 45 seconds after being commanded. + 60 power off 60 seconds (1 minute) after being commanded. + 120 power off 120 seconds (2 minutes) after being commanded. + 300 power off 300 seconds (5 minutes) after being commanded. + + If a value other than a supported value is provided in a + set request, the MasterSwitch VM interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used." + ::= { sPDUOutletConfigVMEntry 6 } + +sPDUOutletConfigVMRebootDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "During a reboot sequence, power is turned off and then + back on. This OID defines the amount of time to wait, + in seconds, after turning the power off, at the start + of the sequence, before turning power back on, at the + end of the reboot sequence. + + Allowed values are: + + 5 wait 5 seconds between off/on. + 10 wait 10 seconds between off/on. + 15 wait 15 seconds between off/on. + 20 wait 20 seconds between off/on. + 30 wait 30 seconds between off/on. + 45 wait 45 seconds between off/on. + 60 wait 60 seconds (1 minute) between off/on. + + If a value other than a supported value is provided in a + set request, the MasterSwitch VM interprets it as the next lower + acceptable value. If the provided value is lower than + the lowest acceptable value, the lowest acceptable + value is used." + ::= { sPDUOutletConfigVMEntry 7 } + +-- the sPDUOutletStatusVM group + +sPDUOutletStatusVMTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletStatusVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting of status of individual outlets. The number of + entries is contained in the sPDUMasterStatusOutletCount OID." + ::= { sPDUOutletStatusVM 1 } + +sPDUOutletStatusVMEntry OBJECT-TYPE + SYNTAX OutletStatusVMEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to gather status from." + INDEX { sPDUOutletStatusVMIndex, sPDUOutletStatusVMOutletIndex } + ::= { sPDUOutletStatusVMTable 1 } + +OutletStatusVMEntry ::= + SEQUENCE { + sPDUOutletStatusVMIndex INTEGER, + sPDUOutletStatusVMName DisplayString, + sPDUOutletStatusVMOutletIndex INTEGER, + sPDUOutletStatusVMOutletName DisplayString, + sPDUOutletStatusVMOutletState INTEGER, + sPDUOutletStatusVMCommandPending INTEGER + } + +sPDUOutletStatusVMIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch VM." + ::= { sPDUOutletStatusVMEntry 1 } + +sPDUOutletStatusVMName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch VM. Maximum size is 23 characters." + ::= { sPDUOutletStatusVMEntry 2 } + +sPDUOutletStatusVMOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletStatusVMEntry 3 } + +sPDUOutletStatusVMOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. Maximum size is 23 characters." + ::= { sPDUOutletStatusVMEntry 4 } + +sPDUOutletStatusVMOutletState OBJECT-TYPE + SYNTAX INTEGER { + outletStatusVMOn (1), + outletStatusVMOff (2) + } + + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet state. If + the outlet is on, the outletStatusOnVM (1) value will be returned. + If the outlet is off, the outletStatusOffVM (2) value will be + returned. " + ::= { sPDUOutletStatusVMEntry 5 } + +sPDUOutletStatusVMCommandPending OBJECT-TYPE + SYNTAX INTEGER { + outletStatusVMCommandPending (1), + outletStatusVMNoCommandPending (2) + } + + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the command pending + state of the outlet. If a command is pending on the + outlet, the outletStatusVMCommandPending (1) value + will be returned. If there is not a command pending + on the outlet, the outletStatusVMNoCommandPending (2) + will be returned." + ::= { sPDUOutletStatusVMEntry 6 } + +-- the sPDUIdentMSP group + +sPDUIdentMSPTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of MasterSwitch pluses controllable + by this IP address." + ::= { sPDUIdentMSP 1 } + + +sPDUIdentMSPTable OBJECT-TYPE + SYNTAX SEQUENCE OF IdentMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for query of the individual MasterSwitch pluses. + The number of entries is contained in the + sPDUIdentMSPTableSize OID." + ::= { sPDUIdentMSP 2 } + +sPDUIdentMSPEntry OBJECT-TYPE + SYNTAX IdentMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The MasterSwitch pluses to query." + INDEX { sPDUIdentMSPIndex} + ::= { sPDUIdentMSPTable 1 } + +IdentMSPEntry ::= + SEQUENCE { + sPDUIdentMSPIndex INTEGER, + sPDUIdentNameMSP DisplayString, + sPDUIdentHardwareRevMSP DisplayString, + sPDUIdentFirmwareRevMSP DisplayString, + sPDUIdentDateOfManufactureMSP DisplayString, + sPDUIdentModelNumberMSP DisplayString, + sPDUIdentSerialNumberMSP DisplayString + } + +sPDUIdentMSPIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch plus entry." + ::= { sPDUIdentMSPEntry 1 } + +sPDUIdentNameMSP OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigMSPName OID." + ::= { sPDUIdentMSPEntry 2 } + +sPDUIdentHardwareRevMSP OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware version of the MasterSwitch plus. + This value is set at the factory." + ::= { sPDUIdentMSPEntry 3 } + +sPDUIdentFirmwareRevMSP OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An 6-character ID string identifying the MasterSwitch plus + firmware version. This value is set at the factory." + ::= { sPDUIdentMSPEntry 4 } + +sPDUIdentDateOfManufactureMSP OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date when the MasterSwitch plus was manufactured in mm/dd/yyyy format. + This value is set at the factory. " + ::= { sPDUIdentMSPEntry 5 } + +sPDUIdentModelNumberMSP OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 17-character string identifying the model number of + the MasterSwitch plus. This value is set at the factory." + ::= { sPDUIdentMSPEntry 6 } + +sPDUIdentSerialNumberMSP OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 17-character string identifying the serial number of + the MasterSwitch plus. This value is set at the factory." + ::= { sPDUIdentMSPEntry 7 } + + +-- the sPDUMasterControlMSP group + +sPDUMasterControlMSPTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of MasterSwitch pluses controllable + by this IP address." + ::= { sPDUMasterControlMSP 1 } + +sPDUMasterControlMSPTable OBJECT-TYPE + SYNTAX SEQUENCE OF MasterControlMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of the individual MasterSwitch pluses. + The number of entries is contained in the + sPDUMasterControlMSPTableSize OID." + ::= { sPDUMasterControlMSP 2 } + +sPDUMasterControlMSPEntry OBJECT-TYPE + SYNTAX MasterControlMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The MasterSwitch pluses to control." + INDEX { sPDUMasterControlMSPIndex} + ::= { sPDUMasterControlMSPTable 1 } + +MasterControlMSPEntry ::= + SEQUENCE { + sPDUMasterControlMSPIndex INTEGER, + sPDUMasterControlMSPName DisplayString, + sPDUMasterControlMSPCommand INTEGER + } + +sPDUMasterControlMSPIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch plus entry." + ::= { sPDUMasterControlMSPEntry 1 } + +sPDUMasterControlMSPName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigMSPName OID." + ::= { sPDUMasterControlMSPEntry 2 } + +sPDUMasterControlMSPCommand OBJECT-TYPE + SYNTAX INTEGER { + noCommandAllMSP (1), + immediateAllOnMSP (2), + sequencedAllOnMSP (3), + immediateAllOffMSP (4), + gracefulAllRebootMSP (5), + immediateAllRebootMSP (6), + gracefulAllShutdownMSP (7), + overrideAllBatCapThreshMSP (8), + cancelAllPendingCommandsMSP (9), + restoreFactoryDefaultsMSP (10) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to immediateAllOnMSP (2) will turn all outlets + on immediately. + + Setting this OID to sequencedAllOnMSP (3) will turn all outlets + on as defined by each outlet's sPDUOutletConfigMSPPowerOnDelay OID value. + + Setting this OID to immediateAllOffMSP (4) will turn all outlets + off immediately. + + Setting this OID to gracefulAllRebootMSP (5) will reboot all outlets + (after the device running PowerChute confirms shutdown) as defined + by each outlet's sPDUOutletConfigMSPRebootDuration OID time value. + + Setting this OID to immediateAllRebootMSP (6) will reboot all outlets + immediately. + + Setting this OID to gracefulAllShutdownMSP (7) will shutdown all outlets + (after the device running PowerChute confirms shutdown) as defined + by each outlet's sPDUOutletConfigMSPPowerOffDelay OID time value. Each + outlet will then turn on after the sum of its + sPDUOutletConfigMSPRestartDelay and sPDUOutletConfigMSPPowerOnDelay OID + values. + + Setting this OID to overrideAllBatCapThreshMSP (8) will cause the + outlet to ignore the Battery Capacity Threshold and proceed turning on + the outlets as defined by each outlet's sPDUOutletConfigMSPPowerOnDelay + OID value. + + Setting this OID to cancelAllPendingCommandsMSP (9) will cause all pending + commands on the MasterSwitch plus to be canceled. + + Setting this OID to restoreFactoryDefaultsMSP (10) will cause the settings of + the MasterSwitch plus to be restored to the factory defaults. + + Getting this OID will return the noCommandAllMSP (1) value." + ::= { sPDUMasterControlMSPEntry 3 } + + +-- the sPDUMasterConfigMSP group + +sPDUMasterConfigMSPTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of MasterSwitch pluses configurable + by this IP address." + ::= { sPDUMasterConfigMSP 1 } + +sPDUMasterConfigMSPTable OBJECT-TYPE + SYNTAX SEQUENCE OF MasterConfigMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of the individual MasterSwitch pluses. + The number of entries is contained in the + sPDUMasterConfigMSPTableSize OID." + ::= { sPDUMasterConfigMSP 2 } + +sPDUMasterConfigMSPEntry OBJECT-TYPE + SYNTAX MasterConfigMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The MasterSwitch pluses to configure." + INDEX { sPDUMasterConfigMSPIndex} + ::= { sPDUMasterConfigMSPTable 1 } + +MasterConfigMSPEntry ::= + SEQUENCE { + sPDUMasterConfigMSPIndex INTEGER, + sPDUMasterConfigMSPName DisplayString, + sPDUMasterConfigMSPPowerOnTimeDelay INTEGER, + sPDUMasterConfigMSPManualButton INTEGER + } + +sPDUMasterConfigMSPIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch plus entry." + ::= { sPDUMasterConfigMSPEntry 1 } + +sPDUMasterConfigMSPName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. Maximum size is 23 characters." + ::= { sPDUMasterConfigMSPEntry 2 } + +sPDUMasterConfigMSPPowerOnTimeDelay OBJECT-TYPE + SYNTAX INTEGER (0..9999) + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The amount of delay, in seconds, between when + power is provided to the MasterSwitch plus and + when the MasterSwitch plus provides basic master + power to the outlets. + + Allowed values are: + + 0 - 9999 seconds (0 - 2hrs, 46 mins, 39 secs). + 0 indicates to apply power immediately." + ::= { sPDUMasterConfigMSPEntry 3 } + + +sPDUMasterConfigMSPManualButton OBJECT-TYPE + SYNTAX INTEGER { + manualButtonDisabled (1), + manualButtonEnabled (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to manualButtonDisabled (1) will disable + the manual button on the MasterSwitch plus. + + Setting this OID to manualButtonEnabled (2) will enable + the manual button on the MasterSwitch plus." + ::= { sPDUMasterConfigMSPEntry 4 } + +-- the sPDUMasterStatusMSP group + +sPDUMasterStatusMSPTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of MasterSwitch pluses at + this IP address." + ::= { sPDUMasterStatusMSP 1 } + + +sPDUMasterStatusMSPTable OBJECT-TYPE + SYNTAX SEQUENCE OF MasterStatusMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for gathering of status from the individual + MasterSwitch pluses. The number of entries is contained + in the sPDUMasterStatusMSPTableSize OID." + ::= { sPDUMasterStatusMSP 2 } + +sPDUMasterStatusMSPEntry OBJECT-TYPE + SYNTAX MasterStatusMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The MasterSwitch pluses to gather status from." + INDEX { sPDUMasterStatusMSPIndex} + ::= { sPDUMasterStatusMSPTable 1 } + +MasterStatusMSPEntry ::= + SEQUENCE { + sPDUMasterStatusMSPIndex INTEGER, + sPDUMasterStatusMSPName DisplayString, + sPDUMasterStatusMSPOutletCount INTEGER + } + +sPDUMasterStatusMSPIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch plus entry." + ::= { sPDUMasterStatusMSPEntry 1 } + +sPDUMasterStatusMSPName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigMSPName OID." + ::= { sPDUMasterStatusMSPEntry 2 } + +sPDUMasterStatusMSPOutletCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the number of controllable + outlets for this MasterSwitch plus." + ::= { sPDUMasterStatusMSPEntry 3 } + +-- the sPDUOutletControlMSP group + +sPDUOutletControlMSPTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletControlMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of individual outlet switches. The number of + entries is contained in the sPDUMasterStatusMSPOutletCount OID." + ::= { sPDUOutletControlMSP 1 } + +sPDUOutletControlMSPEntry OBJECT-TYPE + SYNTAX OutletControlMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to control." + INDEX { sPDUOutletControlMSPIndex, sPDUOutletControlMSPOutletIndex } + ::= { sPDUOutletControlMSPTable 1 } + +OutletControlMSPEntry ::= + SEQUENCE { + sPDUOutletControlMSPIndex INTEGER, + sPDUOutletControlMSPName DisplayString, + sPDUOutletControlMSPOutletIndex INTEGER, + sPDUOutletControlMSPOutletName DisplayString, + sPDUOutletControlMSPOutletCommand INTEGER + } + +sPDUOutletControlMSPIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch plus." + ::= { sPDUOutletControlMSPEntry 1 } + +sPDUOutletControlMSPName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigMSPName OID." + ::= { sPDUOutletControlMSPEntry 2 } + +sPDUOutletControlMSPOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletControlMSPEntry 3 } + +sPDUOutletControlMSPOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. The maximum size is + 23 characters. The name is set by using the + sPDUOutletConfigMSPallOutletName OID. + This OID is provided for informational purposes only." + ::= { sPDUOutletControlMSPEntry 4 } + +sPDUOutletControlMSPOutletCommand OBJECT-TYPE + SYNTAX INTEGER { + immediateOnMSP (1), + delayedOnMSP (2), + immediateOffMSP (3), + gracefulRebootMSP (4), + immediateRebootMSP (5), + gracefulshutdownMSP (6), + overrideBatCapThreshMSP (7), + cancelPendingCommandMSP (8) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet state. If + the outlet is on, the immediateOnMSP (1) value will be returned. + If the outlet is off, the immediateOffMSP (3) value will be + returned. + + Setting this variable to immediateOnMSP (1) will immediately turn the outlet on. + + Setting this variable to delayedOnMSP (2) will turn the outlet on + after the sPDUOutletConfigMSPPowerOnDelay OID time has elapsed. + + Setting this variable to immediateOffMSP (3) will immediately turn the outlet off. + + Setting this variable to gracefulRebootMSP (4) will cause the outlet to wait for + device confirmation (if applicable) and then turn the outlet off after the + sPDUOutletConfigMSPPowerOffDelay OID time has elapsed. The outlet will then turn + on after the sPDUOutletConfigMSPRebootDuration OID time has elapsed. + + Setting this variable to immediateRebootMSP (5) will immediately reboot the outlet. + + Setting this variable to gracefulshutdownMSP (6) will cause the outlet to wait for + device confirmation (if applicable) and then turn the outlet off after the + sPDUOutletConfigMSPPowerOffDelay OID time has elapsed. The outlet will then turn + on after the sum of the sPDUOutletConfigMSPRestartTime OID time and the + sPDUOutletConfigMSPPowerOnDelay OID time has elapsed. + + Setting this variable to overrideBatCapThreshMSP (7) will cause the outlet to + ignore the Battery Capacity Threshold and proceed waiting on the + sPDUOutletConfigMSPPowerOnDelay OID time before turning the outlet on. + + Setting this variable to cancelPendingCommandMSP (8) will cause any + pending command to this outlet to be canceled." + ::= { sPDUOutletControlMSPEntry 5 } + +-- the sPDUOutletConfigMSPall group + +sPDUOutletConfigMSPallTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletConfigMSPallEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual outlets. The number of + entries is contained in the sPDUMasterStatusMSPOutletCount OID." + ::= { sPDUOutletConfigMSPall 1 } + +sPDUOutletConfigMSPallEntry OBJECT-TYPE + SYNTAX OutletConfigMSPallEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to configure." + INDEX { sPDUOutletConfigMSPallIndex, sPDUOutletConfigMSPallOutletIndex } + ::= { sPDUOutletConfigMSPallTable 1 } + +OutletConfigMSPallEntry ::= + SEQUENCE { + sPDUOutletConfigMSPallIndex INTEGER, + sPDUOutletConfigMSPallName DisplayString, + sPDUOutletConfigMSPallOutletIndex INTEGER, + sPDUOutletConfigMSPallOutletName DisplayString, + sPDUOutletConfigMSPallOutletCtrlMode INTEGER + } + +sPDUOutletConfigMSPallIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch plus." + ::= { sPDUOutletConfigMSPallEntry 1 } + +sPDUOutletConfigMSPallName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigMSPName OID." + ::= { sPDUOutletConfigMSPallEntry 2 } + +sPDUOutletConfigMSPallOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletConfigMSPallEntry 3 } + +sPDUOutletConfigMSPallOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the outlet. Maximum size is 23 characters." + ::= { sPDUOutletConfigMSPallEntry 4 } + +sPDUOutletConfigMSPallOutletCtrlMode OBJECT-TYPE + SYNTAX INTEGER { + modeGracefulShutdown (1), + modeAnnunciator (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to modeGracefulShutdown (1) will put this + outlet into the Graceful Shutdown control mode. + + Setting this OID to modeAnnunciator (2) will put this outlet + into the Annunciator control mode." + ::= { sPDUOutletConfigMSPallEntry 5 } + + +-- the sPDUOutConfigMSPgs group + +sPDUOutletConfigMSPgsTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletConfigMSPgsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual outlets. The number of + entries is contained in the sPDUMasterStatusMSPOutletCount OID." + ::= { sPDUOutletConfigMSPgs 1 } + +sPDUOutletConfigMSPgsEntry OBJECT-TYPE + SYNTAX OutletConfigMSPgsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to configure." + INDEX { sPDUOutletConfigMSPgsIndex, sPDUOutletConfigMSPgsOutletIndex } + ::= { sPDUOutletConfigMSPgsTable 1 } + +OutletConfigMSPgsEntry ::= + SEQUENCE { + sPDUOutletConfigMSPgsIndex INTEGER, + sPDUOutletConfigMSPgsName DisplayString, + sPDUOutletConfigMSPgsOutletIndex INTEGER, + sPDUOutletConfigMSPgsOutletName DisplayString, + sPDUOutletConfigMSPgsOutletCtrlMode INTEGER, + sPDUOutletConfigMSPgsDeviceConfirm INTEGER, + sPDUOutletConfigMSPgsLowBattWarning INTEGER, + sPDUOutletConfigMSPgsLowBattMult INTEGER, + sPDUOutletConfigMSPgsRestartDelay INTEGER, + sPDUOutletConfigMSPgsPowerOnDelay INTEGER, + sPDUOutletConfigMSPgsPowerOffDelay INTEGER, + sPDUOutletConfigMSPgsBattCapThresh INTEGER, + sPDUOutletConfigMSPgsRebootDuration INTEGER + } + +sPDUOutletConfigMSPgsIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch plus." + ::= { sPDUOutletConfigMSPgsEntry 1 } + +sPDUOutletConfigMSPgsName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigMSPName OID." + ::= { sPDUOutletConfigMSPgsEntry 2 } + +sPDUOutletConfigMSPgsOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletConfigMSPgsEntry 3 } + +sPDUOutletConfigMSPgsOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. The maximum size is + 23 characters. The name is set by using the + sPDUOutletConfigMSPallOutletName OID. + This OID is provided for informational purposes only." + ::= { sPDUOutletConfigMSPgsEntry 4 } + +sPDUOutletConfigMSPgsOutletCtrlMode OBJECT-TYPE + SYNTAX INTEGER { + modeGracefulShutdown (1), + modeAnnunciator (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Control Mode of the outlet. + This OID is provided for informational purposes only." + ::= { sPDUOutletConfigMSPgsEntry 5 } + +sPDUOutletConfigMSPgsDeviceConfirm OBJECT-TYPE + SYNTAX INTEGER { + deviceConfirmNo (1), + deviceConfirmYes (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to deviceConfirmNo (1) cause the outlet to + NOT wait for device confirmation while performing graceful + operations. + + Setting this OID to deviceConfirmYes (2) cause the outlet to + wait for device confirmation while performing graceful + operations." + ::= { sPDUOutletConfigMSPgsEntry 6 } + +sPDUOutletConfigMSPgsLowBattWarning OBJECT-TYPE + SYNTAX INTEGER (-2..9999) + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The amount of delay, in 6 second intervals, between + when the UPS goes on battery and the power down sequence for + the outlet is initiated. + + Allowed values are: + + -2 - Never initiate the power down sequence on low battery warning. + -1 - Initiate power down sequence based on remaining runtime. + 1 - 9999 six second intervals (6 secs - 16hrs, 39 mins, 54 secs). + 0 indicates to immediately initiate power down sequence on low + battery warning." + ::= { sPDUOutletConfigMSPgsEntry 7 } + +sPDUOutletConfigMSPgsLowBattMult OBJECT-TYPE + SYNTAX INTEGER (1..7) + ACCESS read-write + STATUS mandatory + DESCRIPTION + " Only applicable if sPDUOutletConfigMSPgsLowBattWarning OID is + set to -1 (On Runtime Remaining). + + Allows you to set the value to stagger the shutdown sequence of the outlets. + 1 provides the longest delay (the outlet to shutoff first), and 7 would + provide the shortest delay (the outlet to shut off last). + + Allowed values are: + 1 - 7." + ::= { sPDUOutletConfigMSPgsEntry 8 } + +sPDUOutletConfigMSPgsRestartDelay OBJECT-TYPE + SYNTAX INTEGER (-1..9999) + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The amount of delay, in 6 minute intervals, between + when the outlet is turned off and the outlet is turned back on + when performing a Graceful Shutdown. + + Allowed values are: + + -1 - Never turn outlet back on after a Graceful shutdown. + 0 - 9999 six minute intervals (0 - 999hrs, 54 mins)." + ::= { sPDUOutletConfigMSPgsEntry 9 } + +sPDUOutletConfigMSPgsPowerOnDelay OBJECT-TYPE + SYNTAX INTEGER (-1..9999) + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The amount of delay, in seconds, between the UPS entering + normal (on-line) state and the outlet being powered on. + + Allowed values are: + + -1 - Remain Off when the UPS enters the on-line state. + 0 - 9999 seconds (0 - 2 hrs, 46 mins, 39 secs)." + ::= { sPDUOutletConfigMSPgsEntry 10 } + + +sPDUOutletConfigMSPgsPowerOffDelay OBJECT-TYPE + SYNTAX INTEGER (0..9999) + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The amount of delay, in seconds, between when the server + shuts down and the outlet is powered off. + + Allowed values are: + + 0 - 9999 seconds (0 - 2 hrs, 46 mins, 39 secs)." + ::= { sPDUOutletConfigMSPgsEntry 11 } + +sPDUOutletConfigMSPgsBattCapThresh OBJECT-TYPE + SYNTAX INTEGER (0..100) + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The minimum battery capacity, as a percent (0-100%), required + of the UPS before an outlet will be allowed to power on. + + Allowed values are: + + 0 - 100 percent." + ::= { sPDUOutletConfigMSPgsEntry 12 } + +sPDUOutletConfigMSPgsRebootDuration OBJECT-TYPE + SYNTAX INTEGER (0..9999) + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The amount of delay, in seconds, from outlet off until + outlet on during a reboot. + + Allowed values are: + + 0 - 9999 seconds (0 - 2 hrs, 46 mins, 39 secs)." + ::= { sPDUOutletConfigMSPgsEntry 13 } + + +-- the sPDUOutConfigMSPannun group + +sPDUOutletConfigMSPannunTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletConfigMSPannunEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual outlets. The number of + entries is contained in the sPDUMasterStatusMSPOutletCount OID." + ::= { sPDUOutletConfigMSPannun 1 } + +sPDUOutletConfigMSPannunEntry OBJECT-TYPE + SYNTAX OutletConfigMSPannunEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to configure." + INDEX { sPDUOutletConfigMSPannunIndex, sPDUOutletConfigMSPannunOutletIndex } + ::= { sPDUOutletConfigMSPannunTable 1 } + +OutletConfigMSPannunEntry ::= + SEQUENCE { + sPDUOutletConfigMSPannunIndex INTEGER, + sPDUOutletConfigMSPannunName DisplayString, + sPDUOutletConfigMSPannunOutletIndex INTEGER, + sPDUOutletConfigMSPannunOutletName DisplayString, + sPDUOutletConfigMSPannunOutletCtrlMode INTEGER, + sPDUOutletConfigMSPannunInitialState INTEGER, + sPDUOutletConfigMSPannunAlarmActionDly INTEGER + } + +sPDUOutletConfigMSPannunIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch plus." + ::= { sPDUOutletConfigMSPannunEntry 1 } + +sPDUOutletConfigMSPannunName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigMSPName OID." + ::= { sPDUOutletConfigMSPannunEntry 2 } + +sPDUOutletConfigMSPannunOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletConfigMSPannunEntry 3 } + +sPDUOutletConfigMSPannunOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. The maximum size is + 23 characters. The name is set by using the + sPDUOutletConfigMSPallOutletName OID. + This OID is provided for informational purposes only." + ::= { sPDUOutletConfigMSPannunEntry 4 } + +sPDUOutletConfigMSPannunOutletCtrlMode OBJECT-TYPE + SYNTAX INTEGER { + modeGracefulShutdown (1), + modeAnnunciator (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Control Mode of the outlet. + This OID is provided for informational purposes only." + ::= { sPDUOutletConfigMSPannunEntry 5 } + +sPDUOutletConfigMSPannunInitialState OBJECT-TYPE + SYNTAX INTEGER { + initialStateOff (1), + initialStateOn (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to initialStateOff (1) causes the outlet + to default to off when in the non-alarmed condition. + + Setting this OID to initialStateOn (2) causes the outlet + to default to on when in the non-alarmed condition." + ::= { sPDUOutletConfigMSPannunEntry 6 } + +sPDUOutletConfigMSPannunAlarmActionDly OBJECT-TYPE + SYNTAX INTEGER (0..9999) + ACCESS read-write + STATUS mandatory + DESCRIPTION + " The amount of time, in seconds, that an enabled Measure-UPS + alarm must be asserted before an alarm condition is recognized. + + Allowed values are: + + 0 - 9999 seconds (0 - 2 hrs, 46 mins, 39 secs)." + ::= { sPDUOutletConfigMSPannunEntry 7 } + + +-- the sPDUOutConfigMSPmups group + +sPDUOutletConfigMSPmupsTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletConfigMSPmupsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual outlets. The number of + entries is contained in the sPDUMasterStatusMSPOutletCount OID." + ::= { sPDUOutletConfigMSPmups 1 } + +sPDUOutletConfigMSPmupsEntry OBJECT-TYPE + SYNTAX OutletConfigMSPmupsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to configure." + INDEX { sPDUOutletConfigMSPmupsIndex, sPDUOutletConfigMSPmupsOutletIndex } + ::= { sPDUOutletConfigMSPmupsTable 1 } + +OutletConfigMSPmupsEntry ::= + SEQUENCE { + sPDUOutletConfigMSPmupsIndex INTEGER, + sPDUOutletConfigMSPmupsName DisplayString, + sPDUOutletConfigMSPmupsOutletIndex INTEGER, + sPDUOutletConfigMSPmupsOutletName DisplayString, + sPDUOutletConfigMSPmupsZone1 INTEGER, + sPDUOutletConfigMSPmupsZone2 INTEGER, + sPDUOutletConfigMSPmupsZone3 INTEGER, + sPDUOutletConfigMSPmupsZone4 INTEGER, + sPDUOutletConfigMSPmupsP1LowHum INTEGER, + sPDUOutletConfigMSPmupsP1HiHum INTEGER, + sPDUOutletConfigMSPmupsP1LowTemp INTEGER, + sPDUOutletConfigMSPmupsP1HiTemp INTEGER, + sPDUOutletConfigMSPmupsP2LowHum INTEGER, + sPDUOutletConfigMSPmupsP2HiHum INTEGER, + sPDUOutletConfigMSPmupsP2LowTemp INTEGER, + sPDUOutletConfigMSPmupsP2HiTemp INTEGER + } + +sPDUOutletConfigMSPmupsIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch plus." + ::= { sPDUOutletConfigMSPmupsEntry 1 } + +sPDUOutletConfigMSPmupsName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigMSPName OID." + ::= { sPDUOutletConfigMSPmupsEntry 2 } + +sPDUOutletConfigMSPmupsOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletConfigMSPmupsEntry 3 } + +sPDUOutletConfigMSPmupsOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. The maximum size is + 23 characters. The name is set by using the + sPDUOutletConfigMSPallOutletName OID. + This OID is provided for informational purposes only." + ::= { sPDUOutletConfigMSPmupsEntry 4 } + +sPDUOutletConfigMSPmupsZone1 OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Zone 1 alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Zone 1 alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 5 } + +sPDUOutletConfigMSPmupsZone2 OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Zone 2 alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Zone 2 alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 6 } + +sPDUOutletConfigMSPmupsZone3 OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Zone 3 alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Zone 3 alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 7 } + +sPDUOutletConfigMSPmupsZone4 OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Zone 4 alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Zone 4 alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 8 } + +sPDUOutletConfigMSPmupsP1LowHum OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Probe 1 low humidity alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Probe 1 low humidity alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 9 } + +sPDUOutletConfigMSPmupsP1HiHum OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Probe 1 high humidity alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Probe 1 high humidity alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 10 } + +sPDUOutletConfigMSPmupsP1LowTemp OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Probe 1 low temperature alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Probe 1 low temperature alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 11 } + +sPDUOutletConfigMSPmupsP1HiTemp OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Probe 1 high temperature alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Probe 1 high temperature alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 12 } + +sPDUOutletConfigMSPmupsP2LowHum OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Probe 2 low humidity alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Probe 2 low humidity alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 13 } + +sPDUOutletConfigMSPmupsP2HiHum OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Probe 2 high humidity alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Probe 2 high humidity alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 14 } + +sPDUOutletConfigMSPmupsP2LowTemp OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Probe 2 low temperature alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Probe 2 low temperature alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 15 } + +sPDUOutletConfigMSPmupsP2HiTemp OBJECT-TYPE + SYNTAX INTEGER { + disableAlarm (1), + enableAlarm (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to disableAlarm (1) disables the + Probe 2 high temperature alarm for this outlet. + + Setting this OID to enableAlarm (2) enables the + Probe 2 high temperature alarm for this outlet." + ::= { sPDUOutletConfigMSPmupsEntry 16 } + +-- the sPDUOutletStatusMSP group + +sPDUOutletStatusMSPTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletStatusMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting of status of individual outlets. The number of + entries is contained in the sPDUMasterStatusOutletCount OID." + ::= { sPDUOutletStatusMSP 1 } + +sPDUOutletStatusMSPEntry OBJECT-TYPE + SYNTAX OutletStatusMSPEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to gather status from." + INDEX { sPDUOutletStatusMSPIndex, sPDUOutletStatusMSPOutletIndex } + ::= { sPDUOutletStatusMSPTable 1 } + +OutletStatusMSPEntry ::= + SEQUENCE { + sPDUOutletStatusMSPIndex INTEGER, + sPDUOutletStatusMSPName DisplayString, + sPDUOutletStatusMSPOutletIndex INTEGER, + sPDUOutletStatusMSPOutletName DisplayString, + sPDUOutletStatusMSPOutletState INTEGER, + sPDUOutletStatusMSPCommandPending INTEGER, + sPDUOutletStatusMSPOutletCtrlMode INTEGER + } + +sPDUOutletStatusMSPIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the MasterSwitch MSP." + ::= { sPDUOutletStatusMSPEntry 1 } + +sPDUOutletStatusMSPName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the MasterSwitch plus. The maximum + value is 23 characters. The name is set by + using the sPDUMasterConfigMSPName OID." + ::= { sPDUOutletStatusMSPEntry 2 } + +sPDUOutletStatusMSPOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { sPDUOutletStatusMSPEntry 3 } + +sPDUOutletStatusMSPOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. The maximum size is + 23 characters. The name is set by using the + sPDUOutletConfigMSPallOutletName OID. + This OID is provided for informational purposes only." + ::= { sPDUOutletStatusMSPEntry 4 } + +sPDUOutletStatusMSPOutletState OBJECT-TYPE + SYNTAX INTEGER { + outletStatusMSPOn (1), + outletStatusMSPOff (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet state. If + the outlet is on, the outletStatusMSPOn (1) value will be returned. + If the outlet is off, the outletStatusMSPOff (2) value will be + returned. " + ::= { sPDUOutletStatusMSPEntry 5 } + +sPDUOutletStatusMSPCommandPending OBJECT-TYPE + SYNTAX INTEGER { + outletStatusMSPCommandPending (1), + outletStatusMSPNoCommandPending (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the command pending + state of the outlet. If a command is pending on the + outlet, the outletStatusMSPCommandPending (1) value + will be returned. If there is not a command pending + on the outlet, the outletStatusMSPNoCommandPending (2) + will be returned." + ::= { sPDUOutletStatusMSPEntry 6 } + +sPDUOutletStatusMSPOutletCtrlMode OBJECT-TYPE + SYNTAX INTEGER { + modeGracefulShutdown (1), + modeAnnunciator (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Control Mode of the outlet. + This OID is provided for informational purposes only." + ::= { sPDUOutletStatusMSPEntry 7 } + + +-- the rPDUIdent group + +rPDUIdentName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the Rack PDU. + The maximum string size is device dependent." + ::= { rPDUIdent 1 } + +rPDUIdentHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the Rack PDU. + This value is set at the factory." + ::= { rPDUIdent 2 } + +rPDUIdentFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An 8-byte ID string identifying the Rack PDU firmware revision. + This value is set at the factory." + ::= { rPDUIdent 3 } + + +rPDUIdentDateOfManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date when the Rack PDU was manufactured in mm/dd/yy format. + This value is set at the factory. The year 2000 will be + represented by 00." + ::= { rPDUIdent 4 } + +rPDUIdentModelNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 10-character string identifying the model number of + the Rack PDU. This value is set at the factory." + ::= { rPDUIdent 5 } + +rPDUIdentSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 12-character string identifying the serial number of + the Rack PDU. This value is set at the factory." + ::= { rPDUIdent 6 } + +rPDUIdentDeviceRating OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the electrical rating of the device." + + ::= { rPDUIdent 7 } + +rPDUIdentDeviceNumOutlets OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the number of outlets contained in the device." + + ::= { rPDUIdent 8 } + +rPDUIdentDeviceNumPhases OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the number of phases supported by the device." + + ::= { rPDUIdent 9 } + +rPDUIdentDeviceNumBreakers OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the number of circuit breakers supported by the device. + This is the same as the number of banks of outlets." + + ::= { rPDUIdent 10 } + +rPDUIdentDeviceBreakerRating OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return rating of the circuit breakers on the device if it has any." + + ::= { rPDUIdent 11 } + +rPDUIdentDeviceOrientation OBJECT-TYPE + SYNTAX INTEGER { + orientHorizontal (1), + orientVertical (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the intended physical orientation of the device. + + OrientHorizonatal(1) indicates Horizontal. + OrientVertical(2) indicates Vertical." + + ::= { rPDUIdent 12 } + +rPDUIdentDeviceOutletLayout OBJECT-TYPE + SYNTAX INTEGER { + seqPhaseToNeutral (1), + seqPhaseToPhase (2), + seqPhToNeu21PhToPh (3), + seqPhToPhGrouped (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return outlet layout for the device. + + SeqPhaseToNeutral(1) indicates outlet layout as follows: + 1:1-N,2:2-N,3:3-N,4:1-N,5:2-N,... + + SeqPhaseToPhase(2) indicates outlet layout as follows: + 1:1-2,2:2-3,3:3-1,4:1-2,5:2-3,... + + SeqPhToNeu21PhToPh(3) indicates outlet layout as follows: + 1:1-N,2:2-N...21:3-N,22:1-2,23:2-3,24:3-1,... + + SeqPhToPhGrouped(4) indicates outlet layout as follows: + Otlts1-8::(3-1),Otlts9-16::(2-3),Otlts17-24::(1-2)." + ::= { rPDUIdent 13 } + + + +-- the rPDULoadDevice group + +rPDULoadDevMaxPhaseLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the maximum rated power + that each phase of the Rack PDU can provide. It is + represented in Amps." + ::= { rPDULoadDevice 1 } + +rPDULoadDevNumPhases OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of phases available with this Rack PDU." + ::= { rPDULoadDevice 2 } + +rPDULoadDevMaxBankLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the maximum rated power + that each bank of the Rack PDU can provide. It is + represented in Amps. + + 0 will be returned if the device does not have any banks." + + ::= { rPDULoadDevice 3 } + +rPDULoadDevNumBanks OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of banks of outlets available with this Rack PDU. + A bank of outlets has a unique circuit breaker for a subset + of the total number of outlets on the rPDU." + ::= { rPDULoadDevice 4 } + +-- the rPDULoadPhaseConfig group + +rPDULoadPhaseConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF LoadPhaseConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of each Rack PDU phase. + The number of entries is contained in the + rPDULoadDevNumPhases OID." + ::= { rPDULoadPhaseConfig 1 } + +rPDULoadPhaseConfigEntry OBJECT-TYPE + SYNTAX LoadPhaseConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The Rack PDU phase to configure." + INDEX { rPDULoadPhaseConfigIndex} + ::= { rPDULoadPhaseConfigTable 1 } + +LoadPhaseConfigEntry ::= + SEQUENCE { + rPDULoadPhaseConfigIndex INTEGER, + rPDULoadPhaseConfigLowLoadThreshold INTEGER, + rPDULoadPhaseConfigNearOverloadThreshold INTEGER, + rPDULoadPhaseConfigOverloadThreshold INTEGER + } + +rPDULoadPhaseConfigIndex OBJECT-TYPE + SYNTAX INTEGER { + phase1 (1), + phase2 (2), + phase3 (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the Rack PDU phase entry." + ::= { rPDULoadPhaseConfigEntry 1 } + +rPDULoadPhaseConfigLowLoadThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A threshold that indicates the power consumption of + the load is nearing a low consumption condition. It is + represented in amps. A warning will be issued when the + load is less than the threshold value. + + A threshold value of 0 amps effectively disables this + warning. + + Maximum value must be less than the value returned + by the rPDULoadPhaseConfigNearOverloadThreshold OID." + ::= { rPDULoadPhaseConfigEntry 2 } + +rPDULoadPhaseConfigNearOverloadThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A threshold that indicates the power consumption of + the load is nearing an overload condition. It is + represented in amps. A warning will be issued when the + load is greater than or equal to the threshold value. + + Minimum value must be greater than the value returned by + the rPDULoadPhaseConfigLowLoadThreshold OID. + + Maximum value must be less than or equal to the value + returned by the rPDULoadPhaseConfigOverloadThreshold OID." + ::= { rPDULoadPhaseConfigEntry 3 } + +rPDULoadPhaseConfigOverloadThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A threshold that indicates the power consumption of + the load has entered an overload condition. It is + represented in amps. A warning will be issued when the + load is greater than or equal to the threshold value. + + Minimum value must be greater than or equal to the value + returned by the rPDULoadPhaseConfigNearOverloadThreshold OID. + + Maximum value must be less than or equal to the value + returned by the rPDULoadDevMaxPhaseLoad OID." + ::= { rPDULoadPhaseConfigEntry 4 } + + +-- the rPDULoadStatus group + +rPDULoadStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF LoadStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting of status of each Rack PDU phase/bank. + The number of entries is calculated by adding + the number of phases (rPDULoadDevNumPhases OID) and + the number of banks of outlets (rPDULoadDevNumBanks) + Number of entries = #phases + #banks. + NOTE: If a device has phase and bank information, all phase information + shall preceed the bank information." + ::= { rPDULoadStatus 1 } + +rPDULoadStatusEntry OBJECT-TYPE + SYNTAX LoadStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The Rack PDU phase/bank to gather status from." + INDEX { rPDULoadStatusIndex} + ::= { rPDULoadStatusTable 1 } + +LoadStatusEntry ::= + SEQUENCE { + rPDULoadStatusIndex INTEGER, + rPDULoadStatusLoad Gauge, + rPDULoadStatusLoadState INTEGER, + rPDULoadStatusPhaseNumber INTEGER, + rPDULoadStatusBankNumber INTEGER + } + +rPDULoadStatusIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the Rack PDU phase/bank entry. All phase information will preceed + any bank information" + ::= { rPDULoadStatusEntry 1 } + +rPDULoadStatusLoad OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the phase/bank load measured + in tenths of amps." + ::= { rPDULoadStatusEntry 2 } + +rPDULoadStatusLoadState OBJECT-TYPE + SYNTAX INTEGER { + phaseLoadNormal (1), + phaseLoadLow (2), + phaseLoadNearOverload (3), + phaseLoadOverload (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return the phase/bank load state. + + phaseLoadNormal(1) indicates that the phase/bank is + operating properly within the rPDULoadConfigLowLoadThreshold + and rPDULoadConfigNearOverloadThreshold OID values. + + phaseLoadLow(2) indicates that the phase/bank load has + dropped below the rPDULoadConfigLowLoadThreshold OID value. + An SNMP trap will occur when this state is entered or cleared. + + phaseLoadNearOverload(3) indicates that the phase/bank load + is greater than or equal to the + rPDULoadConfigNearOverloadThreshold OID value. + An SNMP trap will occur when this state is entered or cleared. + + phaseLoadOverload(4) indicates that the phase/bank load is + greater than or equal to the rPDULoadConfigOverloadThreshold + OID value. + An SNMP trap will occur when this state is entered or cleared." + ::= { rPDULoadStatusEntry 3 } + +rPDULoadStatusPhaseNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The phase number to which this record refers. A value of 0 will be returned if + this is bank related information." + ::= { rPDULoadStatusEntry 4 } + +rPDULoadStatusBankNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The bank number to which this record refers. A value of 0 will be returned if + this is phase related information." + ::= { rPDULoadStatusEntry 5 } + +-- the rPDULoadBankConfig group + +rPDULoadBankConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF LoadBankConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of each Rack PDU bank. + The number of entries is contained in the + rPDULoadDevNumBanks OID." + ::= { rPDULoadBankConfig 1 } + +rPDULoadBankConfigEntry OBJECT-TYPE + SYNTAX LoadBankConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The Rack PDU bank to configure." + INDEX { rPDULoadBankConfigIndex} + ::= { rPDULoadBankConfigTable 1 } + +LoadBankConfigEntry ::= + SEQUENCE { + rPDULoadBankConfigIndex INTEGER, + rPDULoadBankConfigLowLoadThreshold INTEGER, + rPDULoadBankConfigNearOverloadThreshold INTEGER, + rPDULoadBankConfigOverloadThreshold INTEGER + } + +rPDULoadBankConfigIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the Rack PDU bank entry." + ::= { rPDULoadBankConfigEntry 1 } + +rPDULoadBankConfigLowLoadThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A threshold that indicates the power consumption of + the load is nearing a low consumption condition. It is + represented in amps. A warning will be issued when the + load is less than the threshold value. + + A threshold value of 0 amps effectively disables this + warning. + + Maximum value must be less than the value returned + by the rPDULoadBankConfigNearOverloadThreshold OID. + + -1 will be returned if the device has no banks." + + ::= { rPDULoadBankConfigEntry 2 } + +rPDULoadBankConfigNearOverloadThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A threshold that indicates the power consumption of + the load is nearing an overload condition. It is + represented in amps. A warning will be issued when the + load is greater than or equal to the threshold value. + + Minimum value must be greater than the value returned by + the rPDULoadBankConfigLowLoadThreshold OID. + + Maximum value must be less than or equal to the value + returned by the rPDULoadBankConfigOverloadThreshold OID. + + -1 will be returned if the device has no banks." + + ::= { rPDULoadBankConfigEntry 3 } + +rPDULoadBankConfigOverloadThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A threshold that indicates the power consumption of + the load has entered an overload condition. It is + represented in amps. A warning will be issued when the + load is greater than or equal to the threshold value. + + Minimum value must be greater than or equal to the value + returned by the rPDULoadBankConfigNearOverloadThreshold OID. + + Maximum value must be less than or equal to the value + returned by the rPDULoadDevMaxBankLoad OID. + + -1 will be returned if the device has no banks." + + ::= { rPDULoadBankConfigEntry 4 } + + +-- the rPDUOutletDevice group + +rPDUOutletDevCommand OBJECT-TYPE + SYNTAX INTEGER { + noCommandAll (1), + immediateAllOn (2), + immediateAllOff (3), + immediateAllReboot (4), + delayedAllOn (5), + delayedAllOff (6), + delayedAllReboot (7), + cancelAllPendingCommands (8), + gracefulAllOff (9), + gracefulAllReboot (10) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this OID to immediateAllOn (2) will turn all outlets + on immediately. + + Setting this OID to immediateAllOff (3) will turn all outlets + off immediately. + + Setting this OID to immediateAllReboot (4) will reboot all outlets + immediately. + + Setting this OID to delayedAllOn (5) will turn all outlets on as + defined by each outlet's rPDUOutletConfigPowerOnTime OID value. + + Setting this OID to delayedAllOff (6) will turn all outlets + off as defined by each outlet's rPDUOutletConfigPowerOffTime OID value. + + Setting this OID to delayedAllReboot (7) will cause a + delayedAllOff command to be performed. Once all outlets are off, + the Switched Rack PDU will then delay the largest + rPDUOutletConfigRebootDuration OID time, and then perform a + delayedAllOn command. + + Setting this OID to cancelAllPendingCommands (8) will cause all pending + commands on the Switched Rack PDU to be canceled. + + Setting this variable to gracefulAllOff (9) will cause the + Switched Rack PDU to shut all outlets off after it waits the + servers graceful shutdown time and each outlet's shutdown delay. + + Setting this variable to gracefulAllReboot (10) will cause the + Switched Rack PDU to shut all outlets off after it waits the + servers graceful shutdown time and each outlet's shutdown delay. + Once all outlet are off, it will wait until the UPS reaches the + configured minimum return battery capacity, then each outlet's + return delay before it turns the outlet back on. + + Getting this OID will return the noCommandAll (1) value." + ::= { rPDUOutletDevice 1 } + +rPDUOutletDevColdstartDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of delay, in seconds, between when + power is provided to the Switched Rack PDU and + when the Switched Rack PDU provides basic master + power to the outlets. + + Allowed values are: + + -1 - never apply power automatically. + 0 - apply power immediately. + 1 to 300 - delay up to 300 seconds (5 minutes)." + ::= { rPDUOutletDevice 2 } + +rPDUOutletDevNumCntrlOutlets OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of controlled outlets on this Switched Rack PDU." + ::= { rPDUOutletDevice 3 } + +rPDUOutletDevNumTotalOutlets OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of outlets on this Rack PDU." + ::= { rPDUOutletDevice 4 } + + +-- the rPDUOutletPhase group + +rPDUOutletPhaseTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for management of outlets on a per phase basis." + ::= { rPDUOutletPhase 1 } + +rPDUOutletPhaseEntry OBJECT-TYPE + SYNTAX OutletPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The phase to manage." + INDEX { rPDUOutletPhaseIndex} + ::= { rPDUOutletPhaseTable 1 } + +OutletPhaseEntry ::= + SEQUENCE { + rPDUOutletPhaseIndex INTEGER, + rPDUOutletPhaseOverloadRestriction INTEGER + } + +rPDUOutletPhaseIndex OBJECT-TYPE + SYNTAX INTEGER { + phase1 (1), + phase2 (2), + phase3 (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the Switched Rack PDU phase entry." + ::= { rPDUOutletPhaseEntry 1 } + +rPDUOutletPhaseOverloadRestriction OBJECT-TYPE + SYNTAX INTEGER { + alwaysAllowTurnON (1), + restrictOnNearOverload (2), + restrictOnOverload (3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This OID controls the behavior of a Switched Rack PDU + phase when an overload condition is possible and + additional outlets are requested to be turned on. + + Setting this OID to alwaysAllowTurnON (1) will always allow + the outlets on the corresponding phase to turn on. + + Setting this OID to restrictOnNearOverload (2) will not allow + outlets on the corresponding phase to turn on if the + rPDULoadConfigNearOverloadThreshold OID is exceeded. + + Setting this OID to restrictOnOverload (3) will not allow + outlets on the corresponding phase to turn on if the + rPDULoadConfigOverloadThreshold OID is exceeded." + ::= { rPDUOutletPhaseEntry 2 } + + +-- the rPDUOutletControl group + +rPDUOutletControlTable OBJECT-TYPE + SYNTAX SEQUENCE OF RPDUOutletControlEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of the individual outlets. + The number of entries is contained in the + rPDUOutletDevNumCntrlOutlets OID." + ::= { rPDUOutletControl 1 } + +rPDUOutletControlEntry OBJECT-TYPE + SYNTAX RPDUOutletControlEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlet to control." + INDEX { rPDUOutletControlIndex} + ::= { rPDUOutletControlTable 1 } + +RPDUOutletControlEntry ::= + SEQUENCE { + rPDUOutletControlIndex INTEGER, + rPDUOutletControlOutletName DisplayString, + rPDUOutletControlOutletPhase INTEGER, + rPDUOutletControlOutletCommand INTEGER, + rPDUOutletControlOutletBank INTEGER + } + +rPDUOutletControlIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { rPDUOutletControlEntry 1 } + +rPDUOutletControlOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. Maximum size is dependent on device. + An error will be returned if the set request exceeds the max size. + This OID is provided for informational purposes only." + ::= { rPDUOutletControlEntry 2 } + +rPDUOutletControlOutletPhase OBJECT-TYPE + SYNTAX INTEGER { + phase1 (1), + phase2 (2), + phase3 (3), + phase1-2 (4), + phase2-3 (5), + phase3-1 (6) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The phase/s associated with this outlet. + + For single phase devices, this object will always + return phase1(1). + + For 3-phase devices, this object will return phase1 (1), + phase2 (2), or phase3 (3) for outlets tied to a single + phase. For outlets tied to two phases, this object will + return phase1-2 (4) for phases 1 and 2, phase2-3 (5) for + phases 2 and 3, and phase3-1 (6) for phases 3 and 1." + ::= { rPDUOutletControlEntry 3 } + +rPDUOutletControlOutletCommand OBJECT-TYPE + SYNTAX INTEGER { + immediateOn (1), + immediateOff (2), + immediateReboot (3), + delayedOn (4), + delayedOff (5), + delayedReboot (6), + cancelPendingCommand (7), + gracefulOff (8), + gracefulReboot (9) + + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet state. If + the outlet is on, the immediateOn (1) value will be returned. + If the outlet is off, the immediateOff (2) value will be + returned. + + + Setting this variable to immediateOn (1) will immediately turn + the outlet on. + + Setting this variable to immediateOff (2) will immediately turn + the outlet off. + + Setting this variable to immediateReboot (3) will immediately + reboot the outlet. + + Setting this variable to delayedOn (4) will turn the outlet on + after the rPDUOutletConfigPowerOnTime OID time has elapsed. + + Setting this variable to delayedOff (5) will turn the outlet off + after the rPDUOutletConfigPowerOffTime OID time has elapsed. + + Setting this variable to delayedReboot (6) will cause the + Switched Rack PDU to perform a delayedOff command, wait the + rPDUOutletConfigRebootDuration OID time, and then perform a + delayedOn command. + + Setting this variable to cancelPendingCommand (7) will cause any + pending command to this outlet to be canceled. + + Setting this variable to gracefulOff (8) will cause the + Switched Rack PDU to shut the outlet off after it waits the + servers graceful shutdown time and the outlets shutdown delay. + + Setting this variable to gracefulReboot (9) will cause the + Switched Rack PDU to shut the outlet off after it waits the + servers graceful shutdown time and the outlets shutdown delay. + Once the outlet is off, it will wait until the UPS reaches the + configured minimum return battery capacity, then the outlets + return delay before it turns the outlet back on." + + ::= { rPDUOutletControlEntry 4 } + +rPDUOutletControlOutletBank OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The bank associated with this outlet." + ::= { rPDUOutletControlEntry 5 } + + +-- the rPDUOutletConfig group + +rPDUOutletConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF RPDUOutletConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual outlets. The number of + entries is contained in the rPDUOutletDevNumCntrlOutlets OID." + ::= { rPDUOutletConfig 1 } + +rPDUOutletConfigEntry OBJECT-TYPE + SYNTAX RPDUOutletConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlet to configure." + INDEX { rPDUOutletConfigIndex} + ::= { rPDUOutletConfigTable 1 } + +RPDUOutletConfigEntry ::= + SEQUENCE { + rPDUOutletConfigIndex INTEGER, + rPDUOutletConfigOutletName DisplayString, + rPDUOutletConfigOutletPhase INTEGER, + rPDUOutletConfigPowerOnTime INTEGER, + rPDUOutletConfigPowerOffTime INTEGER, + rPDUOutletConfigRebootDuration INTEGER, + rPDUOutletConfigOutletBank INTEGER + } + +rPDUOutletConfigIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { rPDUOutletConfigEntry 1 } + +rPDUOutletConfigOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the outlet. Maximum size is dependent on device. + An error will be returned if the set request exceeds the max size." + ::= { rPDUOutletConfigEntry 2 } + +rPDUOutletConfigOutletPhase OBJECT-TYPE + SYNTAX INTEGER { + phase1 (1), + phase2 (2), + phase3 (3), + phase1-2 (4), + phase2-3 (5), + phase3-1 (6) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The phase/s associated with this outlet. + + For single phase devices, this object will always + return phase1(1). + + For 3-phase devices, this object will return phase1 (1), + phase2 (2), or phase3 (3) for outlets tied to a single + phase. For outlets tied to two phases, this object will + return phase1-2 (4) for phases 1 and 2, phase2-3 (5) for + phases 2 and 3, and phase3-1 (6) for phases 3 and 1." + ::= { rPDUOutletConfigEntry 3 } + +rPDUOutletConfigPowerOnTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time (in seconds) the outlet will delay + powering on at coldstart or when a command that requires + a turn-on delay is issued. + + Allowed values are: + + -1 - never power on. + 0 - power on immediately. + 1 to 300 - power on up to 300 seconds (5 minutes) after being + commanded." + ::= { rPDUOutletConfigEntry 4 } + +rPDUOutletConfigPowerOffTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The amount of time (in seconds) the outlet will delay + powering off when a command that requires + a turn-off delay is issued. + + Allowed values are: + + -1 - never power off. + 0 - power off immediately. + 1 to 300 - power off up to 300 seconds (5 minutes) after being + commanded." + ::= { rPDUOutletConfigEntry 5 } + +rPDUOutletConfigRebootDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "During a reboot sequence, power is turned off and then + back on. This OID defines the amount of time to wait, + in seconds, after turning the power off, at the start + of the sequence, before turning power back on, at the + end of the reboot sequence. + + Allowed range is any value between 5 and 60 seconds (1 minute)." + ::= { rPDUOutletConfigEntry 6 } + +rPDUOutletConfigOutletBank OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The bank associated with this outlet." + ::= { rPDUOutletConfigEntry 7 } + + +-- the rPDUOutletStatus group + +rPDUOutletStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF RPDUOutletStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting of status of individual outlets. The number of + entries is contained in the rPDUOutletDevNumCntrlOutlets OID." + ::= { rPDUOutletStatus 1 } + +rPDUOutletStatusEntry OBJECT-TYPE + SYNTAX RPDUOutletStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlet to gather status from." + INDEX { rPDUOutletStatusIndex} + ::= { rPDUOutletStatusTable 1 } + +RPDUOutletStatusEntry ::= + SEQUENCE { + rPDUOutletStatusIndex INTEGER, + rPDUOutletStatusOutletName DisplayString, + rPDUOutletStatusOutletPhase INTEGER, + rPDUOutletStatusOutletState INTEGER, + rPDUOutletStatusCommandPending INTEGER, + rPDUOutletStatusOutletBank INTEGER + } + +rPDUOutletStatusIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { rPDUOutletStatusEntry 1 } + +rPDUOutletStatusOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. Maximum size is dependent on device. + An error will be returned if the set request exceeds the max size. + This OID is provided for informational purposes only." + ::= { rPDUOutletStatusEntry 2 } + +rPDUOutletStatusOutletPhase OBJECT-TYPE + SYNTAX INTEGER { + phase1 (1), + phase2 (2), + phase3 (3), + phase1-2 (4), + phase2-3 (5), + phase3-1 (6) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The phase/s associated with this outlet. + + For single phase devices, this object will always + return phase1(1). + + For 3-phase devices, this object will return phase1 (1), + phase2 (2), or phase3 (3) for outlets tied to a single + phase. For outlets tied to two phases, this object will + return phase1-2 (4) for phases 1 and 2, phase2-3 (5) for + phases 2 and 3, and phase3-1 (6) for phases 3 and 1." + ::= { rPDUOutletStatusEntry 3 } + +rPDUOutletStatusOutletState OBJECT-TYPE + SYNTAX INTEGER { + outletStatusOn (1), + outletStatusOff (2) + } + + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet state. If + the outlet is on, the outletStatusOn (1) value will be returned. + If the outlet is off, the outletStatusOff (2) value will be + returned. " + ::= { rPDUOutletStatusEntry 4 } + +rPDUOutletStatusCommandPending OBJECT-TYPE + SYNTAX INTEGER { + outletStatusCommandPending (1), + outletStatusNoCommandPending (2) + } + + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the command pending + state of the outlet. If a command is pending on the + outlet, the outletStatusCommandPending (1) value + will be returned. If there is not a command pending + on the outlet, the outletStatusNoCommandPending (2) + will be returned." + ::= { rPDUOutletStatusEntry 5 } + +rPDUOutletStatusOutletBank OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The bank associated with this outlet." + ::= { rPDUOutletStatusEntry 6 } + + +-- the rPDUOutletBank group + +rPDUOutletBankTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletBankEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for management of outlets on a per bank basis." + ::= { rPDUOutletBank 1 } + +rPDUOutletBankEntry OBJECT-TYPE + SYNTAX OutletBankEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The bank to manage." + INDEX { rPDUOutletBankIndex} + ::= { rPDUOutletBankTable 1 } + +OutletBankEntry ::= + SEQUENCE { + rPDUOutletBankIndex INTEGER, + rPDUOutletBankOverloadRestriction INTEGER + } + +rPDUOutletBankIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the Switched Rack PDU bank entry." + ::= { rPDUOutletBankEntry 1 } + +rPDUOutletBankOverloadRestriction OBJECT-TYPE + SYNTAX INTEGER { + alwaysAllowTurnON (1), + restrictOnNearOverload (2), + restrictOnOverload (3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This OID controls the behavior of a Switched Rack PDU + bank when an overload condition is possible and + additional outlets are requested to be turned on. + + Setting this OID to alwaysAllowTurnON (1) will always allow + the outlets on the corresponding bank to turn on. + + Setting this OID to restrictOnNearOverload (2) will not allow + outlets on the corresponding bank to turn on if the + rPDULoadConfigNearOverloadThreshold OID is exceeded. + + Setting this OID to restrictOnOverload (3) will not allow + outlets on the corresponding bank to turn on if the + rPDULoadConfigOverloadThreshold OID is exceeded." + ::= { rPDUOutletBankEntry 2 } + +-- the rPDUPowerSupplyDevice group + +rPDUPowerSupply1Status OBJECT-TYPE + SYNTAX INTEGER { + powerSupply1Ok (1), + powerSupply1Failed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return powerSupply1Ok(1) if power + supply 1 is functioning normally. If not functioning normally, + this OID will return powerSupply1Failed(2)." + ::= { rPDUPowerSupplyDevice 1 } + +rPDUPowerSupply2Status OBJECT-TYPE + SYNTAX INTEGER { + powerSupply2Ok (1), + powerSupply2Failed (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return powerSupply2Ok(1) if power + supply 2 is functioning normally. If not functioning normally, + this OID will return powerSupply2Failed(2)." + ::= { rPDUPowerSupplyDevice 2 } + + + +-- the dm3IdentSystem group + +dm3IdentSysDescriptionTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC description records." + ::= { dm3IdentSystem 1 } + +dm3IdentSysDescriptionTable OBJECT-TYPE + SYNTAX SEQUENCE OF IdentSysDescriptionEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing description records of the powerplant. The number of + entries is contained in the dm3IdentSysDescriptionTableSize OID." + ::= { dm3IdentSystem 2 } + +dm3IdentSysDescriptionEntry OBJECT-TYPE + SYNTAX IdentSysDescriptionEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The powerplant description record to reference." + INDEX { dm3IdentSysDescriptionIndex } + ::= { dm3IdentSysDescriptionTable 1 } + +IdentSysDescriptionEntry ::= + SEQUENCE { + dm3IdentSysDescriptionIndex INTEGER, + dm3IdentSysDescriptionText DisplayString + } + +dm3IdentSysDescriptionIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant description record." + ::= { dm3IdentSysDescriptionEntry 1 } + +dm3IdentSysDescriptionText OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A 16 character text field describing the DC power plant device. + This field can be configured from the dm3ConfigSysDescriptionText OID." + ::= { dm3IdentSysDescriptionEntry 2 } + +dm3IdentSysModel OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Model type of the DC power plant." + ::= { dm3IdentSystem 3 } + +dm3IdentSysCntrlRev OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Integer representation of the hardware revision of the Master Controller board." + ::= { dm3IdentSystem 4 } + +dm3IdentSysFWVersion OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Integer representation of the power plant Master Controller firmware revision." + ::= { dm3IdentSystem 5 } + +-- the dm3ConfigSystem group + +dm3ConfigSysDescriptionTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC description records." + ::= { dm3ConfigSystem 1 } + +dm3ConfigSysDescriptionTable OBJECT-TYPE + SYNTAX SEQUENCE OF ConfigSysDescriptionEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing description records of the powerplant. The number of + entries is contained in the dm3ConfigSysDescriptionTableSize OID." + ::= { dm3ConfigSystem 2 } + +dm3ConfigSysDescriptionEntry OBJECT-TYPE + SYNTAX ConfigSysDescriptionEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The powerplant description record to reference." + INDEX { dm3ConfigSysDescriptionIndex } + ::= { dm3ConfigSysDescriptionTable 1 } + +ConfigSysDescriptionEntry ::= + SEQUENCE { + dm3ConfigSysDescriptionIndex INTEGER, + dm3ConfigSysDescriptionText DisplayString + } + +dm3ConfigSysDescriptionIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant description record." + + ::= { dm3ConfigSysDescriptionEntry 1 } + +dm3ConfigSysDescriptionText OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "16 character text field describing the DC power plant device." + + ::= { dm3ConfigSysDescriptionEntry 2 } + +dm3ConfigSysHighTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Ambient high temperature threshold. Temperature sensor located on Master + Controller board. + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dm3StatusSysTempUnits' OID (Celsius or Fahrenheit). + + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigSystem 3 } + +dm3ConfigSysHighTempAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the System High Temperature Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + ::= { dm3ConfigSystem 4 } + +dm3ConfigSysLowTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Ambient low temperature threshold. Temperature sensor located on Master + Controller board. + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dm3StatusSysTempUnits' OID (Celsius or Fahrenheit). + + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigSystem 5 } + +dm3ConfigSysLowTempAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the System Low Temperature Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + ::= { dm3ConfigSystem 6 } + +dm3ConfigSysHardwareTempAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the System Hardware Temperature Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + ::= { dm3ConfigSystem 7 } + +dm3ConfigSysRemoteAccess OBJECT-TYPE + SYNTAX INTEGER { + accessEnabled (1), + accessDisabled (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + " + This OID is used to disable remote write access to the power plant. + Setting this OID to accessEnabled (1) will have no affect. + Setting this OID to accessDisabled (2) will disable the ability to + remotely configure the DC powerplant. + + Once remote access is disabled, it can only be restored from the front + panel of the DC power plant." + ::= { dm3ConfigSystem 8 } + + +-- the dm3ConfigLVD group + +dm3ConfigLVDTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant LVDs controllable + by this IP address." + ::= { dm3ConfigLVD 1 } + +dm3ConfigLVDTable OBJECT-TYPE + SYNTAX SEQUENCE OF ConfigLVDEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing settings of the LVDs. The number of + entries is contained in the dm3ConfigLVDTableSize OID." + ::= { dm3ConfigLVD 2 } + +dm3ConfigLVDEntry OBJECT-TYPE + SYNTAX ConfigLVDEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The LVD to configure." + INDEX { dm3ConfigLVDIndex } + ::= { dm3ConfigLVDTable 1 } + +ConfigLVDEntry ::= + SEQUENCE { + dm3ConfigLVDIndex INTEGER, + dm3ConfigLVDName DisplayString, + dm3ConfigLVDEnable INTEGER, + dm3ConfigLVDTripThresh INTEGER, + dm3ConfigLVDResetThresh INTEGER, + dm3ConfigLVDOpenAlarm INTEGER, + dm3ConfigLVDHWAlarm INTEGER + } + +dm3ConfigLVDIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant LVD." + ::= { dm3ConfigLVDEntry 1 } + +dm3ConfigLVDName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the LVD. The maximum value is 16 characters." + ::= { dm3ConfigLVDEntry 2 } + +dm3ConfigLVDEnable OBJECT-TYPE + SYNTAX INTEGER { + enabledYes (1), + enabledNo (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This OID is used to control and indicate if the LVD is on or off. + Setting this OID to enabledYes (1) will enable (turn on) the LVD. + Setting this OID to enabledNo (2) will disable (turn off) the LVD." + ::= { dm3ConfigLVDEntry 3 } + +dm3ConfigLVDTripThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "LVD Trip threshold. If voltage exceeds threshold, the LVD will trip. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigLVDEntry 4 } + +dm3ConfigLVDResetThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "LVD Reset threshold. If voltage exceeds threshold, the LVD will reset. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigLVDEntry 5 } + +dm3ConfigLVDOpenAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the LVD Open Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + ::= { dm3ConfigLVDEntry 6 } + +dm3ConfigLVDHWAlarm OBJECT-TYPE +SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the LVD Hardware Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + ::= { dm3ConfigLVDEntry 7 } + + +-- the dm3ConfigBattery group + +dm3ConfigBattFloatVolt OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery Float Voltage. This setting controls the power plant voltage. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigBattery 1 } + +dm3ConfigBattMaxRecharge OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery Maximum Recharge Rate. This setting controls the battery max + recharge rate. The value is based on C/20 for 240 AHr battery string. + + Values are represented in thousandths of Amps (mA). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigBattery 2 } + +dm3ConfigBattDischargeThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery discharge threshold. If battery output current exceeds threshold + a battery discharge alarm will occur. + + Values are represented in thousandths of Amps (mA). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigBattery 3 } + +dm3ConfigBattDischargeAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Battery Discharge Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigBattery 4 } + +dm3ConfigBattHighVoltThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery high voltage threshold. If system battery voltage exceeds threshold + a battery high voltage alarm will occur. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigBattery 5 } + +dm3ConfigBattHighVoltAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Battery High Voltage Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigBattery 6 } + +dm3ConfigBattLowVoltThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery low voltage threshold. If system battery voltage is under threshold + a battery low voltage alarm will occur. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigBattery 7 } + +dm3ConfigBattLowVoltAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Battery Low Voltage Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigBattery 8 } + +dm3ConfigBattHighTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery high temperature threshold. If system battery temperature exceeds threshold + a battery high temperature alarm will occur. + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dm3StatusSysTempUnits' OID (Celsius or Fahrenheit). + + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + + ::= { dm3ConfigBattery 9 } + +dm3ConfigBattHighTempAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Battery High Temperature Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigBattery 10 } + +dm3ConfigBattLowTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery low temperature threshold. If system battery temperature is under threshold + a battery low temperature alarm will occur. + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dm3StatusSysTempUnits' OID (Celsius or Fahrenheit). + + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + + ::= { dm3ConfigBattery 11 } + +dm3ConfigBattLowTempAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Battery Low Temperature Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigBattery 12 } + +dm3ConfigBattAmpHour OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery Amp-Hour Size. Units are thousandths of Amp hours (mAHr). + + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigBattery 13 } + +dm3ConfigCompMethod OBJECT-TYPE + SYNTAX INTEGER { + tempcompOn (1), + tempcompOff (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This OID is used to configure and get the state of the battery + temperature compensation. + + Setting this OID to tempcompOn (1) will enable/turn on the battery temperature compensation. + Setting this OID to tempcompOff (2) will disable/turn off the battery temperature compensation." + ::= { dm3ConfigBattery 14 } + +dm3ConfigCompTempCoeff OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Compensation Temperature Coefficient. (uV/degC/cell). + + Units are presented in microvolts. + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigBattery 15 } + +dm3ConfigHighKneeTemp OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "High Knee for temperature compensation: Compensation temperature coefficient + becomes 0mV/degC/cell. + + Values are represented in thousandths of degrees Celcius. + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigBattery 16 } + +dm3ConfigLowKneeTemp OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Low Knee for temperature compensation: Compensation temperature coefficient + becomes 0mV/degC/cell. + + Values are represented in thousandths of degrees Celcius. + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigBattery 17 } + +dm3ConfigBattHwCurrentAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Battery Current Hardware Alarm (indicating current is outside realistic + limits, or a possible measurement fault; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigBattery 18 } + +dm3ConfigBattHwTempAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Battery Temperature Hardware Alarm (indicating temperature is outside realistic + limits, or a possible measurement fault; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigBattery 19 } + + +-- the dm3ConfigRectThresh group +dm3ConfigRectHighVoltThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Rectifier high voltage threshold. If rectifier voltage exceeds threshold + a rectifier high voltage alarm will occur. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigRectThresh 1 } + + +dm3ConfigRectLowVoltThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Rectifier low voltage threshold. If rectifier voltage is under threshold + a rectifier low voltage alarm will occur. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigRectThresh 2 } + +dm3ConfigRectFailSafe OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Rectifier Fail Safe point. This OID represents the value sent to rectifier controllers + to use in the event of communications loss with the Master Controller or Master Controller + board failure. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigRectThresh 3 } + +dm3ConfigRectFailComm OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Rectifier Communication Fail timeout. This OID represents the time interval in which there is no + communication between the rectifier and the master controller at which the rectifier will reset + all its values to default. + + Values are represented in hundredths of Seconds. + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigRectThresh 4 } + +-- the dm3ConfigRectAlarms group + +dm3ConfigRectHighVoltAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Rectifier High Voltage Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigRectAlarms 1 } + +dm3ConfigRectLowVoltAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Rectifier Low Voltage Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigRectAlarms 2 } + +dm3ConfigRectConfigAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This alarm is activated when a new rectifier is detected; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigRectAlarms 3 } + +dm3ConfigRect1ofNAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This setting indicates the action if ONE rectifier of a N+1 system has failed; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigRectAlarms 4 } + +dm3ConfigRect2ofNAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This setting indicates the action if TWO OR MORE rectifiers of a N+1 system have failed; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigRectAlarms 5 } + +dm3ConfigRectDiagAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Rectifier Controller Diagnostics Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigRect1ofNAlarm OID + to be activated if ONE rectifier fails in an N+1 system. It causes the alarm specified in the + dm3ConfigRect2ofNAlarm OID to be activated if TWO OR MORE rectifiers fail in an N+1 system." + + ::= { dm3ConfigRectAlarms 6 } + +dm3ConfigRectImbalanceAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Rectifier Imbalance Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigRectAlarms 7 } + +dm3ConfigRectCurrLimitAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Rectifier Current Limit Alarm (indicating rectifier in the Current Limit state); + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigRect1ofNAlarm OID + to be activated if ONE rectifier fails in an N+1 system. It causes the alarm specified in the + dm3ConfigRect2ofNAlarm OID to be activated if TWO OR MORE rectifiers fail in an N+1 system." + + ::= { dm3ConfigRectAlarms 8 } + +dm3ConfigRectStandbyAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Rectifier Standby Alarm (indicating output DC has been turned off); + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigRect1ofNAlarm OID + to be activated if ONE rectifier fails in an N+1 system. It causes the alarm specified in the + dm3ConfigRect2ofNAlarm OID to be activated if TWO OR MORE rectifiers fail in an N+1 system." + + ::= { dm3ConfigRectAlarms 9 } + +dm3ConfigRectFanFailAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Rectifier Fan Fail Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigRect1ofNAlarm OID + to be activated if ONE rectifier fails in an N+1 system. It causes the alarm specified in the + dm3ConfigRect2ofNAlarm OID to be activated if TWO OR MORE rectifiers fail in an N+1 system." + + ::= { dm3ConfigRectAlarms 10 } + +dm3ConfigRectFailAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Rectifier Fail Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigRect1ofNAlarm OID + to be activated if ONE rectifier fails in an N+1 system. It causes the alarm specified in the + dm3ConfigRect2ofNAlarm OID to be activated if TWO OR MORE rectifiers fail in an N+1 system." + + ::= { dm3ConfigRectAlarms 11 } + +dm3ConfigRectHwVoltAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Rectifier Hardware Voltage Alarm (indicating voltage outside realistic limits, + or a possible measurement fault); + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigRectAlarms 12 } + + +-- the dm3ConfigConvThresh group + +dm3ConfigConvHighVoltThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Converter high voltage threshold. If converter voltage exceeds threshold + a converter high voltage alarm will occur. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + + ::= { dm3ConfigConvThresh 1 } + +dm3ConfigConvLowVoltThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Converter low voltage threshold. If converter voltage exceeds threshold + a converter low voltage alarm will occur. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigConvThresh 2 } + +dm3ConfigConvFailSafe OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Converter Fail Safe point. This OID represents the value sent to converter controllers + to use in the event of communications loss with the Master Controller or Master Controller + board failure. + + Values are represented in thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigConvThresh 3 } + +dm3ConfigConvSetPoint OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Converter Set point. This OID represents the initial set point used in the + voltage control loop. + + Units are thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigConvThresh 4 } + +dm3ConfigConvFailMax OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Converter Fail Maximum limit. This OID represents the value sent to the converter + controllers to define the maximum set point allowed. + + Units are thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigConvThresh 5 } + +dm3ConfigConvFailMin OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Converter Fail Minimum limit. This OID represents the value sent to the converter + controllers to define the minimum set point allowed. + + Units are thousandths of Volts (mV). + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigConvThresh 6 } + +dm3ConfigConvFailComm OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Converter Communication Fail timeout. This OID represents the time interval in which there is no + communication between the converter and the master controller at which the converter will reset + all its values to default. + + Values are represented in hundredths of Seconds. + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigConvThresh 7 } + +-- the dm3ConfigConvAlarms group +dm3ConfigConvHighVoltAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter High Voltage Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigConvAlarms 1 } + +dm3ConfigConvLowVoltAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter Low Voltage Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigConvAlarms 2 } + +dm3ConfigConvConfigAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter Configuration Alarm (indicating a new converter has been detected); + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigConvAlarms 3 } + +dm3ConfigConv1ofNAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter 1ofN Alarm (indicating action if ONE converter of a N+1 system has failed); + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigConvAlarms 4 } + +dm3ConfigConv2ofNAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter 2ofN Alarm (indicating action if TWO OR MORE converters of a N+1 system has failed); + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigConvAlarms 5 } + +dm3ConfigConvDiagAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter Diagnostics Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigConv1ofNAlarm OID + to be activated if ONE converter fails in an N+1 system. It causes the alarm specified in the + dm3ConfigConv2ofNAlarm OID to be activated if TWO OR MORE converters fail in an N+1 system." + + ::= { dm3ConfigConvAlarms 6 } + +dm3ConfigConvImbalanceAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter Imbalance Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigConv1ofNAlarm OID + to be activated if ONE converter fails in an N+1 system. It causes the alarm specified in the + dm3ConfigConv2ofNAlarm OID to be activated if TWO OR MORE converters fail in an N+1 system." + + ::= { dm3ConfigConvAlarms 7 } + +dm3ConfigConvCurrLimitAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter Current Limit Alarm (indicating the converter is in the Current Limit state); + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigConv1ofNAlarm OID + to be activated if ONE converter fails in an N+1 system. It causes the alarm specified in the + dm3ConfigConv2ofNAlarm OID to be activated if TWO OR MORE converters fail in an N+1 system." + + ::= { dm3ConfigConvAlarms 8 } + +dm3ConfigConvStandbyAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter Standby Alarm (indicating the converter is in the Standby state); + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigConv1ofNAlarm OID + to be activated if ONE converter fails in an N+1 system. It causes the alarm specified in the + dm3ConfigConv2ofNAlarm OID to be activated if TWO OR MORE converters fail in an N+1 system." + + ::= { dm3ConfigConvAlarms 9 } + +dm3ConfigConvFanFailAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter Fan Fail Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigConv1ofNAlarm OID + to be activated if ONE converter fails in an N+1 system. It causes the alarm specified in the + dm3ConfigConv2ofNAlarm OID to be activated if TWO OR MORE converters fail in an N+1 system." + + ::= { dm3ConfigConvAlarms 10 } + +dm3ConfigConvFailAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter Fail Alarm; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigConv1ofNAlarm OID + to be activated if ONE converter fails in an N+1 system. It causes the alarm specified in the + dm3ConfigConv2ofNAlarm OID to be activated if TWO OR MORE converters fail in an N+1 system." + + ::= { dm3ConfigConvAlarms 11 } + +dm3ConfigConvHwVoltAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9), + alarmNofN (10) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "For the Converter Voltage Alarm (indicating voltage outside realistic limits, or a + possible measurement fault); + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + Setting this OID to alarmNofN (10) causes the alarm specified in the dm3ConfigConv1ofNAlarm OID + to be activated if ONE converter fails in an N+1 system. It causes the alarm specified in the + dm3ConfigConv2ofNAlarm OID to be activated if TWO OR MORE converters fail in an N+1 system." + + ::= { dm3ConfigConvAlarms 12 } + + +-- the dm3ConfigOutputRelays group + +dm3ConfigOutRlyTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant Output Relays controllable + by this IP address." + ::= { dm3ConfigOutputRelays 1 } + +dm3ConfigOutRlyTable OBJECT-TYPE + SYNTAX SEQUENCE OF ConfigOutRlyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing settings of the Output Relays. The number of + entries is contained in the dm3ConfigOutRlyTableSize OID." + ::= { dm3ConfigOutputRelays 2 } + +dm3ConfigOutRlyEntry OBJECT-TYPE + SYNTAX ConfigOutRlyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The output relay to configure." + INDEX { dm3ConfigOutRlyIndex } + ::= { dm3ConfigOutRlyTable 1 } + +ConfigOutRlyEntry ::= + SEQUENCE { + dm3ConfigOutRlyIndex INTEGER, + dm3ConfigOutRlyName DisplayString, + dm3ConfigOutRlyDelay INTEGER, + dm3ConfigOutRlyAlarm INTEGER + } + +dm3ConfigOutRlyIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant output relay." + ::= { dm3ConfigOutRlyEntry 1 } + +dm3ConfigOutRlyName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the output relay. The maximum value is 16 characters." + ::= { dm3ConfigOutRlyEntry 2 } + +dm3ConfigOutRlyDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Output Relay Delay. This OID represents the time delay from the initiation of an + output relay action to when the output relay action does occur. If the alarm condition + disappears before the end of the delay, no action will occur. Delay for Major + and Minor alarms is not configurable and is always set to 0. + + Values are represented in hundredths of seconds. + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigOutRlyEntry 3 } + +dm3ConfigOutRlyAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Output Relay Alarm. This setting indicates what action to perform in the event of + an output relay alarm condition; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition. + + Relay Alarm for Major and Minor alarms is not configurable and is always set to + alarmMajor and alarmMinor respectively." + + ::= { dm3ConfigOutRlyEntry 4 } + + +-- the dm3ConfigInputRelays group + +dm3ConfigInRlyTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant Input Relays controllable + by this IP address." + ::= { dm3ConfigInputRelays 1 } + +dm3ConfigInRlyTable OBJECT-TYPE + SYNTAX SEQUENCE OF ConfigInRlyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing settings of the Input Relays. The number of + entries is contained in the dm3ConfigInRlyTableSize OID." + ::= { dm3ConfigInputRelays 2 } + +dm3ConfigInRlyEntry OBJECT-TYPE + SYNTAX ConfigInRlyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The input relay to configure." + INDEX { dm3ConfigInRlyIndex } + ::= { dm3ConfigInRlyTable 1 } + +ConfigInRlyEntry ::= + SEQUENCE { + dm3ConfigInRlyIndex INTEGER, + dm3ConfigInRlyName DisplayString, + dm3ConfigInRlyDelay INTEGER, + dm3ConfigInRlyAlarm INTEGER + } + +dm3ConfigInRlyIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant input relay." + ::= { dm3ConfigInRlyEntry 1 } + +dm3ConfigInRlyName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the input relay. The maximum value is 16 characters." + + ::= { dm3ConfigInRlyEntry 2 } + +dm3ConfigInRlyDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Input Relay Delay. This OID represents the time delay from the initiation of an + input relay action to when the input relay action does occur. If the alarm condition + disappears before the end of the delay, no action will occur. + + Values are represented in hundredths of seconds. + + Attempts to set the value above or below the acceptable range of the powerplant + will cause the value to be set at the high or low point of the range respectively." + ::= { dm3ConfigInRlyEntry 3 } + +dm3ConfigInRlyAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Input Relay Alarm. This setting indicates what action to perform in the event of + an input relay alarm condition; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigInRlyEntry 4 } + +-- the dm3ConfigBreakers group + +dm3ConfigBreakersTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant circuit breakers controllable + by this IP address." + ::= { dm3ConfigBreakers 1 } + +dm3ConfigBreakersTable OBJECT-TYPE + SYNTAX SEQUENCE OF ConfigBreakersEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing settings of the circuit breakers. The number of + entries is contained in the dm3ConfigBreakersTableSize OID." + ::= { dm3ConfigBreakers 2 } + +dm3ConfigBreakersEntry OBJECT-TYPE + SYNTAX ConfigBreakersEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The circuit breaker to configure." + INDEX { dm3ConfigBreakersIndex } + ::= { dm3ConfigBreakersTable 1 } + +ConfigBreakersEntry ::= + SEQUENCE { + dm3ConfigBreakersIndex INTEGER, + dm3ConfigBreakersName DisplayString, + dm3ConfigBreakersAlarm INTEGER + } + +dm3ConfigBreakersIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant circuit breaker." + ::= { dm3ConfigBreakersEntry 1 } + +dm3ConfigBreakersName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the circuit breaker. The maximum value is 16 characters." + ::= { dm3ConfigBreakersEntry 2 } + +dm3ConfigBreakersAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Circuit Breaker Alarm. This setting indicates what action to perform in the event of + a circuit breaker alarm condition; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigBreakersEntry 3 } + +-- the dm3ConfigFuses group + +dm3ConfigFusesTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant Fuses controllable + by this IP address." + ::= { dm3ConfigFuses 1 } + +dm3ConfigFusesTable OBJECT-TYPE + SYNTAX SEQUENCE OF ConfigFusesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing settings of the Fuses. The number of + entries is contained in the dm3ConfigFusesTableSize OID." + ::= { dm3ConfigFuses 2 } + +dm3ConfigFusesEntry OBJECT-TYPE + SYNTAX ConfigFusesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The fuse to configure." + INDEX { dm3ConfigFusesIndex } + ::= { dm3ConfigFusesTable 1 } + +ConfigFusesEntry ::= + SEQUENCE { + dm3ConfigFusesIndex INTEGER, + dm3ConfigFusesName DisplayString, + dm3ConfigFusesAlarm INTEGER + } + +dm3ConfigFusesIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant fuse." + ::= { dm3ConfigFusesEntry 1 } + +dm3ConfigFusesName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the fuse. The maximum value is 16 characters." + ::= { dm3ConfigFusesEntry 2 } + +dm3ConfigFusesAlarm OBJECT-TYPE + SYNTAX INTEGER { + alarmIgnore (1), + alarmRelay1 (2), + alarmRelay2 (3), + alarmRelay3 (4), + alarmRelay4 (5), + alarmRelay5 (6), + alarmRelay6 (7), + alarmMinor (8), + alarmMajor (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Fuses Alarm. This setting indicates what action to perform in the event of + a Fuse alarm condition; + Setting this OID to alarmIgnore (1) results in the alarm condition being ignored. + Setting this OID to alarmRelay1 (2) causes relay 1 to be activated for an + alarm condition. + Setting this OID to alarmRelay2 (3) causes relay 2 to be activated for an + alarm condition. + Setting this OID to alarmRelay3 (4) causes relay 3 to be activated for an + alarm condition. + Setting this OID to alarmRelay4 (5) causes relay 4 to be activated for an + alarm condition. + Setting this OID to alarmRelay5 (6) causes relay 5 to be activated for an + alarm condition. + Setting this OID to alarmRelay6 (7) causes relay 6 to be activated for an + alarm condition. + Setting this OID to alarmMinor (8) causes the Minor relay to be activated for an + alarm condition. + Setting this OID to alarmMajor (9) causes the Major relay to be activated for an + alarm condition." + + ::= { dm3ConfigFusesEntry 3 } + +-- the dm3StatusSystem group + +dm3StatusSystemTemp OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System temperature based on sensor on Master Controller PCB. + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dm3StatusSysTempUnits' OID (Celsius or Fahrenheit)." + + ::= { dm3StatusSystem 1 } + +dm3StatusSystemStart OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Time stamp at DC powerplant initialization. + The time is represented as MMM,DD,YYYY,HH:MM:SS." + ::= { dm3StatusSystem 2 } + +dm3StatusSysRemoteAccess OBJECT-TYPE + SYNTAX INTEGER { + accessEnabled (1), + accessDisabled (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Remote Access indicator + This setting indicates if configuration (write) access to the powerplant is enabled or + disabled at the powerplant level. + This value will be accessEnabled (1) if remote configuration is enabled, and + accessDisabled (2) if remote configuration is disabled." + ::= { dm3StatusSystem 3 } + +dm3StatusSysSecurityLevel OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This variable shows the current active security access level of controller. This + can only be changed directly from the front panel." + ::= { dm3StatusSystem 4 } + +dm3StatusSysTempSanity OBJECT-TYPE + SYNTAX INTEGER{ + saneYES (1), + saneNO (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System temperature sanity indicator. Indicates if the system temperature is + reasonable. Reasonable is defined based on powerplant type. A value of saneYes (1) + indicates temperature is reasonable, a value of saneNo (2) indicates it is not." + ::= { dm3StatusSystem 5 } + +dm3StatusSysAlarmState OBJECT-TYPE + SYNTAX INTEGER{ + alarmMinor (1), + alarmMajor (2), + alarmBoth (3), + alarmNone (4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System Alarm State. Reflects the alarm status of the overall DC system. + If a minor alarm is present, the value will be alarmMinor(1). + If a major alarm is present, the value will be alarmMajor(2). + If both minor and a major alarm is present, the value will be alarmBoth(3). + If no alarm is present, the value will be alarmNone(4)." + ::= { dm3StatusSystem 6 } + +dm3StatusSysTempUnits OBJECT-TYPE + SYNTAX INTEGER { + celsius(1), + fahrenheit(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature scale used to display the temperature + in the DC system, Celsius(1) or Fahrenheit(2). + This setting is based on the system preferences + configuration in the agent." + ::= { dm3StatusSystem 7 } + + +-- the dm3StatusAlarms group + +dm3StatusAlarmsTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant alarms viewable + by this IP address." + ::= { dm3StatusAlarms 1 } + +dm3StatusAlarmsTable OBJECT-TYPE + SYNTAX SEQUENCE OF StatusAlarmsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing system alarms. The number of + entries is contained in the dm3StatusAlarmsTableSize OID." + ::= { dm3StatusAlarms 2 } + +dm3StatusAlarmsEntry OBJECT-TYPE + SYNTAX StatusAlarmsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The alarm to display." + INDEX { dm3StatusAlarmsIndex } + ::= { dm3StatusAlarmsTable 1 } + +StatusAlarmsEntry ::= + SEQUENCE { + dm3StatusAlarmsIndex INTEGER, + dm3StatusAlarmsText DisplayString + } + +dm3StatusAlarmsIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the system alarm." + ::= { dm3StatusAlarmsEntry 1 } + +dm3StatusAlarmsText OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The 16 character text describing the active alarm condition." + ::= { dm3StatusAlarmsEntry 2 } + +-- the dm3StatusBattery group + +dm3StatusBattCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Battery Current: This OID shows the battery current in thousandths of Amps (mA)." + ::= { dm3StatusBattery 1 } + +dm3StatusBattTemp OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Battery Temperature: + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dm3StatusSysTempUnits' OID (Celsius or Fahrenheit)." + + ::= { dm3StatusBattery 2 } + +dm3StatusBattCurrentSanity OBJECT-TYPE + SYNTAX INTEGER{ + saneYES (1), + saneNO (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Battery current sanity indicator. Indicates if the battery current is + reasonable. Reasonable is defined based on powerplant type. A value of saneYes (1) + indicates current is reasonable, a value of saneNo (2) indicates it is not." + ::= { dm3StatusBattery 3 } + +dm3StatusBattTempSanity OBJECT-TYPE + SYNTAX INTEGER{ + saneYES (1), + saneNO (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Battery temperature sanity indicator. Indicates if the battery temperature is + reasonable. Reasonable is defined based on powerplant type. A value of saneYes (1) + indicates temperature is reasonable, a value of saneNo (2) indicates it is not." + ::= { dm3StatusBattery 4 } + +-- the dm3StatusOEM group + +dm3StatusOEMrectOffset OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier offset value in thousandths of Volts (mV)." + ::= { dm3StatusOEM 1 } + +dm3StatusOEMrectGain OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier gain value in thousandths of Volts (mV/V)." + ::= { dm3StatusOEM 2 } + +dm3StatusOEMconvOffset OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter offset value in thousandths of Volts (mV)." + ::= { dm3StatusOEM 3 } + +dm3StatusOEMconvGain OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter gain value in thousandths of Volts (mV/V)." + ::= { dm3StatusOEM 4 } + +dm3StatusOEMshuntOffset OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the shunt offset value in thousandths of Amps (mA)." + ::= { dm3StatusOEM 5 } + +dm3StatusOEMshuntGain OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the shunt gain value in thousandths of Amps (mA/A)." + ::= { dm3StatusOEM 6 } + +-- the dm3StatusLVD group + +dm3StatusLVDTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant LVDs viewable + by this IP address." + ::= { dm3StatusLVD 1 } + +dm3StatusLVDTable OBJECT-TYPE + SYNTAX SEQUENCE OF StatusLVDEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing settings of the LVDs. The number of + entries is contained in the dm3StatusLVDTableSize OID." + ::= { dm3StatusLVD 2 } + +dm3StatusLVDEntry OBJECT-TYPE + SYNTAX StatusLVDEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The LVD to gather status from." + INDEX { dm3StatusLVDIndex } + ::= { dm3StatusLVDTable 1 } + +StatusLVDEntry ::= + SEQUENCE { + dm3StatusLVDIndex INTEGER, + dm3StatusLVDName DisplayString, + dm3StatusLVDState INTEGER, + dm3StatusLVDHwFault INTEGER + } + +dm3StatusLVDIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant LVD." + ::= { dm3StatusLVDEntry 1 } + +dm3StatusLVDName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the LVD. The maximum size is + 16 characters. The name is set by using the + dm3ConfigLVDName OID. + This OID is provided for informational purposes only." + ::= { dm3StatusLVDEntry 2 } + +dm3StatusLVDState OBJECT-TYPE + SYNTAX INTEGER { + statusClosed (1), + statusOpened (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusClosed (1) if the LVD is closed. + statusOpened (2) will be returned if the LVD is opened." + ::= { dm3StatusLVDEntry 3 } + +dm3StatusLVDHwFault OBJECT-TYPE + SYNTAX INTEGER { + statusFault (1), + statusNofault (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusFault (1) if the LVD is faulted. + statusNofault (2) will be returned if the LVD is not faulted." + ::= { dm3StatusLVDEntry 4 } + +-- the dm3StatusRectifier group + +dm3StatusRectTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant rectifiers viewable + by this IP address." + ::= { dm3StatusRectifier 1 } + +dm3StatusRectTable OBJECT-TYPE + SYNTAX SEQUENCE OF StatusRectEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing settings of the rectifiers. The number of + entries is contained in the dm3StatusRectTableSize OID." + ::= { dm3StatusRectifier 2 } + +dm3StatusRectEntry OBJECT-TYPE + SYNTAX StatusRectEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The rectifier to gather status from." + INDEX { dm3StatusRectIndex } + ::= { dm3StatusRectTable 1 } + +StatusRectEntry ::= + SEQUENCE { + dm3StatusRectIndex INTEGER, + dm3StatusRectID INTEGER, + dm3StatusRectDesc DisplayString, + dm3StatusRectCurrent INTEGER, + dm3StatusRectCurrentLimit INTEGER, + dm3StatusRectStandby INTEGER, + dm3StatusRectFanFail INTEGER, + dm3StatusRectFail INTEGER, + dm3StatusRectDevType INTEGER, + dm3StatusRectPhyAddr INTEGER, + dm3StatusRectCfg INTEGER, + dm3StatusRectPcbRev INTEGER, + dm3StatusRectFwVer INTEGER, + dm3StatusRectPresent INTEGER, + dm3StatusRectDiagPass INTEGER, + dm3StatusRectState INTEGER + } + +dm3StatusRectIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant rectifier." + ::= { dm3StatusRectEntry 1 } + +dm3StatusRectID OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier ID. This enumerates the number of the rectifier within + a group of rectifiers." + ::= { dm3StatusRectEntry 2 } + +dm3StatusRectDesc OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the 16-character rectifier description." + ::= { dm3StatusRectEntry 3 } + +dm3StatusRectCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier current in thousandths of Amps (mA)." + ::= { dm3StatusRectEntry 4 } + +dm3StatusRectCurrentLimit OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the rectifier is in the Current Limit state. + statusFalse (2) will be returned if the rectifier is not in the Current Limit state." + ::= { dm3StatusRectEntry 5 } + +dm3StatusRectStandby OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the rectifier is in the Standby state. + statusFalse (2) will be returned if the rectifier is not in the Standby state." + ::= { dm3StatusRectEntry 6 } + +dm3StatusRectFanFail OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the rectifier Fan has failed. + statusFalse (2) will be returned if the rectifier Fan has not failed." + ::= { dm3StatusRectEntry 7 } + +dm3StatusRectFail OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the rectifier has failed. + statusFalse (2) will be returned if the rectifier has not failed." + ::= { dm3StatusRectEntry 8 } + +dm3StatusRectDevType OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier device type." + ::= { dm3StatusRectEntry 9 } + +dm3StatusRectPhyAddr OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier physical address (the address on the bus)." + ::= { dm3StatusRectEntry 10 } + +dm3StatusRectCfg OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the rectifier is present after + power-up or set-configuration. + statusFalse (2) will be returned if the rectifier is not configured." + ::= { dm3StatusRectEntry 11 } + +dm3StatusRectPcbRev OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier device PCB serial number." + ::= { dm3StatusRectEntry 12 } + +dm3StatusRectFwVer OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier device firmware revision." + ::= { dm3StatusRectEntry 13 } + +dm3StatusRectPresent OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the rectifier is present. + statusFalse (2) will be returned if the rectifier is not present." + ::= { dm3StatusRectEntry 14 } + +dm3StatusRectDiagPass OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the rectifier diagnostics have passed. + statusFalse (2) will be returned if the rectifier diagnostics have not passed." + ::= { dm3StatusRectEntry 15 } + +dm3StatusRectState OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier device state as defined by the device status register." + ::= { dm3StatusRectEntry 16 } + +dm3StatusSysRectVoltSanity OBJECT-TYPE + SYNTAX INTEGER { + saneYES (1), + saneNO (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Rectifier voltage sanity indicator. Indicates if the rectifier voltage is + reasonable. Reasonable is defined based on powerplant type. A value of saneYes (1) + indicates voltage is reasonable, a value of saneNo (2) indicates it is not." + ::= { dm3StatusRectifier 3 } + +dm3StatusSysRectAvailable OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the rectifier is available. + statusFalse (2) will be returned if the rectifier is not available." + ::= { dm3StatusRectifier 4 } + +dm3StatusSysRectType OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the type of rectifier the system has. There can only be a single type of + rectifier in the power plant" + ::= { dm3StatusRectifier 5 } + +dm3StatusSysRectVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the system level rectifier voltage in thousandths of Volts (mV)." + ::= { dm3StatusRectifier 6 } + +dm3StatusSysRectCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the system level rectifier current in thousandths of Amps (mA)." + ::= { dm3StatusRectifier 7 } + + +-- the dm3StatusConverter group + +dm3StatusConvTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant converters viewable + by this IP address." + ::= { dm3StatusConverter 1 } + +dm3StatusConvTable OBJECT-TYPE + SYNTAX SEQUENCE OF StatusConvEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for viewing status of the converters. The number of + entries is contained in the dm3StatusConvTableSize OID." + ::= { dm3StatusConverter 2 } + +dm3StatusConvEntry OBJECT-TYPE + SYNTAX StatusConvEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The converter to gather status from." + INDEX { dm3StatusConvIndex } + ::= { dm3StatusConvTable 1 } + +StatusConvEntry ::= + SEQUENCE { + dm3StatusConvIndex INTEGER, + dm3StatusConvID INTEGER, + dm3StatusConvDesc DisplayString, + dm3StatusConvCurrent INTEGER, + dm3StatusConvCurrentLimit INTEGER, + dm3StatusConvStandby INTEGER, + dm3StatusConvFanFail INTEGER, + dm3StatusConvFail INTEGER, + dm3StatusConvDevType INTEGER, + dm3StatusConvPhyAddr INTEGER, + dm3StatusConvCfg INTEGER, + dm3StatusConvPcbRev INTEGER, + dm3StatusConvFwVer INTEGER, + dm3StatusConvPresent INTEGER, + dm3StatusConvDiagPass INTEGER, + dm3StatusConvState INTEGER + } + +dm3StatusConvIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant converter." + ::= { dm3StatusConvEntry 1 } + +dm3StatusConvID OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter ID. This enumerates the number of the converter within + a group of converters." + ::= { dm3StatusConvEntry 2 } + +dm3StatusConvDesc OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the 16 character converter description." + ::= { dm3StatusConvEntry 3 } + +dm3StatusConvCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter current in thousandths of Amps (mA)." + ::= { dm3StatusConvEntry 4 } + +dm3StatusConvCurrentLimit OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the converter is in the Current Limit state. + statusFalse (2) will be returned if the converter is not in the Current Limit state." + ::= { dm3StatusConvEntry 5 } + +dm3StatusConvStandby OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the converter is in the Standby state. + statusFalse (2) will be returned if the converter is not in the Standby state." + ::= { dm3StatusConvEntry 6 } + +dm3StatusConvFanFail OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the converter Fan has failed. + statusFalse (2) will be returned if the converter Fan has not failed." + ::= { dm3StatusConvEntry 7 } + +dm3StatusConvFail OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the converter has failed. + statusFalse (2) will be returned if the converter has not failed." + ::= { dm3StatusConvEntry 8 } + +dm3StatusConvDevType OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter device type." + ::= { dm3StatusConvEntry 9 } + +dm3StatusConvPhyAddr OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter physical address (the address on the bus)." + ::= { dm3StatusConvEntry 10 } + +dm3StatusConvCfg OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the converter is present after + power-up or set-configuration. + statusFalse (2) will be returned if the converter is not configured." + ::= { dm3StatusConvEntry 11 } + +dm3StatusConvPcbRev OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter device PCB serial number." + ::= { dm3StatusConvEntry 12 } + +dm3StatusConvFwVer OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter device firmware version." + ::= { dm3StatusConvEntry 13 } + +dm3StatusConvPresent OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the converter is present. + statusFalse (2) will be returned if the converter is not present." + ::= { dm3StatusConvEntry 14 } + +dm3StatusConvDiagPass OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the converter diagnostics have passed. + statusFalse (2) will be returned if the converter diagnostics have not passed." + ::= { dm3StatusConvEntry 15 } + +dm3StatusConvState OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter state as defined by the device status register." + ::= { dm3StatusConvEntry 16 } + +dm3StatusSysConvVoltSanity OBJECT-TYPE + SYNTAX INTEGER{ + saneYES (1), + saneNO (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Converter voltage sanity indicator. Indicates if the converter voltage is + reasonable. Reasonable is defined based on powerplant type. A value of saneYes (1) + indicates voltage is reasonable, a value of saneNo (2) indicates it is not." + ::= { dm3StatusConverter 3 } + +dm3StatusSysConvAvailable OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the converter is available. + statusFalse (2) will be returned if the converter is not available." + ::= { dm3StatusConverter 4 } + +dm3StatusSysConvType OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the converter type." + ::= { dm3StatusConverter 5 } + +dm3StatusSysConvVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the system level converter voltage in thousandths of volts (mV)." + ::= { dm3StatusConverter 6 } + +dm3StatusSysConvCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the system level converter current in thousandths of Amps (mA)." + ::= { dm3StatusConverter 7 } + +-- the dm3StatusOutputRelays group + +dm3StatusOutRlyTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant output relays viewable + by this IP address." + ::= { dm3StatusOutputRelays 1 } + +dm3StatusOutRlyTable OBJECT-TYPE + SYNTAX SEQUENCE OF StatusOutRlyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for viewing status of the output relays. The number of + entries is contained in the dm3StatusOutRlyTableSize OID." + ::= { dm3StatusOutputRelays 2 } + +dm3StatusOutRlyEntry OBJECT-TYPE + SYNTAX StatusOutRlyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The output relay to gather status from." + INDEX { dm3StatusOutRlyIndex } + ::= { dm3StatusOutRlyTable 1 } + +StatusOutRlyEntry ::= + SEQUENCE { + dm3StatusOutRlyIndex INTEGER, + dm3StatusOutRlyName DisplayString, + dm3StatusOutRlyStatus INTEGER + } + +dm3StatusOutRlyIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant output relay." + ::= { dm3StatusOutRlyEntry 1 } + +dm3StatusOutRlyName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the output relay. The maximum size is + 16 characters. The name is set by using the + dm3ConfigOutRlyName OID. + This OID is provided for informational purposes only." + ::= { dm3StatusOutRlyEntry 2 } + +dm3StatusOutRlyStatus OBJECT-TYPE + SYNTAX INTEGER { + statusOn (1), + statusOff (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusOn (1) if the output relay is enabled/on. + statusOff (2) will be returned if the output relay is disabled/off." + ::= { dm3StatusOutRlyEntry 3 } + + +-- the dm3StatusInputRelays group + +dm3StatusInRlyTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant input relays viewable + by this IP address." + ::= { dm3StatusInputRelays 1 } + +dm3StatusInRlyTable OBJECT-TYPE + SYNTAX SEQUENCE OF StatusInRlyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for viewing status of the input relays. The number of + entries is contained in the dm3StatusInRlyTableSize OID." + ::= { dm3StatusInputRelays 2 } + + +dm3StatusInRlyEntry OBJECT-TYPE + SYNTAX StatusInRlyEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The input relays to gather status from." + INDEX { dm3StatusInRlyIndex } + ::= { dm3StatusInRlyTable 1 } + +StatusInRlyEntry ::= + SEQUENCE { + dm3StatusInRlyIndex INTEGER, + dm3StatusInRlyName DisplayString, + dm3StatusInRlyStatus INTEGER + } + +dm3StatusInRlyIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant input relay." + ::= { dm3StatusInRlyEntry 1 } + +dm3StatusInRlyName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the input relay. The maximum size is + 16 characters. The name is set by using the + dm3ConfigInRlyName OID. + This OID is provided for informational purposes only." + ::= { dm3StatusInRlyEntry 2 } + +dm3StatusInRlyStatus OBJECT-TYPE + SYNTAX INTEGER { + statusOn (1), + statusOff (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusOn (1) if the input relay is enabled/on. + statusOff (2) will be returned if the input relay is disabled/off." + ::= { dm3StatusInRlyEntry 3 } + +-- the dm3StatusBreakers group + +dm3StatusBreakersTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant circuit breakers viewable + by this IP address." + ::= { dm3StatusBreakers 1 } + +dm3StatusBreakersTable OBJECT-TYPE + SYNTAX SEQUENCE OF StatusBreakersEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for viewing status of the circuit breakers. The number of + entries is contained in the dm3StatusBreakersTableSize OID." + ::= { dm3StatusBreakers 2 } + +dm3StatusBreakersEntry OBJECT-TYPE + SYNTAX StatusBreakersEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The circuit breaker to gather status from." + INDEX { dm3StatusBreakersIndex } + ::= { dm3StatusBreakersTable 1 } + +StatusBreakersEntry ::= + SEQUENCE { + dm3StatusBreakersIndex INTEGER, + dm3StatusBreakersName DisplayString, + dm3StatusBreakersStatus INTEGER + } + +dm3StatusBreakersIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant circuit breaker." + ::= { dm3StatusBreakersEntry 1 } + +dm3StatusBreakersName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the circuit breaker. The maximum size is + 16 characters. The name is set by using the + dm3ConfigBreakersName OID. + This OID is provided for informational purposes only." + ::= { dm3StatusBreakersEntry 2 } + +dm3StatusBreakersStatus OBJECT-TYPE + SYNTAX INTEGER { + statusClosed (1), + statusOpen (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusClosed (1) if the circuit breaker is closed. + statusOpen (2) will be returned if the circuit breaker is open." + ::= { dm3StatusBreakersEntry 3 } + +-- the dm3StatusFuses group + +dm3StatusFusesTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant fuses controllable + by this IP address." + ::= { dm3StatusFuses 1 } + +dm3StatusFusesTable OBJECT-TYPE + SYNTAX SEQUENCE OF StatusFusesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for viewing status of the fuses. The number of + entries is contained in the dm3StatusFusesTableSize OID." + ::= { dm3StatusFuses 2 } + +dm3StatusFusesEntry OBJECT-TYPE + SYNTAX StatusFusesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The fuse to gather status from." + INDEX { dm3StatusFusesIndex } + ::= { dm3StatusFusesTable 1 } + +StatusFusesEntry ::= + SEQUENCE { + dm3StatusFusesIndex INTEGER, + dm3StatusFusesName DisplayString, + dm3StatusFusesStatus INTEGER + } + +dm3StatusFusesIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant fuse." + ::= { dm3StatusFusesEntry 1 } + +dm3StatusFusesName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the fuse. The maximum size is + 16 characters. The name is set by using the + dm3ConfigFuseName OID. + This OID is provided for informational purposes only." + ::= { dm3StatusFusesEntry 2 } + +dm3StatusFusesStatus OBJECT-TYPE + SYNTAX INTEGER { + statusClosed (1), + statusOpen (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusClosed (1) if the fuse is closed. + statusOpen (2) will be returned if the fuse is open." + ::= { dm3StatusFusesEntry 3 } + +-- the atsIdent group + +atsIdentHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware version of the Automatic Transfer Switch. + This value is set at the factory." + ::= { atsIdent 1 } + +atsIdentFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A string identifying the Automatic Transfer Switch + firmware version." + ::= { atsIdent 2 } + +atsIdentFirmwareDate OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date of release for this Automatic Transfer Switch + firmware version. " + ::= { atsIdent 3 } + +atsIdentDateOfManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date when the Automatic Transfer Switch was manufactured in mm/dd/yyyy format. + This value is set at the factory. " + ::= { atsIdent 4 } + +atsIdentModelNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A string identifying the model number of the Automatic Transfer Switch. + This value is set at the factory." + ::= { atsIdent 5 } + +atsIdentSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A string identifying the serial number of + the Automatic Transfer Switch. This value is set at the factory." + ::= { atsIdent 6 } + +atsIdentNominalLineVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "RMS Utility Voltage measured in V." + ::= { atsIdent 7 } + +atsIdentNominalLineFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Utility Power Frequency measured in Hz." + ::= { atsIdent 8 } + +-- the atsCalibration group + +-- Input Voltage Calibration Factor table + + atsCalibrationNumInputs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of inputs to this device." + ::= { atsCalibrationInput 1 } + + atsCalibrationNumInputPhases OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of phases per input for this device." + ::= { atsCalibrationInput 2 } + + atsCalibrationInputTable OBJECT-TYPE + SYNTAX SEQUENCE OF ATSCalibrationInputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The number of phases per input line to this device." + ::= { atsCalibrationInput 3 } + + atsCalibrationInputPhaseEntry OBJECT-TYPE + SYNTAX ATSCalibrationInputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing calibration information applicable to a + particular input phase." + INDEX { atsCalibrationInputTableIndex, atsCalibrationInputPhaseTableIndex } + ::= { atsCalibrationInputTable 1 } + + ATSCalibrationInputPhaseEntry ::= SEQUENCE { + atsCalibrationInputTableIndex INTEGER, + atsCalibrationInputPhaseTableIndex INTEGER, + atsLineVoltageCalibrationFactor INTEGER + } + + atsCalibrationInputTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input identifier." + ::= { atsCalibrationInputPhaseEntry 1 } + + atsCalibrationInputPhaseTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input phase identifier." + ::= { atsCalibrationInputPhaseEntry 2 } + + atsLineVoltageCalibrationFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Line Voltage Calibration factor. + This value is set at the factory." + ::= { atsCalibrationInputPhaseEntry 3 } + +-- Power Supply Voltage Calibration table + + atsCalibrationPowerSupplyVoltages OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of power supply voltages supported by this device. + This variable indicates the number of rows in the + atsCalibrationPowerSupplyTable. There is one entry per + supported voltage: 24V, 12V and 5V" + ::= { atsCalibrationPowerSupply 1 } + + atsCalibrationPowerSupplyVoltageTable OBJECT-TYPE + SYNTAX SEQUENCE OF ATSCalibrationPowerSupplyVoltageEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of Power Supply table entries." + ::= { atsCalibrationPowerSupply 2 } + + atsCalibrationPowerSupplyVoltageEntry OBJECT-TYPE + SYNTAX ATSCalibrationPowerSupplyVoltageEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular Power Supply Voltage." + INDEX { atsCalibrationPowerSupplyVoltageTableIndex } + ::= { atsCalibrationPowerSupplyVoltageTable 1 } + + ATSCalibrationPowerSupplyVoltageEntry ::= SEQUENCE { + atsCalibrationPowerSupplyVoltageTableIndex INTEGER, + atsCalibrationPowerSupplyVoltage INTEGER, + atsPowerSupplyVoltageCalibrationFactor INTEGER + } + + atsCalibrationPowerSupplyVoltageTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The power supply voltage identifier. + Three power supply voltages are supported by the ATS: + 24V , 12V and 5V . + The value of this index indicates the power supply voltage: + 1 = 24V + 2 = 12V + 3 = 5V" + ::= { atsCalibrationPowerSupplyVoltageEntry 1 } + + atsCalibrationPowerSupplyVoltage OBJECT-TYPE + SYNTAX INTEGER { + powerSupply24V(1), + powerSupply12V(2), + powerSupply(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This value describes the power supply voltage." + ::= { atsCalibrationPowerSupplyVoltageEntry 2 } + + atsPowerSupplyVoltageCalibrationFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The Line Voltage Calibration factor. + This value is set at the factory." + ::= { atsCalibrationPowerSupplyVoltageEntry 3 } + +-- Output Current Calibration table + + atsCalibrationNumOutputs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output lines from this device. + This variable indicates the number of rows in the + atsCalibrationOutputTable." + ::= { atsCalibrationOutput 1 } + + atsCalibrationNumOutputPhases OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output phases utilized in this + device." + ::= { atsCalibrationOutput 2 } + + atsCalibrationOutputTable OBJECT-TYPE + SYNTAX SEQUENCE OF ATSCalibrationOutputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of output table entries." + ::= { atsCalibrationOutput 3 } + + atsCalibrationOutputEntry OBJECT-TYPE + SYNTAX ATSCalibrationOutputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular output." + INDEX { atsCalibrationOutputTableIndex, atsCalibrationOutputPhasesTableIndex } + ::= { atsCalibrationOutputTable 1 } + + ATSCalibrationOutputEntry ::= SEQUENCE { + atsCalibrationOutputTableIndex INTEGER, + atsCalibrationOutputPhasesTableIndex INTEGER, + atsOutputCurrentCalibrationFactor INTEGER + } + + atsCalibrationOutputTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output identifier." + ::= { atsCalibrationOutputEntry 1 } + + atsCalibrationOutputPhasesTableIndex OBJECT-TYPE + SYNTAX INTEGER{ + phase1(1), + phase2(2), + phase3(3), + neutral(4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Description of each calibration factor for each + output phase utilized in this device and one for neutral. " + ::= { atsCalibrationOutputEntry 2 } + + atsOutputCurrentCalibrationFactor OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output current calibration factor measured in Amps." + ::= { atsCalibrationOutputEntry 3 } + + +-- the atsControl group + +atsControlResetATS OBJECT-TYPE + SYNTAX INTEGER { + none(1), + reset(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable will cause the Automatic Transfer Switch to + perform a power-on reset." + ::= { atsControl 1 } + +atsControlClearAllAlarms OBJECT-TYPE + SYNTAX INTEGER { + none(1), + clear(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable will clear all alarms in the Automatic Transfer Switch." + ::= { atsControl 2 } + +-- the atsConfig group + +atsConfigProductName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A configurable character string." + ::= { atsConfig 1 } + +atsConfigPreferredSource OBJECT-TYPE + SYNTAX INTEGER { + sourceA(1), + sourceB(2), + none(3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This variable returns the preferred source of power when both sources are OK." + ::= { atsConfig 2 } + +atsConfigFrontPanelLockout OBJECT-TYPE + SYNTAX INTEGER { + disableFrontPanel(1), + enableFrontPanel(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Setting this variable to disableFrontPanel(1) will disallow source + preference configuration of the Automatic Transfer Switch via the + Front Panel. Once this value is set, it can only be re-enabled through + the serial interface of the ATS. + When this variable is set to enableFrontPanel(2), source preference + configuration of the Automatic Transfer Switch via the Front Panel + is allowed." + ::= { atsConfig 3 } + +atsConfigVoltageSensitivity OBJECT-TYPE + SYNTAX INTEGER { + high(1), + low(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This variable defines the sensitivity to changes in voltage: + high(1) for best protection, low(2) for frequent small line + voltage changes." + ::= { atsConfig 4 } + +atsConfigTransferVoltageRange OBJECT-TYPE + SYNTAX INTEGER { + wide(1), + medium(2), + narrow(3) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This variable defines the range of acceptable voltage from a power source. + If the voltage measured from the selected input source is not within this + range, the Automatic Transfer Switch will switch over (transfer) to the + alternate power source." + + ::= { atsConfig 5 } + +atsConfigCurrentLimit OBJECT-TYPE + SYNTAX INTEGER (0..20) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The threshold (in Amps) at which an Over Current Alarm will be generated." + + ::= { atsConfig 6 } + + +atsConfigResetValues OBJECT-TYPE + SYNTAX INTEGER { + none(1), + reset(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Resets the ATS configuration to its default values." + + ::= { atsConfig 7 } + +-- the atsStatus group + + atsStatusCommStatus OBJECT-TYPE + SYNTAX INTEGER { + atsNeverDiscovered(1), + atsCommEstablished(2), + atsCommLost(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This variable returns the current communication status + of the Automatic Transfer Switch. " + ::= { atsStatusDeviceStatus 1 } + + atsStatusSelectedSource OBJECT-TYPE + SYNTAX INTEGER { + sourceA(1), + sourceB(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This variable returns the current source of power. " + ::= { atsStatusDeviceStatus 2 } + + atsStatusRedundancyState OBJECT-TYPE + SYNTAX INTEGER { + atsRedundancyLost(1), + atsFullyRedundant(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This variable returns the current redundancy state of the ATS. + atsRedundancyLost(1) indicates that the ATS is unable to + switch over to the alternate power source if the current source fails. + atsFullyRedundant(2) indicates that the ATS will switch over to + the alternate power source if the current source fails." + ::= { atsStatusDeviceStatus 3 } + + atsStatusOverCurrentState OBJECT-TYPE + SYNTAX INTEGER { + atsOverCurrent(1), + atsCurrentOK(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This variable returns the output current state of the ATS. + atsOverCurrent(1) indicates that the ATS has exceeded the output + current threshold and will not allow a switch over to the alternate power + source if the current source fails. + atsCurrentOK(2) indicates that the output current is below the + output current threshold." + ::= { atsStatusDeviceStatus 4 } + + atsStatus5VPowerSupply OBJECT-TYPE + SYNTAX INTEGER { + atsPowerSupplyFailure(1), + atsPowerSupplyOK(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This variable returns the current state of the ATS 5-volt power supply. + atsPowerSupplyFailure(1) indicates the 5-volt power supply has failed + and that the ATS serial port Configuration Menu is not accessible . + atsPowerSupplyOK(2) indicates that the ATS 5-volt power supply + is operating within tolerance." + ::= { atsStatusDeviceStatus 5 } + + atsStatus24VPowerSupply OBJECT-TYPE + SYNTAX INTEGER { + atsPowerSupplyFailure(1), + atsPowerSupplyOK(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This variable returns the current state of the ATS 24-volt power supply. + atsPowerSupplyFailure(1) indicates the 24-volt power supply has failed + and the ATS is unable to switch over to the alternate power source if + the current source fails. + atsPowerSupplyOK(2) indicates that the ATS 24-volt power supply + is operating within tolerance." + ::= { atsStatusDeviceStatus 6 } + + atsStatusResetMaxMinValues OBJECT-TYPE + SYNTAX INTEGER { + none(1), + reset(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Resets the maximum and minimum ATS values: + atsInputMaxVoltage, atsInputMinVoltage, + atsInputMaxCurrent, atsInputMinCurrent, + atsInputMaxPower, atsInputMinPower, + atsOutputMaxCurrent, atsOutputMinCurrent, + atsOutputMaxLoad, atsOutputMinLoad, + atsOutputMaxPercentLoad, atsOutputMinPercentLoad, + atsOutputMaxPower, atsOutputMinPower, + atsOutputMaxPercentPower, atsOutputMinPercentPower. + These variables represent the maximum and minimum ATS values + since the last time they were read or reset by this OID. + Values unsupported by this ATS will return (-1)." + ::= { atsStatusResetValues 1 } + +-- +-- Input Group +-- + +-- Number of Inputs + + atsNumInputs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input feeds to this device. + This variable indicates the number of rows in the + input table." + ::= { atsStatusInput 1 } + +-- Input Table + + atsInputTable OBJECT-TYPE + SYNTAX SEQUENCE OF ATSPhaseInputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of input table entries. The number of entries + is given by the value of atsNumInputs." + ::= { atsStatusInput 2 } + + atsInputEntry OBJECT-TYPE + SYNTAX ATSPhaseInputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular input." + INDEX { atsInputTableIndex } + ::= { atsInputTable 1 } + + ATSPhaseInputEntry ::= SEQUENCE { + atsInputTableIndex INTEGER, + atsNumInputPhases INTEGER, + atsInputVoltageOrientation INTEGER, + atsInputFrequency INTEGER, + atsInputType INTEGER, + atsInputName DisplayString + } + + atsInputTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input identifier." + ::= { atsInputEntry 1 } + + atsNumInputPhases OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input phases utilized in this + device. The sum of all the atsNumInputPhases + variable indicates the number of rows in the + input phase table." + ::= { atsInputEntry 2 } + + atsInputVoltageOrientation OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + singlePhase(2), + splitPhase(3), + threePhasePhaseToNeutral(4), + threePhasePhaseToPhase(5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input voltage orientation: + 1: unknown for this Source + 2: singlePhase - phase 1 voltage is between Phase 1 + and Neutral. + 3: splitPhase - phase 1 voltage is between Phase 1 and + Neutral; phase 2 voltage is between Phase 2 and Neutral; + phase 3 voltage is between Phase 1 and Phase2. + 4: threePhasePhaseToNeutral - phase 1 voltage is between + Phase 1 and Neutral; phase 2 voltage is between Phase 2 + and Neutral; phase 3 voltage is between Phase3 and + Neutral. + 5: threePhasePhaseToPhase - phase 1 voltage is between + Phase 1 and Phase 2; phase 2 voltage is between Phase 2 + and Phase 3; phase 3 voltage is between Phase 3 and + Phase 1." + ::= { atsInputEntry 3 } + + atsInputFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input frequency in Hertz, or -1 if it's unsupported + by this Source." + ::= { atsInputEntry 4 } + + atsInputType OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + main(2), + bypass(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input type." + ::= { atsInputEntry 5 } + + atsInputName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A name given to a particular input." + ::= { atsInputEntry 6 } + +-- Input Phase Table + + atsInputPhaseTable OBJECT-TYPE + SYNTAX SEQUENCE OF ATSPhaseInputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of input table entries. The number of entries + is given by the sum of the atsNumInputPhases." + ::= { atsStatusInput 3 } + + atsInputPhaseEntry OBJECT-TYPE + SYNTAX ATSPhaseInputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular input phase." + INDEX { atsInputPhaseTableIndex, atsInputPhaseIndex } + ::= { atsInputPhaseTable 1 } + + ATSPhaseInputPhaseEntry ::= SEQUENCE { + atsInputPhaseTableIndex INTEGER, + atsInputPhaseIndex INTEGER, + atsInputVoltage INTEGER, + atsInputMaxVoltage INTEGER, + atsInputMinVoltage INTEGER, + atsInputCurrent INTEGER, + atsInputMaxCurrent INTEGER, + atsInputMinCurrent INTEGER, + atsInputPower INTEGER, + atsInputMaxPower INTEGER, + atsInputMinPower INTEGER + } + + atsInputPhaseTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input identifier." + ::= { atsInputPhaseEntry 1 } + + atsInputPhaseIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input phase identifier." + ::= { atsInputPhaseEntry 2 } + + atsInputVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input voltage in VAC, or -1 if it's unsupported + by this Source." + ::= { atsInputPhaseEntry 3 } + + atsInputMaxVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum input voltage in VAC measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsInputPhaseEntry 4 } + + atsInputMinVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum input voltage in VAC measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsInputPhaseEntry 5 } + + atsInputCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input current in amperes, or -1 if it's + unsupported by this Source." + ::= { atsInputPhaseEntry 6 } + + atsInputMaxCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum input current in amperes measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsInputPhaseEntry 7 } + + atsInputMinCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum input current in amperes measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsInputPhaseEntry 8 } + + atsInputPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The input power in Watts, or -1 if it's unsupported + by this Source." + ::= { atsInputPhaseEntry 9 } + + atsInputMaxPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum input power in Watts measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsInputPhaseEntry 10 } + + atsInputMinPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum input power in Watts measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsInputPhaseEntry 11 } + + -- + -- The Output group. + -- + + -- Number of Outputs + + atsNumOutputs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output feeds to this device. + This variable indicates the number of rows in the + output table." + ::= { atsStatusOutput 1 } + + -- Output Table + + atsOutputTable OBJECT-TYPE + SYNTAX SEQUENCE OF ATSPhaseOutputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of output table entries. The number of entries + is given by the value of atsOutputNumPhases." + ::= { atsStatusOutput 2 } + + atsOutputEntry OBJECT-TYPE + SYNTAX ATSPhaseOutputEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular output." + INDEX { atsOutputTableIndex } + ::= { atsOutputTable 1 } + + ATSPhaseOutputEntry ::= SEQUENCE { + atsOutputTableIndex INTEGER, + atsNumOutputPhases INTEGER, + atsOutputVoltageOrientation INTEGER, + atsOutputFrequency INTEGER + } + + atsOutputTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output identifier." + ::= { atsOutputEntry 1 } + + atsNumOutputPhases OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output phases utilized in this + device. The sum of all the atsNumOutputPhases + variable indicates the number of rows in the + output phase table." + ::= { atsOutputEntry 2 } + + atsOutputVoltageOrientation OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + singlePhase(2), + splitPhase(3), + threePhasePhaseToNeutral(4), + threePhasePhaseToPhase(5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output voltage orientation: + 1: unknown for this ATS + 2: singlePhase - phase 1 voltage is between Phase 1 + and Neutral. + 3: splitPhase - phase 1 voltage is between Phase 1 and + Neutral; phase 2 voltage is between Phase 2 and Neutral; + phase 3 voltage is between Phase 1 and Phase2. + 4: threePhasePhaseToNeutral - phase 1 voltage is between + Phase 1 and Neutral; phase 2 voltage is between Phase 2 + and Neutral; phase 3 voltage is between Phase3 and + Neutral. + 5: threePhasePhaseToPhase - phase 1 voltage is between + Phase 1 and Phase 2; phase 2 voltage is between Phase 2 + and Phase 3; phase 3 voltage is between Phase 3 and + Phase 1." + ::= { atsOutputEntry 3 } + + atsOutputFrequency OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output frequency in Hertz, or -1 if it's + unsupported by this ATS." + ::= { atsOutputEntry 4 } + + -- Output Phase Table + + atsOutputPhaseTable OBJECT-TYPE + SYNTAX SEQUENCE OF ATSPhaseOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of output table entries. The number of + entries is given by the sum of the atsNumOutputPhases." + ::= { atsStatusOutput 3 } + + atsOutputPhaseEntry OBJECT-TYPE + SYNTAX ATSPhaseOutputPhaseEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An entry containing information applicable to a + particular output phase." + INDEX { atsOutputPhaseTableIndex, atsOutputPhaseIndex } + ::= { atsOutputPhaseTable 1 } + + ATSPhaseOutputPhaseEntry ::= SEQUENCE { + atsOutputPhaseTableIndex INTEGER, + atsOutputPhaseIndex INTEGER, + atsOutputVoltage INTEGER, + atsOutputCurrent INTEGER, + atsOutputMaxCurrent INTEGER, + atsOutputMinCurrent INTEGER, + atsOutputLoad INTEGER, + atsOutputMaxLoad INTEGER, + atsOutputMinLoad INTEGER, + atsOutputPercentLoad INTEGER, + atsOutputMaxPercentLoad INTEGER, + atsOutputMinPercentLoad INTEGER, + atsOutputPower INTEGER, + atsOutputMaxPower INTEGER, + atsOutputMinPower INTEGER, + atsOutputPercentPower INTEGER, + atsOutputMaxPercentPower INTEGER, + atsOutputMinPercentPower INTEGER + } + + atsOutputPhaseTableIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output identifier." + ::= { atsOutputPhaseEntry 1 } + + atsOutputPhaseIndex OBJECT-TYPE + SYNTAX INTEGER{ + phase1(1), + phase2(2), + phase3(3), + neutral(4) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Description of each output phase utilized in + this device and one for neutral. " + ::= { atsOutputPhaseEntry 2 } + + atsOutputVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output voltage in VAC, or -1 if it's unsupported + by this ATS." + ::= { atsOutputPhaseEntry 3 } + + atsOutputCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output current in 0.1 amperes drawn + by the load on the ATS, or -1 if it's unsupported + by this ATS." + ::= { atsOutputPhaseEntry 4 } + + atsOutputMaxCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum output current in 0.1 amperes measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 5 } + + atsOutputMinCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum output current in 0.1 amperes measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 6 } + + atsOutputLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output load in VA, or -1 if it's unsupported + by this ATS." + ::= { atsOutputPhaseEntry 7 } + + atsOutputMaxLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum output load in VA measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 8 } + + atsOutputMinLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum output load in VA measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 9 } + + atsOutputPercentLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The percentage of the ATS load capacity in VA at + redundancy @ (n + x) presently being used on this + output phase, or -1 if it's unsupported by this ATS." + ::= { atsOutputPhaseEntry 10 } + + atsOutputMaxPercentLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum percentage of the ATS load capacity in + VA measured at redundancy @ (n + x) presently + being used on this output phase since the last time + this variable was read or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 11 } + + atsOutputMinPercentLoad OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum percentage of the ATS load capacity in + VA measured at redundancy @ (n + x) presently + being used on this output phase since the last time + this variable was read or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 12 } + + atsOutputPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The output power in Watts, or -1 if it's + unsupported by this ATS." + ::= { atsOutputPhaseEntry 13 } + + atsOutputMaxPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum output power in Watts measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 14 } + + atsOutputMinPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum output power in Watts measured + since the last time this variable was read + or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 15 } + + atsOutputPercentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The percentage of the ATSpower capacity in Watts at + redundancy @ (n + x) presently being used on this + output phase, or -1 if it's unsupported by this ATS." + ::= { atsOutputPhaseEntry 16 } + + atsOutputMaxPercentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum percentage of the ATSpower capacity + in Watts measured at redundancy @ (n + x) presently + being used on this output phase since the last time + this variable was read or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 17 } + + atsOutputMinPercentPower OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum percentage of the ATSpower capacity + in Watts measured at redundancy @ (n + x) presently + being used on this output phase since the last time + this variable was read or reset (atsStatusResetMaxMinValues). + Returns (-1) if unsupported." + ::= { atsOutputPhaseEntry 18 } + +-- the dcmim2IdentSystem group + +dcmim2IdentSysFWVersion OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Integer representation of the power plant Master Controller firmware revision." + ::= { dcmim2IdentSystem 1 } + + +-- the dcmim2ControlSystem group + +dcmim2ControlRunFunctBatteryTest OBJECT-TYPE + SYNTAX INTEGER { + battTestOff (1), + battTestOn (2) +} + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this OID will return the battery functional test state. If + the test is off, the battTestOff (1) value will be returned. + If the test is on, the battTestOn (2) value will be + returned. + + Setting this OID to battTestOff (1) will turn the battery functional test off. + Setting this OID to battTestOn (2) will turn the battery functional test on." + + ::= { dcmim2ControlSystem 1 } + +dcmim2ControlRunCapacityBatteryTest OBJECT-TYPE + SYNTAX INTEGER { + battTestOff (1), + battTestOn (2) +} + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this OID will return the battery capacity test state. If + the test is off, the battTestOff (1) value will be returned. + If the test is on, the battTestOn (2) value will be + returned. + + Setting this OID to battTestOff (1) will turn the battery capacity test off. + Setting this OID to battTestOn (2) will turn the battery capacity test on." + + ::= { dcmim2ControlSystem 2 } + + +-- the dcmim2ConfigSystem group + +dcmim2ConfigSysHighTempTrip OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Trip level (threshold) at which System High Temp alarm condition is created. + Range 28 to 100 (degC). + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dcmim2StatusSysTempUnits' OID (Celsius or Fahrenheit)." + + + ::= { dcmim2ConfigSystem 1 } + +dcmim2ConfigSysHighTempReset OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Level at which System High Temp alarm condition is reset (cleared). + Range 25 to (upper temp - 3) (degC). + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dcmim2StatusSysTempUnits' OID (Celsius or Fahrenheit)." + + ::= { dcmim2ConfigSystem 2 } + +dcmim2ConfigSysLowTempTrip OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Trip level (threshold) at which System Low Temp alarm condition is created. + Range -100 to 10 (degC). + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dcmim2StatusSysTempUnits' OID (Celsius or Fahrenheit)." + + ::= { dcmim2ConfigSystem 3 } + +dcmim2ConfigSysLowTempReset OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Level at which System Low Temp alarm condition is reset (cleared). + Range (lower temp + 3) to 13 (degC). + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dcmim2StatusSysTempUnits' OID (Celsius or Fahrenheit)." + + ::= { dcmim2ConfigSystem 4 } + +-- the dcmim2ConfigBattery group + +dcmim2ConfigBattFloatVolt OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery Float Voltage defined at 25 degrees Celsius. + + Values are represented in thousandths of Volts (mV)." + + ::= { dcmim2ConfigBattery 1 } + +dcmim2ConfigBattMaxRecharge OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery Maximum Recharge Rate. This is the maximum current used + during battery charging. + + Values are represented in thousandths of Amps (mA)." + + ::= { dcmim2ConfigBattery 2 } + +dcmim2ConfigBattMfgCapacity OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Battery capacity (Amp-Hour Size) as specified by the battery manufacturer. + + Values are represented in thousandths of Amp hours (mAHr)." + + ::= { dcmim2ConfigBattery 3 } + +dcmim2ConfigBattType OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Type of battery in the powerplant + + Valid values range from 0 to 254." + + ::= { dcmim2ConfigBattery 4 } + +dcmim2ConfigBattFunctTestDuration OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Duration of the battery functional test. + + Values are represented in thousandths of seconds (mSecs)." + + ::= { dcmim2ConfigBattery 5 } + +dcmim2ConfigBattFunctTestThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold the battery voltage of the system must remain above + in order to pass the battery functional test. + + Values are represented in thousandths of Volts (mV)." + + ::= { dcmim2ConfigBattery 6 } + +dcmim2ConfigBattCapacityTestPercent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Threshold for good battery capacity test results. + + Values range from 0 to 100 percent." + + ::= { dcmim2ConfigBattery 7 } + +dcmim2ConfigBattCapacityTestEndThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Safeguard voltage at which battery capacity test will end + if there is a battery problem. + + Values are represented in thousandths of Volts (mV)." + + ::= { dcmim2ConfigBattery 8 } + +dcmim2ConfigBattCapacityTestCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Constant current value used during battery capacity testing. + + Values are represented in thousandths of Amps (mA)." + + ::= { dcmim2ConfigBattery 9 } + + +-- the dcmim2ConfigLVD group + +dcmim2ConfigLVDTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant LVDs controllable + by this IP address." + ::= { dcmim2ConfigLVD 1 } + +dcmim2ConfigLVDTable OBJECT-TYPE + SYNTAX SEQUENCE OF DC2ConfigLVDEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing settings of the LVDs. The number of + entries is contained in the dcmim2ConfigLVDTableSize OID." + ::= { dcmim2ConfigLVD 2 } + +dcmim2ConfigLVDEntry OBJECT-TYPE + SYNTAX DC2ConfigLVDEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The LVD to configure." + INDEX { dcmim2ConfigLVDIndex } + ::= { dcmim2ConfigLVDTable 1 } + +DC2ConfigLVDEntry ::= + SEQUENCE { + dcmim2ConfigLVDIndex INTEGER, + dcmim2ConfigLVDTrip INTEGER, + dcmim2ConfigLVDReset INTEGER, + dcmim2ConfigLVDState INTEGER + } + +dcmim2ConfigLVDIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant LVD." + ::= { dcmim2ConfigLVDEntry 1 } + +dcmim2ConfigLVDTrip OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "LVD Trip threshold. System bus voltage at which LVD will trip (open) + during a battery backup operation. + + Values are represented in thousandths of Volts (mV)." + ::= { dcmim2ConfigLVDEntry 2 } + +dcmim2ConfigLVDReset OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "LVD Reset threshold. System bus voltage at which LVD will reset (close) + after AC power has been restored. + + Values are represented in thousandths of Volts (mV)." + ::= { dcmim2ConfigLVDEntry 3 } + +dcmim2ConfigLVDState OBJECT-TYPE + SYNTAX INTEGER { + statusClosed (1), + statusOpened (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusClosed (1) if the LVD is closed. + statusOpened (2) will be returned if the LVD is opened." + ::= { dcmim2ConfigLVDEntry 4 } + + +-- the dcmim2StatusSystem group + +dcmim2StatusSysRectCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System (Total Rectifier) current in thousandths of Amps (mA)." + ::= { dcmim2StatusSystem 1 } + +dcmim2StatusSysLoadCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Load current in thousandths of Amps (mA)." + ::= { dcmim2StatusSystem 2 } + +dcmim2StatusSysBusVoltage OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System bus voltage in thousandths of Volts (mV)." + ::= { dcmim2StatusSystem 3 } + +dcmim2StatusSysAmbientTemp OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "System temperature based on sensor on Master Controller PCB. + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dcmim2StatusSysTempUnits' OID (Celsius or Fahrenheit)." + ::= { dcmim2StatusSystem 4 } + +dcmim2StatusSysUpTime OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Length of time since the DC Powerplant controller has been powered up." + ::= { dcmim2StatusSystem 5 } + +dcmim2StatusSysTempUnits OBJECT-TYPE + SYNTAX INTEGER { + celsius(1), + fahrenheit(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature scale used to display the temperature + in the DC system, Celsius(1) or Fahrenheit(2). + This setting is based on the system preferences + configuration in the agent." + ::= { dcmim2StatusSystem 6 } + + +-- the dcmim2StatusRectifier group + +dcmim2StatusRectTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant rectifiers viewable + by this IP address." + ::= { dcmim2StatusRectifier 1 } + +dcmim2StatusRectTable OBJECT-TYPE + SYNTAX SEQUENCE OF DC2StatusRectEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing settings of the rectifiers. The number of + entries is contained in the dcmim2StatusRectTableSize OID." + ::= { dcmim2StatusRectifier 2 } + +dcmim2StatusRectEntry OBJECT-TYPE + SYNTAX DC2StatusRectEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The rectifier to gather status from." + INDEX { dcmim2StatusRectIndex } + ::= { dcmim2StatusRectTable 1 } + +DC2StatusRectEntry ::= + SEQUENCE { + dcmim2StatusRectIndex INTEGER, + dcmim2StatusRectDevType INTEGER, + dcmim2StatusRectID INTEGER, + dcmim2StatusRectPhyAddr INTEGER, + dcmim2StatusRectFail INTEGER, + dcmim2StatusRectCurrent INTEGER + } + +dcmim2StatusRectIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant rectifier." + ::= { dcmim2StatusRectEntry 1 } + +dcmim2StatusRectDevType OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier device type." + ::= { dcmim2StatusRectEntry 2 } + +dcmim2StatusRectID OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier ID. This enumerates the number of the rectifier within + a group of rectifiers." + ::= { dcmim2StatusRectEntry 3 } + +dcmim2StatusRectPhyAddr OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the rectifier physical address (the address on the bus)." + ::= { dcmim2StatusRectEntry 4 } + +dcmim2StatusRectFail OBJECT-TYPE + SYNTAX INTEGER { + statusTrue (1), + statusFalse (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusTrue (1) if the rectifier has failed. + statusFalse (2) will be returned if the rectifier has not failed." + ::= { dcmim2StatusRectEntry 5 } + +dcmim2StatusRectCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID shows the individual rectifier current in thousandths of Amps (mA)." + ::= { dcmim2StatusRectEntry 6 } + + +-- the dcmim2StatusBattery group + +dcmim2StatusBattFloatVolt OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Battery Float Voltage represented in thousandths of Volts (mV)." + ::= { dcmim2StatusBattery 1 } + +dcmim2StatusBattCurrent OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Battery Current: This OID shows the battery current in thousandths of Amps (mA)." + ::= { dcmim2StatusBattery 2 } + +dcmim2StatusBattTemp OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Battery Temperature: + + Values are represented in thousandths of a degree. + Units are displayed in the scale shown in + the 'dcmim2StatusSysTempUnits' OID (Celsius or Fahrenheit)." + ::= { dcmim2StatusBattery 3 } + +dcmim2StatusBattMfgCapacity OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Battery capacity (Amp-Hour Size) as specified by the battery manufacturer. + Values are represented in thousandths of Amp hours (mAHr)." + ::= { dcmim2StatusBattery 4 } + +dcmim2StatusBattTestCapacity OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Battery capacity (Amp-Hour Size) as determined by the battery capacity test. + Values are represented in thousandths of Amp hours (mAHr)." + ::= { dcmim2StatusBattery 5 } + +dcmim2StatusBattFunctTestResult OBJECT-TYPE + SYNTAX INTEGER{ + functTestNotPerformed (1), + functTestInProcess (2), + functTestInterrupted (3), + functTestPass (4), + functTestFail (5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Results of the last battery functional test that was run." + ::= { dcmim2StatusBattery 6 } + +dcmim2StatusBattCapacityTestResult OBJECT-TYPE + SYNTAX INTEGER{ + capacityTestNotPerformed (1), + capacityTestInProcess (2), + capacityTestInterrupted (3), + capacityTestPass (4), + capacityTestFail (5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Results of the last battery capacity test that was run." + ::= { dcmim2StatusBattery 7 } + + +-- the dcmim2StatusLVD group + +dcmim2StatusLVDTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant LVDs accessible + by this IP address." + ::= { dcmim2StatusLVD 1 } + +dcmim2StatusLVDTable OBJECT-TYPE + SYNTAX SEQUENCE OF DC2StatusLVDEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing the LVDs. The number of + entries is contained in the dcmim2StatusLVDTableSize OID." + ::= { dcmim2StatusLVD 2 } + +dcmim2StatusLVDEntry OBJECT-TYPE + SYNTAX DC2StatusLVDEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The LVD to access." + INDEX { dcmim2StatusLVDIndex } + ::= { dcmim2StatusLVDTable 1 } + +DC2StatusLVDEntry ::= + SEQUENCE { + dcmim2StatusLVDIndex INTEGER, + dcmim2StatusLVDState INTEGER + } + +dcmim2StatusLVDIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the DC powerplant LVD." + ::= { dcmim2StatusLVDEntry 1 } + +dcmim2StatusLVDState OBJECT-TYPE + SYNTAX INTEGER { + statusClosed (1), + statusOpened (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this OID will return statusClosed (1) if the LVD is closed. + statusOpened (2) will be returned if the LVD is opened." + ::= { dcmim2StatusLVDEntry 2 } + + +-- the dcmim2StatusAlarms group + +dcmim2StatusAlarmsTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of DC powerplant alarms viewable + by this IP address." + ::= { dcmim2StatusAlarms 1 } + +dcmim2StatusAlarmsTable OBJECT-TYPE + SYNTAX SEQUENCE OF DC2StatusAlarmsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for accessing system alarms. The number of + entries is contained in the dcmim2StatusAlarmsTableSize OID." + ::= { dcmim2StatusAlarms 2 } + +dcmim2StatusAlarmsEntry OBJECT-TYPE + SYNTAX DC2StatusAlarmsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The alarm to display." + INDEX { dcmim2StatusAlarmsIndex } + ::= { dcmim2StatusAlarmsTable 1 } + +DC2StatusAlarmsEntry ::= + SEQUENCE { + dcmim2StatusAlarmsIndex INTEGER, + dcmim2StatusAlarmsText DisplayString + } + +dcmim2StatusAlarmsIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the system alarm." + ::= { dcmim2StatusAlarmsEntry 1 } + +dcmim2StatusAlarmsText OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The 16 character text describing the active alarm condition." + ::= { dcmim2StatusAlarmsEntry 2 } + +-- External Environmental Monitor + +emIdentFirmwareRevision OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the Environmental Monitor." + ::= { emIdent 1 } + +emConfigProbesNumProbes OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of temperature and humidity probes available." + ::= { emConfig 1 } + +emConfigProbesTable OBJECT-TYPE + SYNTAX SEQUENCE OF EmConfigProbesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of probes supported by the Environmental Monitor + and their configurations." + ::= { emConfig 2 } + +emConfigProbesEntry OBJECT-TYPE + SYNTAX EmConfigProbesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The Environmental Monitor probe configurations." + INDEX { emConfigProbeNumber } + ::= { emConfigProbesTable 1 } + +EmConfigProbesEntry ::= + SEQUENCE { + emConfigProbeNumber + INTEGER, + emConfigProbeName + DisplayString, + emConfigProbeHighTempThreshold + INTEGER, + emConfigProbeLowTempThreshold + INTEGER, + emConfigProbeTempUnits + INTEGER, + emConfigProbeHighHumidThreshold + INTEGER, + emConfigProbeLowHumidThreshold + INTEGER, + emConfigProbeHighTempEnable + INTEGER, + emConfigProbeLowTempEnable + INTEGER, + emConfigProbeHighHumidEnable + INTEGER, + emConfigProbeLowHumidEnable + INTEGER + } + +emConfigProbeNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index into an Environmental Monitor probe entry." + ::= { emConfigProbesEntry 1 } + +emConfigProbeName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A descriptive name of the probe set by the user, + possibly denoting its location or purpose." + ::= { emConfigProbesEntry 2 } + +emConfigProbeHighTempThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The high temperature alarm threshold for the probe. + Units are displayed in the scale selected in + the 'emConfigProbeTempUnits' OID (Celsius or Fahrenheit)." + ::= { emConfigProbesEntry 3 } + +emConfigProbeLowTempThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The low temperature alarm threshold for the probe. + Units are displayed in the scale selected in + the 'emConfigProbeTempUnits' OID (Celsius or Fahrenheit)." + ::= { emConfigProbesEntry 4 } + +emConfigProbeTempUnits OBJECT-TYPE + SYNTAX INTEGER { + celsius(1), + fahrenheit(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature scale used to display the temperature + thresholds of the probe, Celsius(1) or Fahrenheit(2). + This setting is based on the system preferences + configuration in the agent." + ::= { emConfigProbesEntry 5 } + +emConfigProbeHighHumidThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The high humidity alarm threshold for the probe in + percent relative humidity." + ::= { emConfigProbesEntry 6 } + +emConfigProbeLowHumidThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The low humidity alarm threshold for the probe in + percent relative humidity." + ::= { emConfigProbesEntry 7 } + +emConfigProbeHighTempEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The high temperature alarm enable/disable for the + probe. No alarm will be generated if this value + is set to disabled(1). The alarm will be + generated if this value is set to enabled(2) and + the threshold has been violated." + ::= { emConfigProbesEntry 8 } + +emConfigProbeLowTempEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The low temperature alarm enable/disable for the + probe. No alarm will be generated if this value + is set to disabled(1). The alarm will be + generated if this value is set to enabled(2) and + the threshold has been violated." + ::= { emConfigProbesEntry 9 } + +emConfigProbeHighHumidEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The high humidity alarm enable/disable for the + probe. No alarm will be generated if this value + is set to disabled(1). The alarm will be + generated if this value is set to enabled(2) and + the threshold has been violated." + ::= { emConfigProbesEntry 10 } + +emConfigProbeLowHumidEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The low humidity alarm enable/disable for the + probe. No alarm will be generated if this value + is set to disabled(1). The alarm will be + generated if this value is set to enabled(2) and + the threshold has been violated." + ::= { emConfigProbesEntry 11 } + +emConfigContactsNumContacts OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of contacts supported by the Environmental + Monitor." + ::= { emConfig 3 } + +emConfigContactsTable OBJECT-TYPE + SYNTAX SEQUENCE OF EmConfigContactsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of contacts supported by the Environmental Monitor + and their configurations." + ::= { emConfig 4 } + +emConfigContactsEntry OBJECT-TYPE + SYNTAX EmConfigContactsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The Environmental Monitor contact configurations." + INDEX { emConfigContactNumber } + ::= { emConfigContactsTable 1 } + +EmConfigContactsEntry ::= + SEQUENCE { + emConfigContactNumber + INTEGER, + emConfigContactName + DisplayString, + emConfigContactEnable + INTEGER + } + +emConfigContactNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of an Environmental Monitor contact." + ::= { emConfigContactsEntry 1 } + +emConfigContactName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A descriptive name for an Environmental Monitor + contact set by the user, possibly denoting its + location or purpose." + ::= { emConfigContactsEntry 2 } + +emConfigContactEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An Environmental Monitor contact alarm enable/disable. + No alarm will be generated if the contact is disabled(1). + An alarm will be generated if the contact is enabled(2) + and the contact has been faulted." + ::= { emConfigContactsEntry 3 } + +emStatusCommStatus OBJECT-TYPE + SYNTAX INTEGER { + noComm(1), + comm(2), + commLost(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The communication status between the agent + and the Environmental Monitor. + + noComm(1), Communication has never been established. + comm(2), Communication has been established. + commLost(3), Communication was established, but was lost." + ::= { emStatus 1 } + +emStatusProbesNumProbes OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of available probes on the Environmental + Monitor." + ::= { emStatus 2 } + +emStatusProbesTable OBJECT-TYPE + SYNTAX SEQUENCE OF EmStatusProbesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of probes supported by the Environmental Monitor + and their status." + ::= { emStatus 3 } + +emStatusProbesEntry OBJECT-TYPE + SYNTAX EmStatusProbesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The status of the probe." + INDEX { emStatusProbeNumber } + ::= { emStatusProbesTable 1 } + +EmStatusProbesEntry ::= + SEQUENCE { + emStatusProbeNumber + INTEGER, + emStatusProbeName + DisplayString, + emStatusProbeStatus + INTEGER, + emStatusProbeCurrentTemp + INTEGER, + emStatusProbeTempUnits + INTEGER, + emStatusProbeCurrentHumid + INTEGER, + emStatusProbeHighTempViolation + INTEGER, + emStatusProbeLowTempViolation + INTEGER, + emStatusProbeHighHumidViolation + INTEGER, + emStatusProbeLowHumidViolation + INTEGER + } + +emStatusProbeNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the probe." + ::= { emStatusProbesEntry 1 } + +emStatusProbeName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A descriptive name for the probe set by the user, + possibly denoting its location or purpose." + ::= { emStatusProbesEntry 2 } + +emStatusProbeStatus OBJECT-TYPE + SYNTAX INTEGER { + disconnected(1), + connected(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The connected status of the probe, either + disconnected(1) or connected(2)." + ::= { emStatusProbesEntry 3 } + +emStatusProbeCurrentTemp OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current temperature reading from the probe displayed + in the units shown in the 'emStatusProbeTempUnits' OID + (Celsius or Fahrenheit)." + ::= { emStatusProbesEntry 4 } + +emStatusProbeTempUnits OBJECT-TYPE + SYNTAX INTEGER { + celsius(1), + fahrenheit(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature scale used to display the temperature + thresholds of the probe, Celsius(1) or Fahrenheit(2). + This setting is based on the system preferences + configuration in the agent." + ::= { emStatusProbesEntry 5 } + +emStatusProbeCurrentHumid OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current humidity reading from the probe in + percent relative humidity." + ::= { emStatusProbesEntry 6 } + +emStatusProbeHighTempViolation OBJECT-TYPE + SYNTAX INTEGER { + noViolation(1), + highTempViolation(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The high temperature violation status of the probe + temperature reading. This OID will show a highTempViolation(2) + if the current temperature reading shown in the + 'emStatusProbeCurrentTemp' OID is greater than or equal to + the high temperature threshold value, the + 'emConfigProbeHighTempThreshold' OID, and the value of the + 'emConfigProbeHighTempEnable' OID is enabled. Otherwise it will show + noViolation(1). If the 'emConfigProbeHighTempEnable' OID is disabled, + this OID will show disabled(3)." + ::= { emStatusProbesEntry 7 } + +emStatusProbeLowTempViolation OBJECT-TYPE + SYNTAX INTEGER { + noViolation(1), + lowTempViolation(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The high temperature violation status of the probe + temperature reading. This OID will show a lowTempViolation(2) + if the current temperature reading shown in the + 'emStatusProbeCurrentTemp' OID is less than or equal to + the low temperature threshold value, the + 'emConfigProbeLowTempThreshold' OID, and the value of the + 'emConfigProbeLowTempEnable' OID is enabled. Otherwise it will show + noViolation(1). If the 'emConfigProbeLowTempEnable' OID is disabled, + this OID will show disabled(3)." + ::= { emStatusProbesEntry 8 } + +emStatusProbeHighHumidViolation OBJECT-TYPE + SYNTAX INTEGER { + noViolation(1), + highHumidViolation(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The high humidity violation status of the probe humidity + reading. This OID will show a highTempViolation(2) + if the current humidity reading shown in the + 'emStatusProbeCurrentHumid' OID is greater than or equal to + the high humidity threshold value, the + 'emConfigProbeHighHumidThreshold' OID, and the value of the + 'emConfigProbeHighHumidEnable' OID is enabled. Otherwise it will + show noViolation(1). If the 'emConfigProbeHighHumidEnable' OID is + disabled, this OID will show disabled(3)" + ::= { emStatusProbesEntry 9 } + +emStatusProbeLowHumidViolation OBJECT-TYPE + SYNTAX INTEGER { + noViolation(1), + lowHumidViolation(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The low humidity violation status of the probe humidity + reading. This OID will show a lowTempViolation(2) + if the current humidity reading shown in the + 'emStatusProbeCurrentHumid' OID is less than or equal to + the low humidity threshold value, the + 'emConfigProbeLowHumidThreshold' OID, and the value of the + 'emConfigProbeLowHumidEnable' OID is enabled. Otherwise it will + show noViolation(1). If the 'emConfigProbeLowHumidEnable' OID is + disabled, this OID will show disabled(3)." + ::= { emStatusProbesEntry 10 } + +emStatusContactsNumContacts OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of contacts supported by the + Environmental Monitor." + ::= { emStatus 4 } + +emStatusContactsTable OBJECT-TYPE + SYNTAX SEQUENCE OF EmStatusContactsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of contacts supported by the Environmental Monitor + and their status." + ::= { emStatus 5 } + +emStatusContactsEntry OBJECT-TYPE + SYNTAX EmStatusContactsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The status of the contact." + INDEX { emStatusContactNumber } + ::= { emStatusContactsTable 1 } + +EmStatusContactsEntry ::= + SEQUENCE { + emStatusContactNumber + INTEGER, + emStatusContactName + DisplayString, + emStatusContactStatus + INTEGER + } + +emStatusContactNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the Environmental Monitor contact." + ::= { emStatusContactsEntry 1 } + +emStatusContactName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A descriptive name for the Environmental Monitor contact + set by the user, possibly denoting its location or purpose." + ::= { emStatusContactsEntry 2 } + +emStatusContactStatus OBJECT-TYPE + SYNTAX INTEGER { + noFault(1), + fault(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Environmental Monitor contact. The status + will show noFault(1) if the contact is in the normal state + and the 'emConfigContactEnable' OID is enabled. The status will + show a fault(2) if the contact is faulted and the + 'emContactEnable' OID is enabled. If the 'emConfigContactEnable' + OID is disabled, the status will show disabled(3)." + ::= { emStatusContactsEntry 3 } + +-- Integrated Environmental Monitor (IEM) + +iemIdentHardwareRevision OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the Integrated Environmental + Monitor." + ::= { iemIdent 1 } + +iemConfigProbesNumProbes OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of temperature and humidity probes available." + ::= { iemConfig 1 } + +iemConfigProbesTable OBJECT-TYPE + SYNTAX SEQUENCE OF IemConfigProbesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of probes supported by the Environmental Monitor + and their configurations." + ::= { iemConfig 2 } + +iemConfigProbesEntry OBJECT-TYPE + SYNTAX IemConfigProbesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The Environmental Monitor probe configurations." + INDEX { iemConfigProbeNumber } + ::= { iemConfigProbesTable 1 } + +IemConfigProbesEntry ::= + SEQUENCE { + iemConfigProbeNumber + INTEGER, + iemConfigProbeName + DisplayString, + iemConfigProbeHighTempThreshold + INTEGER, + iemConfigProbeLowTempThreshold + INTEGER, + iemConfigProbeTempUnits + INTEGER, + iemConfigProbeHighHumidThreshold + INTEGER, + iemConfigProbeLowHumidThreshold + INTEGER, + iemConfigProbeHighTempEnable + INTEGER, + iemConfigProbeLowTempEnable + INTEGER, + iemConfigProbeHighHumidEnable + INTEGER, + iemConfigProbeLowHumidEnable + INTEGER + } + +iemConfigProbeNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to a Environmental Monitor probe entry." + ::= { iemConfigProbesEntry 1 } + +iemConfigProbeName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A descriptive name for the probe set by the user, + possibly denoting its location or purpose." + ::= { iemConfigProbesEntry 2 } + +iemConfigProbeHighTempThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The high temperature alarm threshold for the probe. + Units are displayed in the scale selected in the + 'iemConfigProbeTempUnits' OID (Celsius or Fahrenheit)." + ::= { iemConfigProbesEntry 3 } + +iemConfigProbeLowTempThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The low temperature alarm threshold for the probe. + Units are displayed in the scale selected in the + 'iemConfigProbeTempUnits' OID (Celsius or Fahrenheit)." + ::= { iemConfigProbesEntry 4 } + +iemConfigProbeTempUnits OBJECT-TYPE + SYNTAX INTEGER { + celsius(1), + fahrenheit(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature scale used to display the temperature + thresholds of the probe, Celsius(1) or Fahrenheit(2). + This setting is based on the system preferences + configuration in the agent." + ::= { iemConfigProbesEntry 5 } + +iemConfigProbeHighHumidThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The high humidity alarm threshold for the probe in + percent relative humidity." + ::= { iemConfigProbesEntry 6 } + +iemConfigProbeLowHumidThreshold OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The low humidity alarm threshold for the probe in + percent relative humidity." + ::= { iemConfigProbesEntry 7 } + +iemConfigProbeHighTempEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The high temperature alarm enable/disable for the + probe. No alarm will be generated if this value + is set to disabled(1). The alarm will be + generated if this value is set to enabled(2) and + the threshold has been violated." + ::= { iemConfigProbesEntry 8 } + +iemConfigProbeLowTempEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The low temperature alarm enable/disable for the + probe. No alarm will be generated if this value + is set to disabled(1). The alarm will be + generated if this value is set to enabled(2) and + the threshold has been violated." + ::= { iemConfigProbesEntry 9 } + +iemConfigProbeHighHumidEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The high humidity alarm enable/disable for the + probe. No alarm will be generated if this value + is set to disabled(1). The alarm will be + generated if this value is set to enabled(2) and + the threshold has been violated." + ::= { iemConfigProbesEntry 10 } + +iemConfigProbeLowHumidEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The low humidity alarm enable/disable for the + probe. No alarm will be generated if this value + is set to disabled(1). The alarm will be + generated if this value is set to enabled(2) and + the threshold has been violated." + ::= { iemConfigProbesEntry 11 } + +iemConfigContactsNumContacts OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of contacts available on the Environmental + Monitor." + ::= { iemConfig 3 } + +iemConfigContactsTable OBJECT-TYPE + SYNTAX SEQUENCE OF IemConfigContactsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of contacts supported by the Environmental Monitor + and their configurations." + ::= { iemConfig 4 } + +iemConfigContactsEntry OBJECT-TYPE + SYNTAX IemConfigContactsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The Environmental Monitor contact configurations." + INDEX { iemConfigContactNumber } + ::= { iemConfigContactsTable 1 } + +IemConfigContactsEntry ::= + SEQUENCE { + iemConfigContactNumber + INTEGER, + iemConfigContactName + DisplayString, + iemConfigContactEnable + INTEGER + } + +iemConfigContactNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of an Environmental Monitor contact." + ::= { iemConfigContactsEntry 1 } + +iemConfigContactName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A descriptive name for the Environmental Monitor contact + set by the user, possibly denoting its location or purpose." + ::= { iemConfigContactsEntry 2 } + +iemConfigContactEnable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An Environmental Monitor contact alarm enable/disable." + ::= { iemConfigContactsEntry 3 } + + +iemStatusProbesNumProbes OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of available probes on the Environmental + Monitor." + ::= { iemStatus 1 } + +iemStatusProbesTable OBJECT-TYPE + SYNTAX SEQUENCE OF IemStatusProbesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of probes supported by the Environmental Monitor + and their status." + ::= { iemStatus 2 } + +iemStatusProbesEntry OBJECT-TYPE + SYNTAX IemStatusProbesEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The status of the probe." + INDEX { iemStatusProbeNumber } + ::= { iemStatusProbesTable 1 } + +IemStatusProbesEntry ::= + SEQUENCE { + iemStatusProbeNumber + INTEGER, + iemStatusProbeName + DisplayString, + iemStatusProbeStatus + INTEGER, + iemStatusProbeCurrentTemp + INTEGER, + iemStatusProbeTempUnits + INTEGER, + iemStatusProbeCurrentHumid + INTEGER, + iemStatusProbeHighTempViolation + INTEGER, + iemStatusProbeLowTempViolation + INTEGER, + iemStatusProbeHighHumidViolation + INTEGER, + iemStatusProbeLowHumidViolation + INTEGER + } + +iemStatusProbeNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the probe." + ::= { iemStatusProbesEntry 1 } + +iemStatusProbeName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A descriptive name for the probe set by the user, + denoting its location or purpose." + ::= { iemStatusProbesEntry 2 } + +iemStatusProbeStatus OBJECT-TYPE + SYNTAX INTEGER { + disconnected(1), + connected(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The connected status of the probe, either + disconnected(1) or connected(2)." + ::= { iemStatusProbesEntry 3 } + +iemStatusProbeCurrentTemp OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current temperature reading from the probe displayed + in the units shown in the 'iemStatusProbeTempUnits' OID + (Celsius or Fahrenheit)." + ::= { iemStatusProbesEntry 4 } + +iemStatusProbeTempUnits OBJECT-TYPE + SYNTAX INTEGER { + celsius(1), + fahrenheit(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature scale used to display the temperature + thresholds of the probe, Celsius(1) or Fahrenheit(2). + This setting is based on the system preferences + configuration in the agent." + ::= { iemStatusProbesEntry 5 } + +iemStatusProbeCurrentHumid OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current humidity reading from the probe in percent + relative humidity." + ::= { iemStatusProbesEntry 6 } + +iemStatusProbeHighTempViolation OBJECT-TYPE + SYNTAX INTEGER { + noViolation(1), + highTempViolation(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The high temperature violation status of the probe + temperature reading. This OID will show a highTempViolation(2) + if the current temperature reading shown in the + 'iemStatusProbeCurrentTemp' OID is greater than or equal to + the high temperature threshold value, the + 'iemConfigProbeHighTempThreshold' OID, and the value of the + 'iemConfigProbeHighTempEnable' OID is enabled. Otherwise it will show + noViolation(1). If the 'iemConfigProbeHighTempEnable' OID is disabled, + this OID will show disabled(3)." + ::= { iemStatusProbesEntry 7 } + +iemStatusProbeLowTempViolation OBJECT-TYPE + SYNTAX INTEGER { + noViolation(1), + lowTempViolation(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The high temperature violation status of the probe + temperature reading. This OID will show a lowTempViolation(2) + if the current temperature reading shown in the + 'iemStatusProbeCurrentTemp' OID is less than or equal to + the low temperature threshold value, the + 'iemConfigProbeLowTempThreshold' OID, and the value of the + 'iemPConfigrobeLowTempEnable' OID is enabled. Otherwise it will show + noViolation(1). If the 'iemConfigProbeLowTempEnable' OID is disabled, + this OID will show disabled(3)." + ::= { iemStatusProbesEntry 8 } + +iemStatusProbeHighHumidViolation OBJECT-TYPE + SYNTAX INTEGER { + noViolation(1), + highHumidViolation(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The high humidity violation status of the probe humidity + reading. This OID will show a highTempViolation(2) + if the current humidity reading shown in the + 'iemStatusProbeCurrentHumid' OID is greater than or equal to + the high humidity threshold value, the + 'iemConfigProbeHighHumidThreshold' OID, and the value of the + 'iemConfigProbeHighHumidEnable' OID is enabled. Otherwise it will + show noViolation(1). If the 'iemConfigProbeHighHumidEnable' OID is + disabled, this OID will show disabled(3)." + ::= { iemStatusProbesEntry 9 } + +iemStatusProbeLowHumidViolation OBJECT-TYPE + SYNTAX INTEGER { + noViolation(1), + lowHumidViolation(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The low humidity violation status of the probe humidity + reading. This OID will show a lowTempViolation(2) + if the current humidity reading shown in the + 'iemStatusProbeCurrentHumid' OID is less than or equal to + the low humidity threshold value, the + 'iemConfigProbeLowHumidThreshold' OID, and the value of the + 'iemConfigProbeLowHumidEnable' OID is enabled. Otherwise it will + show noViolation(1). If the 'iemConfigProbeLowHumidEnable' OID is + disabled, this OID will show disabled(3)." + ::= { iemStatusProbesEntry 10 } + +iemStatusContactsNumContacts OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of contacts supported on the + Environmental Monitor." + ::= { iemStatus 3 } + +iemStatusContactsTable OBJECT-TYPE + SYNTAX SEQUENCE OF IemStatusContactsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of contacts supported by the Environmental Monitor + and their status." + ::= { iemStatus 4 } + +iemStatusContactsEntry OBJECT-TYPE + SYNTAX IemStatusContactsEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The status of the contact." + INDEX { iemStatusContactNumber } + ::= { iemStatusContactsTable 1 } + +IemStatusContactsEntry ::= + SEQUENCE { + iemStatusContactNumber + INTEGER, + iemStatusContactName + DisplayString, + iemStatusContactStatus + INTEGER + } + +iemStatusContactNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the Environmental Monitor contact." + ::= { iemStatusContactsEntry 1 } + +iemStatusContactName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A descriptive name for the Environmental Monitor contact + set by the user, denoting its location or purpose." + ::= { iemStatusContactsEntry 2 } + +iemStatusContactStatus OBJECT-TYPE + SYNTAX INTEGER { + noFault(1), + fault(2), + disabled(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the Environmental Monitor contact. The status + will show noFault(1) if the contact is in the normal state + and the 'iemConfigContactEnable' OID is enabled. The status will + show a fault(2) if the contact is faulted and the + 'iemConfigContactEnable' OID is enabled. If the + 'iemConfigContactEnable' OID is disabled, the status will show + disabled(3)." + ::= { iemStatusContactsEntry 3 } + +iemStatusRelaysNumRelays OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output relays supported on the + Environmental Monitor." + ::= { iemStatus 6 } + +iemStatusRelaysTable OBJECT-TYPE + SYNTAX SEQUENCE OF IemStatusRelaysEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of output relays supported by the + Environmental Monitor and their status." + ::= { iemStatus 7 } + +iemStatusRelaysEntry OBJECT-TYPE + SYNTAX IemStatusRelaysEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The status of the relay." + INDEX { iemStatusRelayNumber } + ::= { iemStatusRelaysTable 1 } + +IemStatusRelaysEntry ::= + SEQUENCE { + iemStatusRelayNumber + INTEGER, + iemStatusRelayName + DisplayString, + iemStatusRelayStatus + INTEGER + } + +iemStatusRelayNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the output relay." + ::= { iemStatusRelaysEntry 1 } + +iemStatusRelayName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A descriptive name for the output relay set by the + user, denoting its location or purpose." + ::= { iemStatusRelaysEntry 2 } + +iemStatusRelayStatus OBJECT-TYPE + SYNTAX INTEGER { + faultState(1), + normalState(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the output relay, either faultState(1) or + normalState(2)." + ::= { iemStatusRelaysEntry 3 } + +-- Environmental Management System (EMS) + +-- EMS IDENT + +emsIdentEMSName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the + device. " + ::= { emsIdent 1 } + +emsIdentProductNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the model number of + the device. This value is set at the factory." + ::= { emsIdent 2 } + +emsIdentFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The firmware revision of the device." + ::= { emsIdent 3 } + +emsIdentHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The hardware revision of the device. + This value is set at the factory." + ::= { emsIdent 4 } + +emsIdentDateOfManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The date when the device was manufactured in mm/dd/yyyy format. + This value is set at the factory. " + ::= { emsIdent 5 } + +emsIdentSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the serial number of + the device. This value is set at the factory." + ::= { emsIdent 6 } + +-- EMS CONTROL + +-- EMS OUTPUT RELAY CONTROL STATUS TABLE + +emsOutputRelayControlTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutputRelayControlEMSEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of individual output relays. The number of + entries is contained in the emsStatusOutputRelayCount OID." + ::= { emsOutputRelayControl 1 } + +emsOutputRelayControlEntry OBJECT-TYPE + SYNTAX OutputRelayControlEMSEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The output relays to control." + INDEX { emsOutputRelayControlOutputRelayIndex } + ::= { emsOutputRelayControlTable 1 } + +OutputRelayControlEMSEntry ::= + SEQUENCE { + emsOutputRelayControlOutputRelayIndex INTEGER, + emsOutputRelayControlOutputRelayName DisplayString, + emsOutputRelayControlOutputRelayCommand INTEGER + } + +emsOutputRelayControlOutputRelayIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the output relay entry." + ::= { emsOutputRelayControlEntry 1 } + +emsOutputRelayControlOutputRelayName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the output relay. + This OID is provided for informational purposes only." + ::= { emsOutputRelayControlEntry 2 } + +emsOutputRelayControlOutputRelayCommand OBJECT-TYPE + SYNTAX INTEGER { + immediateCloseEMS (1), + immediateOpenEMS (2) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the output relay state. If + the output relay is closed, the immediateCloseEMS (1) value will be returned. + If the output relay is open, the immediateOpenEMS (2) value will be + returned. + + Setting this variable to immediateCloseEMS (1) will immediately close the relay. + + Setting this variable to immediateOpenEMS (2) will immediately open the relay." + ::= { emsOutputRelayControlEntry 3 } + +-- EMS OUTLET CONTROL TABLE + +emsOutletControlTable OBJECT-TYPE + SYNTAX SEQUENCE OF OutletControlEMSEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of individual outlet switches. The number of + entries is contained in the emsStatusOutletCount OID." + ::= { emsOutletControl 1 } + +emsOutletControlEntry OBJECT-TYPE + SYNTAX OutletControlEMSEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to control." + INDEX { emsOutletControlOutletIndex } + ::= { emsOutletControlTable 1 } + +OutletControlEMSEntry ::= + SEQUENCE { + emsOutletControlOutletIndex INTEGER, + emsOutletControlOutletName DisplayString, + emsOutletControlOutletCommand INTEGER + } + +emsOutletControlOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { emsOutletControlEntry 1 } + +emsOutletControlOutletName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet. + This OID is provided for informational purposes only." + ::= { emsOutletControlEntry 2 } + +emsOutletControlOutletCommand OBJECT-TYPE + SYNTAX INTEGER { + immediateOnEMS (1), + immediateOffEMS (2) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the outlet state. If + the outlet is on, the immediateOnEMS (1) value will be returned. + If the outlet is off, the immediateOffEMS (2) value will be + returned. + + Setting this variable to immediateOnEMS (1) will immediately turn the outlet on. + + Setting this variable to immediateOffEMS (2) will immediately turn the outlet off." + ::= { emsOutletControlEntry 3 } + +-- EMS SENSOR CONTROL TABLE + +emsSensorControlTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSSensorControlEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control/reset of individual sensors. The number of + entries is contained in the emsStatusSensorCount OID." + ::= { emsSensorControl 1 } + +emsSensorControlEntry OBJECT-TYPE + SYNTAX EMSSensorControlEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The sensors to control/reset." + INDEX { emsSensorControlSensorIndex } + ::= { emsSensorControlTable 1 } + +EMSSensorControlEntry ::= + SEQUENCE { + emsSensorControlSensorIndex INTEGER, + emsSensorControlSensorSystemName DisplayString, + emsSensorControlSensorUserName DisplayString, + emsSensorControlSensorCommand INTEGER + } + +emsSensorControlSensorIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the sensor entry." + ::= { emsSensorControlEntry 1 } + +emsSensorControlSensorSystemName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system name of the sensor. This describes the hardware system + intent of this sensor." + ::= { emsSensorControlEntry 2 } + +emsSensorControlSensorUserName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the sensor as given by the system user." + ::= { emsSensorControlEntry 3 } + +emsSensorControlSensorCommand OBJECT-TYPE + SYNTAX INTEGER { + noCommandEMS (1), + resetCommandEMS (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return noCommandEMS(1). + + Setting this variable to resetCommandEMS(2) will issue a reset command to the + sensor. Some sensors cannot be manually reset and will not be affected + by this command." + ::= { emsSensorControlEntry 4 } + +-- EMS ALARM DEVICE CONTROL TABLE + +emsAlarmDeviceControlTable OBJECT-TYPE + SYNTAX SEQUENCE OF AlarmDeviceControlEMSEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for control of individual alarm devices. + Note: Some alarm devices are not controllable. The number of + entries is contained in the emsStatusAlarmDeviceCount OID." + ::= { emsAlarmDeviceControl 1 } + +emsAlarmDeviceControlEntry OBJECT-TYPE + SYNTAX AlarmDeviceControlEMSEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The alarm devices to control." + INDEX { emsAlarmDeviceControlDeviceIndex } + ::= { emsAlarmDeviceControlTable 1 } + +AlarmDeviceControlEMSEntry ::= + SEQUENCE { + emsAlarmDeviceControlDeviceIndex INTEGER, + emsAlarmDeviceControlDeviceName DisplayString, + emsAlarmDeviceControlDeviceCommand INTEGER + } + +emsAlarmDeviceControlDeviceIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the alarm device entry." + ::= { emsAlarmDeviceControlEntry 1 } + +emsAlarmDeviceControlDeviceName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the alarm device. + This OID is provided for informational purposes only." + ::= { emsAlarmDeviceControlEntry 2 } + +emsAlarmDeviceControlDeviceCommand OBJECT-TYPE + SYNTAX INTEGER { + alarmDeviceOnEMS (1), + alarmDeviceOffEMS (2), + alarmDeviceNotInstalledEMS (3) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the device state. If + the device is active, the alarmDeviceOnEMS (1) value will be returned. + If the device is inactive, the alarmDeviceOffEMS (2) value will be + returned. If the device is not installed, the + alarmDeviceNotInstalledEMS (3) value will be returned. + + Actions resulting from setting this variable are device-dependent. + + Setting this variable to alarmDeviceOnEMS (1) will turn that device (ex. Beacon) on. + Setting this variable to alarmDeviceOffEMS (2) will turn that device off." + + ::= { emsAlarmDeviceControlEntry 3 } + + +-- EMS CONFIG + +emsConfigName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the device." + ::= { emsConfig 1 } + +emsConfigCheckLogLight OBJECT-TYPE + SYNTAX INTEGER { + lightDisabled (1), + lightOnInformational (2), + lightOnWarning (3), + lightOnSevere (4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The setting of this OID determines the level of event that will + trigger the check-log light on the EMS. This is not available on the EMU2. + + lightDisabled (1) disables the check-log light. + lightOnInformational (2) lights check-log for any event of + informational severity or above. + lightOnWarning (3) lights check-log for any event of + warning severity or above. + lightOnSevere (4) lights check-log for any event of severe severity." + + ::= { emsConfig 2 } + +-- EMS PROBE CONFIG TABLE + +emsProbeConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSProbeConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual probes. The number of + entries is contained in the emsStatusProbeCount OID." + ::= { emsProbeConfig 1 } + +emsProbeConfigEntry OBJECT-TYPE + SYNTAX EMSProbeConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The probes to configure." + INDEX { emsProbeConfigProbeIndex } + ::= { emsProbeConfigTable 1 } + +EMSProbeConfigEntry ::= + SEQUENCE { + emsProbeConfigProbeIndex INTEGER, + emsProbeConfigProbeName DisplayString, + emsProbeConfigProbeHighTempThresh INTEGER, + emsProbeConfigProbeLowTempThresh INTEGER, + emsProbeConfigProbeHighHumidityThresh INTEGER, + emsProbeConfigProbeLowHumidityThresh INTEGER, + emsProbeConfigProbeMaxTempThresh INTEGER, + emsProbeConfigProbeMinTempThresh INTEGER, + emsProbeConfigProbeDeltaTemp INTEGER, + emsProbeConfigProbeMaxHumidityThresh INTEGER, + emsProbeConfigProbeMinHumidityThresh INTEGER, + emsProbeConfigProbeDeltaHumidity INTEGER, + emsProbeConfigProbeSTIncTempVariance INTEGER, + emsProbeConfigProbeSTIncTempTime INTEGER, + emsProbeConfigProbeSTDecTempVariance INTEGER, + emsProbeConfigProbeSTDecTempTime INTEGER, + emsProbeConfigProbeLTIncTempVariance INTEGER, + emsProbeConfigProbeLTIncTempTime INTEGER, + emsProbeConfigProbeLTDecTempVariance INTEGER, + emsProbeConfigProbeLTDecTempTime INTEGER + } + +emsProbeConfigProbeIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the probe entry." + ::= { emsProbeConfigEntry 1 } + +emsProbeConfigProbeName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the probe." + ::= { emsProbeConfigEntry 2 } + +emsProbeConfigProbeHighTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe high temperature threshold. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeConfigEntry 3 } + +emsProbeConfigProbeLowTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe low temperature threshold. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeConfigEntry 4 } + +emsProbeConfigProbeHighHumidityThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe high humidity threshold. + + Values are represented in whole number percentage." + ::= { emsProbeConfigEntry 5 } + +emsProbeConfigProbeLowHumidityThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe low humidity threshold. + + Values are represented in whole number percentage." + ::= { emsProbeConfigEntry 6 } + +emsProbeConfigProbeMaxTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe maximum temperature threshold. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeConfigEntry 7 } + +emsProbeConfigProbeMinTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe minimum temperature threshold. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeConfigEntry 8 } + +emsProbeConfigProbeDeltaTemp OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe delta temperature. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeConfigEntry 9 } + +emsProbeConfigProbeMaxHumidityThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe maximum humidity threshold. + + Values are represented in whole number percentage." + ::= { emsProbeConfigEntry 10 } + +emsProbeConfigProbeMinHumidityThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe minimum humidity threshold. + + Values are represented in whole number percentage." + ::= { emsProbeConfigEntry 11 } + +emsProbeConfigProbeDeltaHumidity OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe delta humidity. + + Values are represented in whole number percentage." + ::= { emsProbeConfigEntry 12 } + +emsProbeConfigProbeSTIncTempVariance OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe short-term increasing temperature variance used for rate of change alarms. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeConfigEntry 13 } + +emsProbeConfigProbeSTIncTempTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe short-term increasing temperature time used for rate of change alarms. + + Values are represented in whole number minutes." + ::= { emsProbeConfigEntry 14 } + +emsProbeConfigProbeSTDecTempVariance OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe short-term decreasing temperature variance used for rate of change alarms. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeConfigEntry 15 } + +emsProbeConfigProbeSTDecTempTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe short-term decreasing temperature time used for rate of change alarms. + + Values are represented in whole number minutes." + ::= { emsProbeConfigEntry 16 } + +emsProbeConfigProbeLTIncTempVariance OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe long-term increasing temperature variance used for rate of change alarms. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeConfigEntry 17 } + +emsProbeConfigProbeLTIncTempTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe long-term increasing temperature time used for rate of change alarms. + + Values are represented in whole number hours." + ::= { emsProbeConfigEntry 18 } + +emsProbeConfigProbeLTDecTempVariance OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe long-term decreasing temperature variance used for rate of change alarms. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeConfigEntry 19 } + +emsProbeConfigProbeLTDecTempTime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Probe long-term decreasing temperature time used for rate of change alarms. + + Values are represented in whole number hours." + ::= { emsProbeConfigEntry 20 } + + +-- EMS INPUT CONTACT CONFIG STATUS TABLE + +emsInputContactConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSInputContactConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual input contacts. The number of + entries is contained in the emsStatusInputContactCount OID." + ::= { emsInputContactConfig 1 } + +emsInputContactConfigEntry OBJECT-TYPE + SYNTAX EMSInputContactConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The input contacts to configure." + INDEX { emsInputContactConfigInputContactIndex } + ::= { emsInputContactConfigTable 1 } + +EMSInputContactConfigEntry ::= + SEQUENCE { + emsInputContactConfigInputContactIndex INTEGER, + emsInputContactConfigInputContactName DisplayString, + emsInputContactConfigInputContactNormalState INTEGER + } + +emsInputContactConfigInputContactIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the input contact entry." + ::= { emsInputContactConfigEntry 1 } + +emsInputContactConfigInputContactName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the input contact." + ::= { emsInputContactConfigEntry 2 } + +emsInputContactConfigInputContactNormalState OBJECT-TYPE + SYNTAX INTEGER { + normallyClosedEMS (1), + normallyOpenEMS (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the normal state of the input contact. If + the normal state is closed, the normallyClosedEMS (1) value will be returned. + If the normal state is closed, the normallyOpenEMS (2) value will be + returned. + + Setting this variable will change the normal state of the input contact" + ::= { emsInputContactConfigEntry 3 } + +-- EMS OUTPUT RELAY CONFIG STATUS TABLE + +emsOutputRelayConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSOutputRelayConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual output relays. The number of + entries is contained in the emsStatusOutputRelayCount OID." + ::= { emsOutputRelayConfig 1 } + +emsOutputRelayConfigEntry OBJECT-TYPE + SYNTAX EMSOutputRelayConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The output relays to configure." + INDEX { emsOutputRelayConfigOutputRelayIndex } + ::= { emsOutputRelayConfigTable 1 } + +EMSOutputRelayConfigEntry ::= + SEQUENCE { + emsOutputRelayConfigOutputRelayIndex INTEGER, + emsOutputRelayConfigOutputRelayName DisplayString, + emsOutputRelayConfigOutputRelayNormalState INTEGER + } + +emsOutputRelayConfigOutputRelayIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the output relay entry." + ::= { emsOutputRelayConfigEntry 1 } + +emsOutputRelayConfigOutputRelayName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the output relay." + ::= { emsOutputRelayConfigEntry 2 } + +emsOutputRelayConfigOutputRelayNormalState OBJECT-TYPE + SYNTAX INTEGER { + normallyClosedEMS (1), + normallyOpenEMS (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the normal state of the output relay. If + the normal state is closed, the normallyClosedEMS (1) value will be returned. + If the normal state is closed, the normallyOpenEMS (2) value will be + returned. + + Setting this variable will change the normal state of the output relay" + ::= { emsOutputRelayConfigEntry 3 } + +-- EMS OUTLET CONFIG TABLE + +emsOutletConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSOutletConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual outlets. The number of + entries is contained in the emsStatusOutletCount OID." + ::= { emsOutletConfig 1 } + +emsOutletConfigEntry OBJECT-TYPE + SYNTAX EMSOutletConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to configure." + INDEX { emsOutletConfigOutletIndex } + ::= { emsOutletConfigTable 1 } + +EMSOutletConfigEntry ::= + SEQUENCE { + emsOutletConfigOutletIndex INTEGER, + emsOutletConfigOutletName DisplayString, + emsOutletConfigOutletNormalState INTEGER + } + +emsOutletConfigOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { emsOutletConfigEntry 1 } + +emsOutletConfigOutletName OBJECT-TYPE + SYNTAX DisplayString ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the outlet." + ::= { emsOutletConfigEntry 2 } + +emsOutletConfigOutletNormalState OBJECT-TYPE + SYNTAX INTEGER { + normallyOnEMS (1), + normallyOffEMS (2) + } + + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the normal state of the outlet. If + the normal state is on, the normallyOnEMS (1) value will be returned. + If the normal state is off, the normallyOffEMS (2) value will be + returned. + + Setting this variable will change the normal state of the outlet" + ::= { emsOutletConfigEntry 3 } + +-- EMS SENSOR CONFIG TABLE + +emsSensorConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSSensorConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual sensors. The number of + entries is contained in the emsStatusSensorCount OID." + ::= { emsSensorConfig 1 } + +emsSensorConfigEntry OBJECT-TYPE + SYNTAX EMSSensorConfigEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The sensors to configure." + INDEX { emsSensorConfigSensorIndex } + ::= { emsSensorConfigTable 1 } + +EMSSensorConfigEntry ::= + SEQUENCE { + emsSensorConfigSensorIndex INTEGER, + emsSensorConfigSensorSystemName DisplayString, + emsSensorConfigSensorUserName DisplayString, + emsSensorConfigSensorNormalState INTEGER, + emsSensorConfigSensorAlarmDelay INTEGER + } + +emsSensorConfigSensorIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the sensor entry." + ::= { emsSensorConfigEntry 1 } + +emsSensorConfigSensorSystemName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system name of the sensor. This describes the hardware system + intent of this sensor." + ::= { emsSensorConfigEntry 2 } + +emsSensorConfigSensorUserName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the sensor as given by the system user." + ::= { emsSensorConfigEntry 3 } + +emsSensorConfigSensorNormalState OBJECT-TYPE + SYNTAX INTEGER { + normallyClosedEMS (1), + normallyOpenEMS (2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Getting this variable will return the normal state of the sensor. If + the normal state is closed, the normallyClosedEMS (1) value will be returned. + If the normal state is closed, the normallyOpenEMS (2) value will be + returned. + + Setting this variable will change the normal state of the sensor. Note: + Only the AUX sensor in the EMS has a configurable Normal State" + ::= { emsSensorConfigEntry 4 } + +emsSensorConfigSensorAlarmDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The delay (in seconds) after a sensor detects an alarm condition before the + condition is reported." + ::= { emsSensorConfigEntry 5 } + +-- EMS STATUS +--- EMS MASTER status + +emsStatusEMSName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the + device. " + ::= { emsStatus 1 } + +emsStatusCommStatus OBJECT-TYPE + SYNTAX INTEGER { + noComm(1), + comm(2), + commLost(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The communication status between the agent + and the device. + + noComm(1), Communication has never been established. + comm(2), Communication has been established. + commLost(3), Communication was established, but was lost." + ::= { emsStatus 2 } + +emsStatusProbeCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of T/H probes (both local and remote) that + is supported by this device." + ::= { emsStatus 3 } + +emsStatusInputContactCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of Input Contacts that + is supported by this device." + ::= { emsStatus 4 } + +emsStatusOutputRelayCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of Output Relays that + is supported by this device." + ::= { emsStatus 5 } + +emsStatusOutletCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of AC Outlets that + is supported by this device." + ::= { emsStatus 6 } + +emsStatusSensorCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of Sensors that + is supported by this device." + ::= { emsStatus 7 } + +emsStatusAlinkAruDeviceCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of remote Aru's supported by this device." + ::= { emsStatus 8 } + +emsStatusAlinkProbeDeviceCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of remote T/H probes supported by this device." + ::= { emsStatus 9 } + +emsStatusAlarmDeviceCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of alarm devices supported by this device." + ::= { emsStatus 10 } + +emsStatusSysTempUnits OBJECT-TYPE + SYNTAX INTEGER { + celsius(1), + fahrenheit(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature scale used to display the temperature + in the system, Celsius(1) or Fahrenheit(2). + This setting is based on the system preferences + configuration in the agent." + ::= { emsStatus 11 } + +emsStatusCheckLogLight OBJECT-TYPE + SYNTAX INTEGER { + lightOff (1), + lightOn (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the check-log light on the device. + For the EMU2, this will always indicate lightOff(1). + + lightOff (1) indicates the light is off (no new log entries). + lightOn (2) indicates the light is on (new log entries present)." + + ::= { emsStatus 12 } + +emsStatusHardwareStatus OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the EMS hardware. This integer should be interpreted + as a bit map, with each bit representing the presence or absence of + a specific hardware error condition. + + 0 indicates there are no error conditions detected in the EMS hardware. + 1 indicates a Current Limit error condition related to the Alink port. + 2 indicates incorrect hardware is plugged into an EMS port. + 3 indicates that both of these error conditions are present." + + ::= { emsStatus 13 } + +-- EMS PROBE STATUS TABLE + +emsProbeStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSProbeStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for access of individual probes. The number of + entries is contained in the emsStatusProbeCount OID." + ::= { emsProbeStatus 1 } + +emsProbeStatusEntry OBJECT-TYPE + SYNTAX EMSProbeStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The probes to access." + INDEX { emsProbeStatusProbeIndex } + ::= { emsProbeStatusTable 1 } + +EMSProbeStatusEntry ::= + SEQUENCE { + emsProbeStatusProbeIndex INTEGER, + emsProbeStatusProbeName DisplayString, + emsProbeStatusProbeTemperature INTEGER, + emsProbeStatusProbeHighTempThresh INTEGER, + emsProbeStatusProbeLowTempThresh INTEGER, + emsProbeStatusProbeHumidity INTEGER, + emsProbeStatusProbeHighHumidityThresh INTEGER, + emsProbeStatusProbeLowHumidityThresh INTEGER, + emsProbeStatusProbeSerialNumber DisplayString, + emsProbeStatusProbeCommStatus INTEGER, + emsProbeStatusProbeAlarmStatus INTEGER, + emsProbeStatusProbeMaxTempThresh INTEGER, + emsProbeStatusProbeMinTempThresh INTEGER, + emsProbeStatusProbeMaxHumidityThresh INTEGER, + emsProbeStatusProbeMinHumidityThresh INTEGER + } + +emsProbeStatusProbeIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the probe entry." + ::= { emsProbeStatusEntry 1 } + +emsProbeStatusProbeName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the probe." + ::= { emsProbeStatusEntry 2 } + +emsProbeStatusProbeTemperature OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe temperature reading. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeStatusEntry 3 } + +emsProbeStatusProbeHighTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe high temperature threshold. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeStatusEntry 4 } + +emsProbeStatusProbeLowTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe low temperature threshold. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeStatusEntry 5 } + +emsProbeStatusProbeHumidity OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe humidity reading. + + Values are represented in whole number percentage." + ::= { emsProbeStatusEntry 6 } + +emsProbeStatusProbeHighHumidityThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe high humidity threshold. + + Values are represented in whole number percentage." + ::= { emsProbeStatusEntry 7 } + +emsProbeStatusProbeLowHumidityThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe low humidity threshold. + + Values are represented in whole number percentage." + ::= { emsProbeStatusEntry 8 } + +emsProbeStatusProbeSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A label indicating the type (Local[L] or Remote[R]) and Number + of the probe. For example, the first local probe would be L1 and + the third remote probe would be R3." + ::= { emsProbeStatusEntry 9 } + +emsProbeStatusProbeCommStatus OBJECT-TYPE + SYNTAX INTEGER { + commsNeverDiscovered(1), + commsEstablished(2), + commsLost(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + " The state of communications to the probe. + commNeverDiscovered(1) indicates there has never been communications with this device. + commsEstablished(2) indicates communication is normal and active with this device. + commsLost(3) indicates communication had been established, but is no longer." + ::= { emsProbeStatusEntry 10 } + +emsProbeStatusProbeAlarmStatus OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The alarm status of the probe. This integer should be interpreted + as a bit map, with each bit representing the presence or absence of + the specific alarm conditions listed below. The bit will be '1' if + the condition is present, and '0' if the condition is not present. + + Bit Hex. Value Description + 1 0x0001 Maximum temperature exceeded. + 2 0x0002 High temperature exceeded. + 3 0x0004 Low temperature exceeded. + 4 0x0008 Minimum temperature exceeded. + 5 0x0010 Short-term increasing temperature rate exceeded. + 6 0x0020 Short-term decreasing temperature rate exceeded. + 7 0x0040 Long-term increasing temperature rate exceeded. + 8 0x0080 Long-term decreasing temperature rate exceeded. + 9 0x0100 Maximum humidity exceeded. + 10 0x0200 High humidity exceeded. + 11 0x0400 Low humidity exceeded. + 12 0x0800 Minimum humidity exceeded." + ::= { emsProbeStatusEntry 11 } + +emsProbeStatusProbeMaxTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe maximum temperature threshold. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeStatusEntry 12 } + +emsProbeStatusProbeMinTempThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe minimum temperature threshold. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the emsStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { emsProbeStatusEntry 13 } + +emsProbeStatusProbeMaxHumidityThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe maximum humidity threshold. + + Values are represented in whole number percentage." + ::= { emsProbeStatusEntry 14 } + +emsProbeStatusProbeMinHumidityThresh OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Probe minimum humidity threshold. + + Values are represented in whole number percentage." + ::= { emsProbeStatusEntry 15 } + + +-- EMS INPUT CONTACT STATUS TABLE + +emsInputContactStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSInputContactStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for access of individual input contacts. The number of + entries is contained in the emsStatusInputContactCount OID." + ::= { emsInputContactStatus 1 } + +emsInputContactStatusEntry OBJECT-TYPE + SYNTAX EMSInputContactStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The input contacts to access." + INDEX { emsInputContactStatusInputContactIndex } + ::= { emsInputContactStatusTable 1 } + +EMSInputContactStatusEntry ::= + SEQUENCE { + emsInputContactStatusInputContactIndex INTEGER, + emsInputContactStatusInputContactName DisplayString, + emsInputContactStatusInputContactState INTEGER, + emsInputContactStatusInputContactNormalState INTEGER + } + +emsInputContactStatusInputContactIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the input contact entry." + ::= { emsInputContactStatusEntry 1 } + +emsInputContactStatusInputContactName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the input contact." + ::= { emsInputContactStatusEntry 2 } + +emsInputContactStatusInputContactState OBJECT-TYPE + SYNTAX INTEGER { + contactClosedEMS (1), + contactOpenEMS (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the state of the input contact. If + the input contact is closed, the contactClosedEMS (1) value will be returned. + If the input contact state is open, the contactOpenEMS (2) value will be + returned. " + + ::= { emsInputContactStatusEntry 3 } + +emsInputContactStatusInputContactNormalState OBJECT-TYPE + SYNTAX INTEGER { + normallyClosedEMS (1), + normallyOpenEMS (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the normal state of the input contact. If + the normal state is closed, the normallyClosedEMS (1) value will be returned. + If the normal state is open, the normallyOpenEMS (2) value will be + returned. " + + ::= { emsInputContactStatusEntry 4 } + + +-- EMS OUTPUT RELAY STATUS TABLE + +emsOutputRelayStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSOutputRelayStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for access of individual output relays. The number of + entries is contained in the emsStatusOutputRelayCount OID." + ::= { emsOutputRelayStatus 1 } + +emsOutputRelayStatusEntry OBJECT-TYPE + SYNTAX EMSOutputRelayStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The output relays to access." + INDEX { emsOutputRelayStatusOutputRelayIndex } + ::= { emsOutputRelayStatusTable 1 } + +EMSOutputRelayStatusEntry ::= + SEQUENCE { + emsOutputRelayStatusOutputRelayIndex INTEGER, + emsOutputRelayStatusOutputRelayName DisplayString, + emsOutputRelayStatusOutputRelayState INTEGER, + emsOutputRelayStatusOutputRelayNormalState INTEGER + } + +emsOutputRelayStatusOutputRelayIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the output relay entry." + ::= { emsOutputRelayStatusEntry 1 } + +emsOutputRelayStatusOutputRelayName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the output relay." + ::= { emsOutputRelayStatusEntry 2 } + +emsOutputRelayStatusOutputRelayState OBJECT-TYPE + SYNTAX INTEGER { + relayClosedEMS (1), + relayOpenEMS (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the state of the output relay. If + the output relay is closed, the relayClosedEMS (1) value will be returned. + If the output relay is open, the relayOpenEMS (2) value will be + returned. " + + ::= { emsOutputRelayStatusEntry 3 } + +emsOutputRelayStatusOutputRelayNormalState OBJECT-TYPE + SYNTAX INTEGER { + normallyClosedEMS (1), + normallyOpenEMS (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the normal state of the output relay. If + the normal state is closed, the normallyClosedEMS (1) value will be returned. + If the normal state is open, the normallyOpenEMS (2) value will be + returned. " + + ::= { emsOutputRelayStatusEntry 4 } + +-- EMS OUTLET STATUS TABLE + +emsOutletStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSOutletStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for access of individual outlets. The number of + entries is contained in the emsStatusOutletCount OID." + ::= { emsOutletStatus 1 } + +emsOutletStatusEntry OBJECT-TYPE + SYNTAX EMSOutletStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The outlets to access." + INDEX { emsOutletStatusOutletIndex } + ::= { emsOutletStatusTable 1 } + +EMSOutletStatusEntry ::= + SEQUENCE { + emsOutletStatusOutletIndex INTEGER, + emsOutletStatusOutletName DisplayString, + emsOutletStatusOutletState INTEGER, + emsOutletStatusOutletNormalState INTEGER + } + +emsOutletStatusOutletIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the outlet entry." + ::= { emsOutletStatusEntry 1 } + +emsOutletStatusOutletName OBJECT-TYPE + SYNTAX DisplayString ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the outlet." + ::= { emsOutletStatusEntry 2 } + +emsOutletStatusOutletState OBJECT-TYPE + SYNTAX INTEGER { + outletOnEMS (1), + outletOffEMS (2) + } + + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the state of the outlet. If + the outlet is on, the outletOnEMS (1) value will be returned. + If the outlet is off, the outletOffEMS (2) value will be + returned. " + + ::= { emsOutletStatusEntry 3 } + +emsOutletStatusOutletNormalState OBJECT-TYPE + SYNTAX INTEGER { + normallyOnEMS (1), + normallyOffEMS (2) + } + + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the normal state of the outlet. If + the normal state is on, the normallyOnEMS (1) value will be returned. + If the normal state is off, the normallyOffEMS (2) value will be + returned. " + + ::= { emsOutletStatusEntry 4 } + +-- EMS ALARM DEVICE STATUS TABLE + +emsAlarmDeviceStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSAlarmDeviceStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for access of individual alarm devices. The number of + entries is contained in the emsStatusAlarmDeviceCount OID." + ::= { emsAlarmDeviceStatus 1 } + +emsAlarmDeviceStatusEntry OBJECT-TYPE + SYNTAX EMSAlarmDeviceStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The alarm devices to access." + INDEX { emsAlarmDeviceStatusDeviceIndex } + ::= { emsAlarmDeviceStatusTable 1 } + +EMSAlarmDeviceStatusEntry ::= + SEQUENCE { + emsAlarmDeviceStatusDeviceIndex INTEGER, + emsAlarmDeviceStatusDeviceName DisplayString, + emsAlarmDeviceStatusDeviceState INTEGER + } + +emsAlarmDeviceStatusDeviceIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the alarm device entry." + ::= { emsAlarmDeviceStatusEntry 1 } + +emsAlarmDeviceStatusDeviceName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the alarm device. + This OID is provided for informational purposes only." + ::= { emsAlarmDeviceStatusEntry 2 } + +emsAlarmDeviceStatusDeviceState OBJECT-TYPE + SYNTAX INTEGER { + alarmDeviceOnEMS (1), + alarmDeviceOffEMS (2), + alarmDeviceNotInstalledEMS (3) + } + + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the device state. If + the device is active, the alarmDeviceOnEMS (1) value will be returned. + If the device is inactive, the alarmDeviceOffEMS (2) value will be + returned. If the device is not installed, the + alarmDeviceNotInstalledEMS (3) value will be returned." + + ::= { emsAlarmDeviceStatusEntry 3 } + + +-- EMS SENSOR STATUS TABLE + +emsSensorStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF EMSSensorStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for access of individual sensors. The number of + entries is contained in the emsStatusSensorCount OID." + ::= { emsSensorStatus 1 } + +emsSensorStatusEntry OBJECT-TYPE + SYNTAX EMSSensorStatusEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The sensors to access." + INDEX { emsSensorStatusSensorIndex } + ::= { emsSensorStatusTable 1 } + +EMSSensorStatusEntry ::= + SEQUENCE { + emsSensorStatusSensorIndex INTEGER, + emsSensorStatusSensorSystemName DisplayString, + emsSensorStatusSensorName DisplayString, + emsSensorStatusSensorState INTEGER, + emsSensorStatusSensorNormalState INTEGER, + emsSensorStatusSensorAlarmDelay INTEGER + } + +emsSensorStatusSensorIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the sensor entry." + ::= { emsSensorStatusEntry 1 } + +emsSensorStatusSensorSystemName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system name of the sensor. This describes the hardware system + intent of this sensor." + ::= { emsSensorStatusEntry 2 } + +emsSensorStatusSensorName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the sensor as given by the system user." + ::= { emsSensorStatusEntry 3 } + +emsSensorStatusSensorState OBJECT-TYPE + SYNTAX INTEGER { + sensorFaultedEMS (1), + sensorOKEMS (2), + sensorNotInstalledEMS (3) + } + + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the sensor state. If the sensor is faulted, + the sensorFaultedEMS (1) value will be returned. + If the sensor is not faulted, the sensorOKEMS (2) value will be + returned. If the sensor is not installed, the sensorNotInstalledEMS (3) + value will be returned." + ::= { emsSensorStatusEntry 4 } + +emsSensorStatusSensorNormalState OBJECT-TYPE + SYNTAX INTEGER { + normallyClosedEMS (1), + normallyOpenEMS (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "Getting this variable will return the normal state of the sensor. If + the normal state is closed, the normallyClosedEMS (1) value will be returned. + If the normal state is closed, the normallyOpenEMS (2) value will be + returned." + ::= { emsSensorStatusEntry 5 } + +emsSensorStatusSensorAlarmDelay OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The delay (in seconds) after a sensor detects an alarm condition before the + condition is reported." + ::= { emsSensorStatusEntry 6 } + + + +-- airFM AIR CONDITIONER IDENT + +airFMIdentName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the + device. " + ::= { airFMIdent 1 } + +airFMIdentTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the airFMIdentTable. " + ::= { airFMIdent 2 } + +airFMIdentTable OBJECT-TYPE + SYNTAX SEQUENCE OF AirFMIdentTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting identification information + from each module in the system. " + ::= { airFMIdent 3 } + +airFMIdentTableEntry OBJECT-TYPE + SYNTAX AirFMIdentTableEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The module to get information from." + INDEX { airFMIdentModuleIndex } + ::= { airFMIdentTable 1 } + +AirFMIdentTableEntry ::= + SEQUENCE { + airFMIdentModuleIndex INTEGER, + airFMIdentModuleModelNumber DisplayString, + airFMIdentModuleDateOfMfg DisplayString, + airFMIdentModuleSerialNumber DisplayString, + airFMIdentModuleFirmwareRev DisplayString, + airFMIdentModuleHardwareRev DisplayString + } + +airFMIdentModuleIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the module information." + ::= { airFMIdentTableEntry 1 } + +airFMIdentModuleModelNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the + model number. " + ::= { airFMIdentTableEntry 2 } + +airFMIdentModuleDateOfMfg OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the + manufacture date. " + ::= { airFMIdentTableEntry 3 } + +airFMIdentModuleSerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the + unit serial number. " + ::= { airFMIdentTableEntry 4 } + +airFMIdentModuleFirmwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the + firmware revision. " + ::= { airFMIdentTableEntry 5 } + +airFMIdentModuleHardwareRev OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the + hardware revision. " + ::= { airFMIdentTableEntry 6 } + +-- airFM AIR CONDITIONER STATUS + +airFMStatusSystemOn OBJECT-TYPE + SYNTAX INTEGER { + statusOn (1), + statusOff (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The operating state of the system. " + ::= { airFMStatus 1 } + +airFMStatusSystemAverageRetTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system average return air + temperature in tenths of degrees Celsius. " + ::= { airFMStatus 2 } + +airFMStatusSystemAverageRetTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system average return air + temperature in tenths of degrees Fahrenheit. " + ::= { airFMStatus 3 } + +airFMStatusSystemAverageRetHum OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system average return air + humidity. " + ::= { airFMStatus 4 } + +airFMStatusSystemActionTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system action air + temperature in tenths of degrees Celsius. " + ::= { airFMStatus 5 } + +airFMStatusSystemActionTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system action air + temperature in tenths of degrees Fahrenheit. " + ::= { airFMStatus 6 } + +airFMStatusSystemActionHum OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system action air humidity. " + ::= { airFMStatus 7 } + +airFMStatusSystemRemoteHighTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system remote high air + temperature in tenths of degrees Celsius. " + ::= { airFMStatus 8 } + +airFMStatusSystemRemoteHighTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system remote high air + temperature in tenths of degrees Fahrenheit. " + ::= { airFMStatus 9 } + +airFMStatusSystemRemoteAvgTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system remote average air + temperature in tenths of degrees Celsius. " + ::= { airFMStatus 10 } + +airFMStatusSystemRemoteAvgTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system remote average air + temperature in tenths of degrees Fahrenheit. " + ::= { airFMStatus 11 } + +airFMStatusSystemRemoteAvgHum OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system remote average air + humidity. " + ::= { airFMStatus 12 } + +airFMStatusSystemRemoteLowTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system remote low air + temperature in tenths of degrees Celsius. " + ::= { airFMStatus 13 } + +airFMStatusSystemRemoteLowTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The system remote low air + temperature in tenths of degrees Fahrenheit. " + ::= { airFMStatus 14 } + +airFMStatusSystemCoolingEnabled OBJECT-TYPE + SYNTAX INTEGER { + enabledYes (1), + enabledNo (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The state of the system cooling + function enable. " + ::= { airFMStatus 15 } + +airFMStatusSystemReheatingEnabled OBJECT-TYPE + SYNTAX INTEGER { + enabledYes (1), + enabledNo (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The state of the system reheating + function enable. " + ::= { airFMStatus 16 } + +airFMStatusSystemHumidifyEnabled OBJECT-TYPE + SYNTAX INTEGER { + enabledYes (1), + enabledNo (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The state of the system humidify + function enable. " + ::= { airFMStatus 17 } + +airFMStatusSystemDehumidifyEnabled OBJECT-TYPE + SYNTAX INTEGER { + enabledYes (1), + enabledNo (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The state of the system dehumidify + function enable. " + ::= { airFMStatus 18 } + +airFMStatusModuleTableSize OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of entries in the airFMStatusModuleTable. " + ::= { airFMStatus 19 } + +airFMStatusModuleTable OBJECT-TYPE + SYNTAX SEQUENCE OF AirFMStatusModuleEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for getting information from each module + in the system. " + ::= { airFMStatus 20 } + +airFMStatusModuleEntry OBJECT-TYPE + SYNTAX AirFMStatusModuleEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The module to get status from." + INDEX { airFMStatusModuleIndex } + ::= { airFMStatusModuleTable 1 } + +AirFMStatusModuleEntry ::= + SEQUENCE { + airFMStatusModuleIndex INTEGER, + airFMStatusModuleOutputCapacity INTEGER, + airFMStatusModuleSupplyTempC INTEGER, + airFMStatusModuleSupplyTempF INTEGER, + airFMStatusModuleSupplyHum INTEGER, + airFMStatusModuleReturnTempC INTEGER, + airFMStatusModuleReturnTempF INTEGER, + airFMStatusModuleReturnHum INTEGER + } + +airFMStatusModuleIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index of the module information." + ::= { airFMStatusModuleEntry 1 } + +airFMStatusModuleOutputCapacity OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The module output capacity in kilowatts." + ::= { airFMStatusModuleEntry 2 } + +airFMStatusModuleSupplyTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The module supply air temperature in + tenths of degrees Celsius. " + ::= { airFMStatusModuleEntry 3 } + +airFMStatusModuleSupplyTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The module supply air temperature in + tenths of degrees Fahrenheit. " + ::= { airFMStatusModuleEntry 4 } + +airFMStatusModuleSupplyHum OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The module supply air humidity. " + ::= { airFMStatusModuleEntry 5 } + +airFMStatusModuleReturnTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The module return air temperature in + tenths of degrees Celsius. " + ::= { airFMStatusModuleEntry 6 } + +airFMStatusModuleReturnTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The module return air temperature in + tenths of degrees Fahrenheit. " + ::= { airFMStatusModuleEntry 7 } + +airFMStatusModuleReturnHum OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The module return air humidity. " + ::= { airFMStatusModuleEntry 8 } + +-- airFM AIR CONDITIONER GROUP DATA + +airFMGroupSysStatus OBJECT-TYPE + SYNTAX INTEGER { + statusOnLine (1), + statusIdle (2), + statusLoadShare (3), + statusOffLine (4), + statusFailed (5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of this system within the group. " + ::= { airFMGroup 1 } + +airFMGroupSysRuntime OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of hours the system has been running. " + ::= { airFMGroup 2 } + +airFMGroupSysRole OBJECT-TYPE + SYNTAX INTEGER { + rolePrimary (1), + roleBackup (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The role of this system within the group. " + ::= { airFMGroup 3 } + +-- airPA Portable Air Conditioner Ident + +airPAIdentName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the device name. " + ::= { airPAIdent 1 } + +airPAModelNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the device model number. " + ::= { airPAIdent 2 } + +airPADateOfManufacture OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying when the device was produced. " + ::= { airPAIdent 3 } + +airPASerialNumber OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the device serial number. " + ::= { airPAIdent 4 } + +airPAFirmwareRevision OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the device firmware revision. " + ::= { airPAIdent 5 } + +airPAHardwareRevision OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the device hardware revision. " + ::= { airPAIdent 6 } + +-- airPA Portable Air Conditioner Status + +airPASystemPower OBJECT-TYPE + SYNTAX INTEGER { + powerON (1), + powerOFF (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The status of the unit's system power setting. + + ON(1) The system power is turned on. + OFF(2) The system power is turned off. " + ::= { airPAStatus 1 } + +airPAOperatingMode OBJECT-TYPE + SYNTAX INTEGER { + modeOFF (1), + modeVENTING (2), + modeCOOLING (3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current operating mode of the unit. + + OFF(1) The system is off. + VENTING(2) The system's venting function is active. + COOLING(3) The system's cooling function is active. " + ::= { airPAStatus 2 } + +airPASetpointTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature setpoint in Fahrenheit to which the unit is controlling. " + ::= { airPAStatus 3 } + +airPASetpointTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature setpoint in Celsius to which the unity is controlling. " + ::= { airPAStatus 4 } + +airPABlowerSpeed OBJECT-TYPE + SYNTAX INTEGER { + speedLOW (1), + speedHIGH (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The unit's blower speed setting. + + LOW(1) The blower speed is low. + HIGH(2) The blower speed is high. " + ::= { airPAStatus 5 } + +airPACompressor OBJECT-TYPE + SYNTAX INTEGER { + statusON (1), + statusOFF (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The unit's compressor status. + + ON(1) The compressor is turned on. + OFF(2) The compressor is turned off. " + ::= { airPAStatus 6 } + +airPACondenserFan OBJECT-TYPE + SYNTAX INTEGER { + statusON (1), + statusOFF (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The unit's condenser fan status. + + ON(1) The condenser fan is turned on. + OFF(2) The condenser fan is turned off. " + ::= { airPAStatus 7 } + +airPACondensatePump OBJECT-TYPE + SYNTAX INTEGER { + statusON (1), + statusOFF (2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The unit's condensate pump status. + + ON(1) The condensate pump is turned on. + OFF(2) The condensate pump is turned off. " + ::= { airPAStatus 8 } + +airPASupplyTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The supply temperature in degrees Fahrenheit. " + ::= { airPAStatus 9 } + +airPASupplyTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The supply temperature in degrees Celsius. " + ::= { airPAStatus 10 } + +airPAReturnTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The return temperature in degrees Fahrenheit. " + ::= { airPAStatus 11 } + +airPAReturnTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The return temperature in degrees Celsius. " + ::= { airPAStatus 12 } + +airPARemoteTempF OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The remote temperature in degrees Fahrenheit. " + ::= { airPAStatus 13 } + +airPARemoteTempC OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The remote temperature in degrees Celsius. " + ::= { airPAStatus 14 } + +airPARemoteHumidity OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The remote humidity. " + ::= { airPAStatus 15 } + +-- RACK AIR REMOVAL UNIT IDENT + +rARUIdentTable OBJECT-TYPE + SYNTAX SEQUENCE OF IdentRARUEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for query of the individual devices. + The number of entries is contained in the + rARUStatusAruDeviceCount OID." + ::= { rARUIdent 1 } + +rARUIdentEntry OBJECT-TYPE + SYNTAX IdentRARUEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The device to query." + INDEX { rARUIdentIndex} + ::= { rARUIdentTable 1 } + +IdentRARUEntry ::= + SEQUENCE { + rARUIdentIndex INTEGER, + rARUIdentName DisplayString + } + +rARUIdentIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the device entry." + ::= { rARUIdentEntry 1 } + +rARUIdentName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A character string identifying the + device. " + ::= { rARUIdentEntry 2 } + + +-- RACK AIR REMOVAL UNIT CONFIGURATION + +rARUConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF ConfigRARUEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for configuration of individual ARUs. The number of + entries is contained in the rARUStatusAruDeviceCount OID." + ::= { rARUConfig 1 } + +rARUConfigEntry OBJECT-TYPE + SYNTAX ConfigRARUEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The ARUs to configure." + INDEX { rARUConfigAruIndex } + ::= { rARUConfigTable 1 } + +ConfigRARUEntry ::= + SEQUENCE { + rARUConfigAruIndex INTEGER, + rARUConfigAruName DisplayString, + rARUConfigAruRemoteSetpoint INTEGER, + rARUConfigAruTempOvrdEnableDisable INTEGER, + rARUConfigAruTempOvrdSetpoint INTEGER + } + +rARUConfigAruIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the device entry." + ::= { rARUConfigEntry 1 } + +rARUConfigAruName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The name of the ARU." + ::= { rARUConfigEntry 2 } + +rARUConfigAruRemoteSetpoint OBJECT-TYPE + SYNTAX INTEGER { + aruOff (1), + aru85F-29C (2), + aru90F-32C (3), + aru95F-35C (4), + aru100F-38C (5), + aru7kW (6), + aru5kW (7), + aru3kW (8), + aru2kW (9) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This OID is the Remote setpoint of the ARU. + NOTE: -1 will be returned if the ARU is not communicating." + + ::= { rARUConfigEntry 3 } + +rARUConfigAruTempOvrdEnableDisable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This OID is used to enable/disable the remote temperature override setting of the ARU. + + If this OID is set to 1, the remote setting for temperature override is disabled. + If this OID is set to 2, the remote setting for temperature override is enabled." + ::= { rARUConfigEntry 4 } + +rARUConfigAruTempOvrdSetpoint OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "This OID is the Temperature Override setpoint of the ARU. + NOTE: -1 will be returned if the ARU is not communicating." + + ::= { rARUConfigEntry 5 } + +-- RACK AIR REMOVAL UNIT STATUS + +rARUStatusAruDeviceCount OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of ARUs accessible from this IP." + ::= { rARUStatus 1 } + +rARUStatusSysTempUnits OBJECT-TYPE + SYNTAX INTEGER { + celsius(1), + fahrenheit(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The temperature scale used to display the temperature + in the system, Celsius(1) or Fahrenheit(2). + This setting is based on the system preferences + configuration in the agent." + ::= { rARUStatus 2 } + +rARUStatusTable OBJECT-TYPE + SYNTAX SEQUENCE OF StatusRARUEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Allows for access of individual ARUs. The number of + entries is contained in the rARUStatusAruDeviceCount OID." + ::= { rARUStatus 3 } + +rARUStatusEntry OBJECT-TYPE + SYNTAX StatusRARUEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The ARUs to access." + INDEX { rARUStatusAruIndex } + ::= { rARUStatusTable 1 } + +StatusRARUEntry ::= + SEQUENCE { + rARUStatusAruIndex INTEGER, + rARUStatusAruName DisplayString, + rARUStatusAruRemoteSetpoint INTEGER, + rARUStatusAruManualSetpoint INTEGER, + rARUStatusAruTemp1 INTEGER, + rARUStatusAruTemp2 INTEGER, + rARUStatusAruTemp3 INTEGER, + rARUStatusAruTempOvrdEnableDisable INTEGER, + rARUStatusAruTempOvrdSetpoint INTEGER, + rARUStatusAruAlarmState DisplayString, + rARUStatusAruCommStatus INTEGER + } + +rARUStatusAruIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index to the ARU entry." + ::= { rARUStatusEntry 1 } + +rARUStatusAruName OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The name of the ARU." + ::= { rARUStatusEntry 2 } + +rARUStatusAruRemoteSetpoint OBJECT-TYPE + SYNTAX INTEGER { + aruOff (1), + aru85F-29C (2), + aru90F-32C (3), + aru95F-35C (4), + aru100F-38C (5), + aru7kW (6), + aru5kW (7), + aru3kW (8), + aru2kW (9) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "ARU remote setpoint temperature setting. + + NOTE: -1 will be returned if the ARU is not communicating. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the rARUStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { rARUStatusEntry 3 } + +rARUStatusAruManualSetpoint OBJECT-TYPE + SYNTAX INTEGER { + aruOff (1), + aru85F-29C (2), + aru90F-32C (3), + aru95F-35C (4), + aru100F-38C (5), + aru7kW (6), + aru5kW (7), + aru3kW (8), + aru2kW (9), + aruRem (10) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "ARU manual setpoint temperature setting. + + NOTE: -1 will be returned if the ARU is not communicating. + + Values are represented in whole number degrees. + If the manual setpoint is set to Remote, this OID will return 0. + Units are displayed in the scale shown in + the rARUStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { rARUStatusEntry 4 } + +rARUStatusAruTemp1 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "ARU temperature probe #1 reading. + + NOTE: -1 will be returned if the ARU is not communicating. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the rARUStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { rARUStatusEntry 5 } + +rARUStatusAruTemp2 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "ARU temperature probe #2 reading. + + NOTE: -1 will be returned if the ARU is not communicating. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the rARUStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { rARUStatusEntry 6 } + +rARUStatusAruTemp3 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "ARU temperature probe #3 reading. + + NOTE: -1 will be returned if the ARU is not communicating. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the rARUStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { rARUStatusEntry 7 } + +rARUStatusAruTempOvrdEnableDisable OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + enabled(2) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "This OID indicates whether the ARU remote temperature override is enabled or disabled. + If this OID is a 1, the remote setting for temperature override is disabled. + If this OID is a 2, the remote setting for temperature override is enabled." + ::= { rARUStatusEntry 8 } + +rARUStatusAruTempOvrdSetpoint OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "ARU remote temperature override setpoint setting. + + NOTE: -1 will be returned if the ARU is not communicating. + + Values are represented in whole number degrees. + Units are displayed in the scale shown in + the rARUStatusSysTempUnits OID (Celsius or Fahrenheit)." + ::= { rARUStatusEntry 9 } + +rARUStatusAruAlarmState OBJECT-TYPE + SYNTAX DisplayString + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An ASCII string containing the 8 flags representing + the current alarm state of the ARU. If the state of + the ARU is unknown, this variable is set to ‘UNKNOWN’. + + The flags are numbered 1 to 8, read from left to + right. The flags are defined as follows: + + Flag 1: Fan Fail 1 + Flag 2: Fan Fail 2 + Flag 3: Fan Fail 3 + Flag 4: Smoke + + Flag 5: High Temp (Out of Thermal Control) + Flag 6: Over Temp (Exhaust Temp. Exceeds Override Setpoint) + Flag 7: Reserved + Flag 8: Reserved" + ::= { rARUStatusEntry 10 } + +rARUStatusAruCommStatus OBJECT-TYPE + SYNTAX INTEGER { + commsNeverDiscovered(1), + commsEstablished(2), + commsLost(3) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The state of communications to the device. + commNeverDiscovered(1) indicates there has never been communications with this device. + commsEstablished(2) indicates communication is normal and active with this device. + commsLost(3) indicates communication had been established, but is no device." + ::= { rARUStatusEntry 11 } + +-- Traps +-- Annotations are provided for Novell's NMS product +-- +-- Each trap has at least one variable (mtrapargsString) which always appears +-- as the last variable in the list. This variable contains either a static +-- or dynamically-constructed string which provides an enhanced description of +-- the trap's purpose and any pertinent information about the trap. + +communicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Communication to the UPS has been lost. Steps + to reestablish communication are in progress." + --#TYPE "APC UPS: Communication lost" + --#SUMMARY "Communication lost between the agent and the UPS." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 1 + +upsOverload TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: The UPS has sensed a load greater than 100 percent + of its rated capacity." + --#TYPE "APC UPS: Overload" + --#SUMMARY "The UPS has sensed a load greater than 100 percent of its rated capacity." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 2 + +upsDiagnosticsFailed TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: The UPS failed its internal diagnostic self-test." + --#TYPE "APC UPS: Failed self-test" + --#SUMMARY "The UPS has failed its internal self-test." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 3 + +upsDischarged TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: The UPS batteries are discharged; if utility power fails + an immediate low battery condition will exist. Sufficient runtime + for necessary action cannot be guaranteed." + --#TYPE "APC UPS: batteries are discharged" + --#SUMMARY "The UPS batteries are discharged." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 4 + +upsOnBattery TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The UPS has switched to battery backup power." + --#TYPE "APC UPS: On battery" + --#SUMMARY "The UPS has switched to battery backup power." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 5 + +smartBoostOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The UPS has enabled SmartBoost(TM)." + --#TYPE "APC UPS: SmartBoost(TM)" + --#SUMMARY "The UPS has enabled SmartBoost(TM); low incoming line voltage." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 6 + +lowBattery TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: The UPS batteries are low and will soon be exhausted. + If utility power is not restored the UPS will put itself + to 'sleep' and immediately cut power to the load." + --#TYPE "APC UPS: Low battery" + --#SUMMARY "The UPS system's batteries are low and will soon be exhausted." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 7 + +communicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communication with the UPS has been established." + --#TYPE "APC UPS: Communication established" + --#SUMMARY "UPS communication has been established." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 8 + +powerRestored TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Utility power has been restored." + --#TYPE "APC UPS: Utility power restored" + --#SUMMARY "Returned from battery backup power; utility power restored." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 9 + +upsDiagnosticsPassed TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The UPS passed its internal self-test." + --#TYPE "APC UPS: Passed self-test" + --#SUMMARY "The UPS passed internal self-test." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 10 + +returnFromLowBattery TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The UPS has returned from a low battery + condition." + --#TYPE "APC UPS: Returned from Low-Battery condition" + --#SUMMARY "The UPS has returned from a Low-Battery condition." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 11 + +upsTurnedOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The UPS has been turned 'off' by the management station." + --#TYPE "APC UPS: Turned off" + --#SUMMARY "The UPS has been switched off by a management station." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE NONOPERATIONAL + ::= 12 + +upsSleeping TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The UPS is entering 'sleep' mode. Power + to the load will be cut off." + --#TYPE "APC UPS: Entered sleep mode" + --#SUMMARY "The UPS entered sleep mode. Power to the load will be cut off." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE NONOPERATIONAL + ::= 13 + +upsWokeUp TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATION: The UPS has returned from 'sleep' mode. Power + to the load has been restored." + --#TYPE "APC UPS: Wake up" + --#SUMMARY "The UPS has returned from sleep mode. Power to the load has been restored." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 14 + +upsRebootStarted TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The UPS has started its reboot sequence. + The UPS will reboot itself at this time." + --#TYPE "APC UPS: Starting reboot" + --#SUMMARY "The UPS has started its reboot sequence." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE NONOPERATIONAL + ::= 15 + +upsDipSwitchChanged TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The dip switch settings on the UPS have been + changed, possibly altering UPS performance." + --#TYPE "APC UPS: DIP switch altered" + --#SUMMARY "The DIP switch settings on the UPS have been changed." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 16 + +upsBatteryNeedsReplacement TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: The batteries of the UPS need immediate replacement." + --#TYPE "APC UPS: UPS batteries need replacement" + --#SUMMARY "The UPS batteries require immediate replacement." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 17 + + +-- the Environmental Monitor traps + +contactFault TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: One of the contacts on the Environmental Monitor has + changed from its default position. The first variable is + the contact number that is faulted." + --#TYPE "APC Environment: Contact fault" + --#SUMMARY "An Environment contact closure has faulted." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 18 + +contactFaultResolved TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A fault on one of the Environmental Monitor contacts + has been resolved. The first variable is + the contact number that has been resolved." + --#TYPE "APC Environment: Contact fault cleared." + --#SUMMARY "A Environment contact closure has returned to it's default state." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 19 + +-- the Matrix-UPS traps + +hardwareFailureBypass TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: UPS on bypass due to internal fault" + --#TYPE "APC UPS: On bypass due to internal fault" + --#SUMMARY "The UPS is on bypass due to an internal fault." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 20 + +softwareBypass TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: UPS on bypass - user set via software or panel" + --#TYPE "APC UPS: On bypass by user via software or panel" + --#SUMMARY "UPS put on bypass by user via software or front UPS panel." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 21 + +switchedBypass TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: UPS on bypass - initiated by user" + --#TYPE "APC UPS: On bypass initiated by user" + --#SUMMARY "UPS put on bypass by user." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 22 + +returnFromBypass TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: UPS has returned from bypass" + --#TYPE "APC UPS: UPS has returned from bypass" + --#SUMMARY "The UPS has returned from bypass mode." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 23 + +bypassPowerSupplyFailure TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Base module bypass power supply needs repair" + --#TYPE "APC UPS: Base module bypass power supply needs repair" + --#SUMMARY "The base module bypass power supply needs repair." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE NONOPERATIONAL + ::= 24 + +baseFanFailure TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Base module fan needs repair" + --#TYPE "APC UPS: Base module fan needs repair" + --#SUMMARY "The base module fan needs repair." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE NONOPERATIONAL + ::= 25 + +batteryPackCommLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Check installation of external battery packs signal cable" + --#TYPE "APC UPS: Communication lost with battery packs" + --#SUMMARY "Communication lost with external battery packs, check battery signal cable." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 26 + +batteryPackCommEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: UPS is communicating with the external battery packs." + --#TYPE "APC UPS: Communication established with battery packs" + --#SUMMARY "Communication established with external battery packs." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 27 + +calibrationStart TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A battery calibration test has been initiated on the UPS." + --#TYPE "APC UPS: Calibration initiated" + --#SUMMARY "A battery run time calibration test has been initiated." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 28 + +-- Misc. Traps + +restartAgent TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Agent restarting as commanded by manager." + --#TYPE "APC SNMP Agent: Agent restarting" + --#SUMMARY "Agent restarting as commanded by manager." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 29 + +upsTurnedOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A UPS is turned on." + --#TYPE "APC UPS: A UPS is turned on." + --#SUMMARY " A UPS is turned on." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 30 + +smartAvrReducing TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The UPS is reducing the line voltage via SmartTrim(TM)." + --#TYPE "APC UPS: SmartTrim(TM) reducing" + --#SUMMARY "The UPS has enabled SmartTrim(TM) voltage reduction." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 31 + +codeAuthenticationDone TRAP-TYPE + ENTERPRISE apc + VARIABLES { mconfigTFTPServerIP, newCodeAuthentViaTFTP } + DESCRIPTION + "INFORMATIONAL: Authentication on agent code image is done." + --#TYPE "APC CODE: Authentication on agent code image is done." + --#SUMMARY "Authentication on agent code image is done." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 32 + +upsOverloadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The overload condition has been cleared." + --#TYPE "APC UPS: Overload cleared." + --#SUMMARY "The overload condition has been cleared. ." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 33 + +smartBoostOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The UPS has returned from SmartBoost(TM)." + --#TYPE "APC UPS: SmartBoost(TM) off." + --#SUMMARY "The UPS has returned from SmartBoost(TM)." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 34 + +smartAvrReducingOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The UPS has returned from SmartTrim(TM)." + --#TYPE "APC UPS: SmartTrim(TM) reducing off" + --#SUMMARY "The UPS has returned from SmartTrim(TM) voltage reduction." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 35 + +upsBatteryReplaced TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A bad battery fault has been cleared." + --#TYPE "APC UPS: Bad battery replaced" + --#SUMMARY "The UPS has returned from a bad battery fault." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 36 + +calibrationEnd TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The UPS has finished calibrating." + --#TYPE "APC UPS: Calibration end" + --#SUMMARY "The UPS has finished calibrating" + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 37 + +dischargeCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A UPS discharge condition has been cleared." + --#TYPE "APC UPS: Discharge cleared." + --#SUMMARY "The UPS discharge condition has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 38 + +gracefullShutdown TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A graceful shutdown has been initiated." + --#TYPE "APC UPS: A graceful shutdown has been initiated." + --#SUMMARY "A graceful shutdown has been initiated." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 39 + + +outletOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUOutletControlIndex } + DESCRIPTION + "WARNING: The specified PDU outlet has turned on. + If sPDUOutletControlIndex equals zero, then all outlets have + turned on." + --#TYPE "APC PDU: Outlet has been turned on." + --#SUMMARY "Outlet has been turned on" + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 41 + + +outletOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUOutletControlIndex } + DESCRIPTION + "WARNING: The specified PDU outlet has turned off. + If sPDUOutletControlIndex equals zero, then all outlets + have turned off." + --#TYPE "APC PDU: Outlet has turned off." + --#SUMMARY "Outlet has turned off." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 42 + +outletReboot TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUOutletControlIndex } + DESCRIPTION + "WARNING: The specified PDU outlet has rebooted. + If sPDUOutletControlIndex equals zero, then all outlets + have rebooted." + --#TYPE "APC PDU: Outlet has rebooted." + --#SUMMARY "Outlet has rebooted." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 43 + +configChangeSNMP TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The SNMP configuration has been changed." + --#TYPE "APC: The SNMP configuration has been changed." + --#SUMMARY "The SNMP configuration has been changed." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 44 + + +configChangeOutlet TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUOutletConfigIndex } + DESCRIPTION + "WARNING: The specified PDU outlet has changed configuration. + If sPDUOutletConfigIndex equals zero, then the Master outlet + has changed configuration." + --#TYPE "APC PDU: Outlet configuration has been changed." + --#SUMMARY "Outlet configuration has been changed." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 45 + +accessViolationConsole TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: Someone has attempted to login via the console with the incorrect password." + --#TYPE "APC: Access violation via the console." + --#SUMMARY "Three unsuccessful logins have been attempted via the console." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 46 + +accessViolationHTTP TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: Someone has attempted to login via HTTP with the incorrect password." + --#TYPE "APC: Access violation via HTTP." + --#SUMMARY "An unsuccessful attempt to login via HTTP." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 47 + +passwordChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The password for the device has been changed." + --#TYPE "APC: Password change for the device." + --#SUMMARY "Someone has changed the password on the device." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 48 + +badVoltage TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The output voltage is not within acceptable range." + --#TYPE "APC UPS: Bad output voltage." + --#SUMMARY "The output voltage is not within acceptable range." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 49 + +badVoltageCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The output voltage has returned to an acceptable level." + --#TYPE "APC UPS: The bad voltage output condition has been cleared." + --#SUMMARY "The output voltage has returned to an acceptable level." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 50 + +chargerFailure TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The battery charger has failed." + --#TYPE "APC UPS: The battery charger has failed." + --#SUMMARY "The battery charger has failed." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 51 + +chargerFailureCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The battery charger failure condition has been cleared." + --#TYPE "APC UPS: The battery charger failure condition cleared" + --#SUMMARY "The battery charger failure condition has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 52 + +batteryOverTemperature TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The battery temperature threshold has been violated." + --#TYPE "APC UPS: The battery temperature threshold has been violated." + --#SUMMARY "The battery temperature threshold has been violated." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 53 + +batteryOverTemperatureCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The battery over temperature has been cleared." + --#TYPE "APC UPS: The battery over temperature has been cleared." + --#SUMMARY "The battery over temperature has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 54 + + smartRelayFault TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: SmartBoost(TM) or SmartTrim(TM) relay fault." + --#TYPE "APC UPS: SmartBoost(TM) or SmartTrim(TM) relay fault." + --#SUMMARY "SmartBoost(TM) or SmartTrim(TM) relay fault." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 55 + +smartRelayFaultCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: SmartBoost(TM) or SmartTrim(TM) relay fault has been cleared." + --#TYPE "APC UPS: SmartBoost(TM) or SmartTrim(TM) relay fault cleared." + --#SUMMARY "SmartBoost(TM) or SmartTrim(TM) relay fault has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 56 + +humidityThresholdViolation1 TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Probe 1 humidity threshold violated. The + first variable is the current humidity." + --#TYPE "APC Environmental Monitor: Probe 1 humidity threshold violation" + --#SUMMARY "A humidity threshold has been violated on probe 1." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 57 + +humidityThresholdViolationCleared1 TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An Environmental Monitor humidity threshold violation has been cleared on probe 1." + --#TYPE "APC Environmental Monitor: Probe 1 humidity violation cleared" + --#SUMMARY "A humidity threshold violation has been cleared on probe 1." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 58 + +temperatureThresholdViolation1 TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: An Environmental Monitor temperature threshold has been violated on probe 1. + The first variable is the current temperature." + --#TYPE "APC Environmental Monitor: Probe 1 temperature violation" + --#SUMMARY "A temperature threshold has been violated on probe 1." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 59 + +temperatureThresholdViolationCleared1 TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An Environmental Monitor temperature threshold violation has been cleared on probe 1." + --#TYPE "APC Environmental Monitor: Probe 1 temperature violation cleared" + --#SUMMARY "A temperature threshold violation has been cleared on probe 1." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 60 + +humidityThresholdViolation2 TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: An Environmental Monitor humidity threshold has been violated on probe 2. + The first variable is the current humidity." + --#TYPE "APC Environmental Monitor: Probe 2 humidity violation" + --#SUMMARY "A humidity threshold has been violated on probe 2." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 61 + +humidityThresholdViolationCleared2 TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An Environmental Monitor humidity threshold violation has been cleared on probe 2." + --#TYPE "APC Environmental Monitor: Probe 2 humidity violation cleared" + --#SUMMARY "A humidity threshold violation has been cleared on probe 2." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 62 + +temperatureThresholdViolation2 TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: An Environmental Monitor temperature threshold has been violated on probe 2. + The first variable is the current temperature." + --#TYPE "APC Environmental Monitor: Probe 2 temperature violation" + --#SUMMARY "A temperature threshold has been violated on probe 2." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 63 + +temperatureThresholdViolationCleared2 TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An Environmental Monitor temperature threshold violation has been cleared on probe 2." + --#TYPE "APC Environmental Monitor: Probe 2 temperature violation cleared" + --#SUMMARY "A temperature threshold violation has been cleared on probe 2." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 64 + +mupsCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communication with the Environmental Monitor has been established." + --#TYPE "APC Environmental Monitor: Communication established" + --#SUMMARY "Communication established between the agent and the Environmental Monitor." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 65 + +mupsCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Communication to the Environmental Monitor has been lost. Steps + to reestablish communication are in progress." + --#TYPE "APC Environmental Monitor: Communication failure" + --#SUMMARY "Communication lost between the agent and the Environmental Monitor." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 66 + +batteryIncrease TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The number of batteries has increased." + --#TYPE "APC UPS: The number of batteries has increased." + --#SUMMARY "The number of batteries has increased." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 67 + +batteryDecrease TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The number of batteries has decreased." + --#TYPE "APC UPS: The number of batteries has decreased." + --#SUMMARY "The number of batteries has decreased." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 68 + +powerModuleIncrease TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The number of power modules has increased." + --#TYPE "APC UPS: The number of power modules has increased." + --#SUMMARY "The number of power modules has increased." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 69 + +powerModuleDecrease TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The number of power modules has decreased." + --#TYPE "APC UPS: The number of power modules has decreased." + --#SUMMARY "The number of power modules has decreased." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 70 + +intelligenceModuleInserted TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An intelligence module has been inserted." + --#TYPE "APC UPS: An intelligence module has been inserted." + --#SUMMARY "An intelligence module has been inserted." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 71 + +intelligenceModuleRemoved TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An intelligence module has been removed." + --#TYPE "APC UPS: An intelligence module has been removed." + --#SUMMARY "An intelligence module has been removed." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 72 + +rintelligenceModuleInserted TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A redundant intelligence module has been inserted." + --#TYPE "APC UPS: A redundant intelligence module has been inserted." + --#SUMMARY "A redundant intelligence module has been inserted." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 73 + +rintelligenceModuleRemoved TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A redundant intelligence module has been removed." + --#TYPE "APC UPS: A redundant intelligence module has been removed." + --#SUMMARY "A redundant intelligence module has been removed." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 74 + +extBatteryFrameIncease TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An external battery frame has been added." + --#TYPE "APC UPS: An external battery frame has been added." + --#SUMMARY "An external battery frame has been added." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 75 + +extBatteryFrameDecrease TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An external battery frame has been removed." + --#TYPE "APC UPS: An external battery frame has been removed." + --#SUMMARY "An external battery frame has been removed." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 76 + +abnormalCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: An abnormal condition has been detected. + The first variable is the fault condition." + --#TYPE "APC: An abnormal condition has been detected." + --#SUMMARY "An abnormal condition has been detected." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 77 + +abnormalConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An abnormal condition has been cleared. + The first variable is the fault condition." + --#TYPE "APC: An abnormal condition has been cleared." + --#SUMMARY "An abnormal condition has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 78 + +deviceStatusChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString} + DESCRIPTION + "INFORMATIONAL: The status of the device being monitored has changed." + --#TYPE "APC : The status of the device being monitored has changed." + --#SUMMARY "The status of the device being monitored has changed." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 79 + +noBatteries TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The UPS has no batteries attached." + --#TYPE "APC UPS: No batteries attached." + --#SUMMARY "The UPS has no batteries attached." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 80 + +noBatteriesCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The UPS's batteries have been attached." + --#TYPE "APC UPS: The no batteries attached condition has been cleared." + --#SUMMARY "The UPS's batteries have been attached." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 81 + +userAdded TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A new user has been added." + --#TYPE "APC: A new user has been added." + --#SUMMARY "A new user has been added." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 82 + +userDeleted TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A user has been deleted." + --#TYPE "APC: A user has been deleted." + --#SUMMARY "A user has been deleted." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 83 + +userModified TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A user has been modified." + --#TYPE "APC: A user has been modified." + --#SUMMARY "A user has been modified." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 84 + +-- MasterSwitch Vm Traps + +msvmCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communications with the MasterSwitch VM has been established." + --#TYPE "APC: Communications established with the MasterSwitch VM." + --#SUMMARY "Communications with the MasterSwitch VM has been established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 85 + +msvmCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsString } + DESCRIPTION + "SEVERE: Communications with the MasterSwitch VM has been lost." + --#TYPE "APC: Communications lost with the MasterSwitch VM." + --#SUMMARY "Communications with the MasterSwitch VM has been lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 86 + +msvmOverload TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsString } + DESCRIPTION + "SEVERE: The MasterSwitch VM in an overload condition." + --#TYPE "APC: The MasterSwitch VM is near or at an overload condition." + --#SUMMARY "The MasterSwitch VM is near or at an overload condition." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 87 + +msvmOverloadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The overload condition on the MasterSwitch VM has been cleared." + --#TYPE "APC: The overload condition cleared on the MasterSwitch VM." + --#SUMMARY "The overload condition on the MasterSwitch VM has been cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 88 + +msvmOutletOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, + sPDUOutletControlVMOutletIndex, sPDUOutletControlVMOutletName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet on the MasterSwitch VM has turned on." + --#TYPE "APC: An outlet on the MasterSwitch VM has turned on." + --#SUMMARY "An outlet on the MasterSwitch VM has turned on." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 89 + +msvmOutletOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, + sPDUOutletControlVMOutletIndex, sPDUOutletControlVMOutletName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet on the MasterSwitch VM has turned off." + --#TYPE "APC: An outlet on the MasterSwitch VM has turned off." + --#SUMMARY "An outlet on the MasterSwitch VM has turned off." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 90 + +msvmDeviceConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A device configuration change has been made on a MasterSwitch VM." + --#TYPE "APC: A device configuration change on a MasterSwitch VM." + --#SUMMARY "A device configuration change has been made on a MasterSwitch VM." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 91 + +msvmOutletConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, + sPDUOutletControlVMOutletIndex, sPDUOutletControlVMOutletName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet configuration change has been made on a MasterSwitch VM." + --#TYPE "APC: An outlet configuration change on a MasterSwitch VM." + --#SUMMARY "An outlet configuration change has been made on a MasterSwitch VM." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 92 + +msvmLowLoad TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The MasterSwitch VM has violated the low load threshold." + --#TYPE "APC: The MasterSwitch VM has violated the low load threshold." + --#SUMMARY "The MasterSwitch VM has violated the low load threshold." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 93 + +msvmLowLoadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The low load condition on the MasterSwitch VM has been cleared." + --#TYPE "APC: The low load condition cleared on the MasterSwitch VM." + --#SUMMARY "The low load condition on the MasterSwitch VM has been cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 94 + +msvmNearOverload TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsString } + DESCRIPTION + "SEVERE: The MasterSwitch VM is approaching an overload condition." + --#TYPE "APC: The MasterSwitch VM is near or at an overload condition." + --#SUMMARY "The MasterSwitch VM is near or at an overload condition." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 95 + +msvmNearOverloadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The near overload condition on the MasterSwitch VM has been cleared." + --#TYPE "APC: The overload condition cleared on the MasterSwitch VM." + --#SUMMARY "The overload condition on the MasterSwitch VM has been cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 96 + +msvmPowerSupplyStatusChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlVMIndex, sPDUMasterControlVMName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: The power supply status of the MasterSwitch VM has changed." + --#TYPE "APC: The power supply status changed on MasterSwitch VM" + --#SUMMARY "The power supply status of the MasterSwitch VM has changed." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 97 + +-- MasterSwitch plus (MSP) Traps + +mspCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlMSPIndex, sPDUMasterControlMSPName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communications with the MasterSwitch plus has been established." + --#TYPE "APC: Communications established with the MasterSwitch plus." + --#SUMMARY "Communications with the MasterSwitch plus has been established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 98 + +mspCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlMSPIndex, sPDUMasterControlMSPName, mtrapargsString } + DESCRIPTION + "SEVERE: Communications with the MasterSwitch plus has been lost." + --#TYPE "APC: Communications lost with the MasterSwitch plus." + --#SUMMARY "Communications with the MasterSwitch plus has been lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 99 + +mspOutletOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlMSPIndex, sPDUMasterControlMSPName, + sPDUOutletControlMSPOutletIndex, sPDUOutletControlMSPOutletName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet on the MasterSwitch plus has turned on." + --#TYPE "APC: An outlet on the MasterSwitch plus has turned on." + --#SUMMARY "An outlet on the MasterSwitch plus has turned on." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 100 + +mspOutletOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlMSPIndex, sPDUMasterControlMSPName, + sPDUOutletControlMSPOutletIndex, sPDUOutletControlMSPOutletName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet on the MasterSwitch plus has turned off." + --#TYPE "APC: An outlet on the MasterSwitch plus has turned off." + --#SUMMARY "An outlet on the MasterSwitch plus has turned off." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 101 + +mspDeviceConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlMSPIndex, sPDUMasterControlMSPName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A device configuration change has been made on a MasterSwitch plus." + --#TYPE "APC: A device configuration change on a MasterSwitch plus." + --#SUMMARY "A device configuration change has been made on a MasterSwitch plus." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 102 + +mspOutletConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { sPDUMasterControlMSPIndex, sPDUMasterControlMSPName, sPDUOutletControlMSPOutletIndex, sPDUOutletControlMSPOutletName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet configuration change has been made on a MasterSwitch plus." + --#TYPE "APC: An outlet configuration change on a MasterSwitch plus." + --#SUMMARY "An outlet configuration change has been made on a MasterSwitch plus." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 103 + +rsSourceSwitched TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger02, mtrapargsString03, mtrapargsInteger, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The Redundant Switch has switched source. + The first variable is an integer representing the current source: 0=A, 1=B. + The second variable is the 32-character name of the current source. + The third variable is an integer representing the transfer cause: + 0=No Transfers Recorded, 1=Due to user action or preferred switching, + 3=Due to line notch or spike, 5=Due to low line voltage, + 7=Transfer due to high line voltage, + 9=Transfer due to frequency out of range. + The fourth variable is a character string listing the transfer cause." + --#TYPE "APC Redundant Switch: The Redundant Switch has switched source" + --#SUMMARY "The Redundant Switch has switched source." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 104 + +rsLostRedundancy TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: The Redundant Switch has lost redundancy. + The first variable is an integer representing the source which is no longer available: 0=A, 1=B. + The second variable is the 32-character name of the source which is no longer available." + --#TYPE "APC Redundant Switch: The Redundant Switch has lost redundancy" + --#SUMMARY "The Redundant Switch has has lost redundancy." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 105 + +rsRedundancyRestored TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Redundancy has been restored to the Redundant Switch . + The first variable is an integer representing the source which has been restored: 0=A, 1=B. + The second variable is the 32-character name of the source which has been restored." + --#TYPE "APC Redundant Switch: Redundancy has been restored." + --#SUMMARY "Redundancy has been restored to the Redundant Switch ." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 106 + +rsConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A configuration change has been made on a Redundant Switch." + --#TYPE "APC: A configuration change on a Redundant Switch." + --#SUMMARY "A configuration change has been made on a Redundant Switch." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 107 + +rsCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communications with the Redundant Switch has been established." + --#TYPE "APC: Communications established with the Redundant Switch." + --#SUMMARY "Communications with the Redundant Switch has been established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 108 + +rsCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Communications with the Redundant Switch has been lost." + --#TYPE "APC: Communications lost with the Redundant Switch." + --#SUMMARY "Communications with the Redundant Switch has been lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 109 + +dcCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communications with the DC power plant has been established." + --#TYPE "APC: Communications established with the DC power plant." + --#SUMMARY "Communications with the DC power plant has been established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 110 + +dcCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Communications with the DC power plant has been lost." + --#TYPE "APC: Communications lost with the DC power plant." + --#SUMMARY "Communications with the DC power plant has been lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 111 + +dcPINChanged TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The active PIN on the DC controller has been changed." + --#TYPE "APC: The active PIN on the DC controller has been changed." + --#SUMMARY "The active PIN on the DC controller has been changed." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 112 + +dcMajorAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: A Major alarm is active in the DC power plant." + --#TYPE "APC: A Major alarm is active in the DC power plant." + --#SUMMARY "A Major alarm is active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 113 + +dcMajorAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Major alarm is no longer active in the DC power plant." + --#TYPE "APC: A Major alarm is no longer active in the DC power plant." + --#SUMMARY "A Major alarm is no longer active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 114 + +dcMinorAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Minor alarm is active in the DC power plant." + --#TYPE "APC: A Minor alarm is active in the DC power plant." + --#SUMMARY "A Minor alarm is active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 115 + +dcMinorAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Minor alarm is no longer active in the DC power plant." + --#TYPE "APC: A Minor alarm is no longer active in the DC power plant." + --#SUMMARY "A Minor alarm is no longer active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 116 + +dcOutputRelayOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { dm3StatusOutRlyIndex, dm3StatusOutRlyName, mtrapargsString } + DESCRIPTION + "WARNING: An output relay for the powerplant has been activated (state changed to on). + The first variable is an integer representing the output relay number that has gone on. + The second variable is the 16-character name of the output relay." + --#TYPE "APC: An output relay has gone on." + --#SUMMARY "An output relay has gone on in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 117 + +dcOutputRelayOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { dm3StatusOutRlyIndex, dm3StatusOutRlyName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An output relay for the powerplant has been deactivated (state changed to off). + The first variable is an integer representing the output relay number that has gone off. + The second variable is the 16-character name of the output relay." + --#TYPE "APC: An output relay has gone off." + --#SUMMARY "An output relay has gone off in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 118 + +dcInputRelayOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { dm3StatusInRlyIndex, dm3StatusInRlyName, mtrapargsString } + DESCRIPTION + "WARNING: An input relay for the powerplant has been activated (state changed to on). + The first variable is an integer representing the input relay number that has gone on. + The second variable is the 16-character name of the input relay." + --#TYPE "APC: An input relay has gone on." + --#SUMMARY "An input relay has gone on in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 119 + +dcInputRelayOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { dm3StatusInRlyIndex, dm3StatusInRlyName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An input relay for the powerplant has been deactivated (state changed to off). + The first variable is an integer representing the input relay number that has gone off. + The second variable is the 16-character name of the input relay." + --#TYPE "APC: An input relay has gone off." + --#SUMMARY "An input relay has gone off in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 120 + +logicPowerSuppliesIncreased TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The number of system power supplies has increased." + --#TYPE "APC UPS: The number of system power supplies has increased." + --#SUMMARY "The number of system power supplies has increased." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 121 + +logicPowerSuppliesDecreased TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The number of system power supplies has decreased." + --#TYPE "APC UPS: The number of system power supplies has decreased." + --#SUMMARY "The number of system power supplies has decreased." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 122 + +externalSwitchGearClosed TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: External Switch Gear closed." + --#TYPE "APC UPS: External Switch Gear closed." + --#SUMMARY "External Switch Gear closed." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 123 + +externalSwitchGearOpened TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: External Switch Gear opened." + --#TYPE "APC UPS: External Switch Gear opened." + --#SUMMARY "External Switch Gear opened." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 124 + +generalDeviceEvent TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: APC Device event." + --#TYPE "APC Device event" + --#SUMMARY "APC Device event." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 125 + +atsSourceSwitched TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The Automatic Transfer Switch has switched source. + The first variable is an integer representing the current source: 0=A, 1=B. + The second variable is the 32-character name of the current source." + --#TYPE "APC Automatic Transfer Switch: The ATS has switched source" + --#SUMMARY "The Automatic Transfer Switch has switched source." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 126 + +atsLostRedundancy TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: The Automatic Transfer Switch has lost redundancy. + The first variable is an integer representing the source which is no longer available: 0=A, 1=B. + The second variable is the 32-character name of the source which is no longer available." + --#TYPE "APC Automatic Transfer Switch: The ATS has lost redundancy. " + --#SUMMARY "The Automatic Transfer Switch has has lost redundancy." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 127 + +atsRedundancyRestored TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Redundancy has been restored to the Automatic Transfer Switch . + The first variable is an integer representing the source which has been restored: 0=A, 1=B. + The second variable is the 32-character name of the source which has been restored." + --#TYPE "APC Automatic Transfer Switch: Redundancy has been restored." + --#SUMMARY "Redundancy has been restored to the Automatic Transfer Switch ." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 128 + +atsConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A configuration change has been made on the Automatic Transfer Switch. + The first variable is an integer representing the configuration setting which changed: + 0=Transfer Voltage Range, 1=Sensitivity 2=Preferred Source + 3=Front Panel Lockout 4=Current Limit" + --#TYPE "APC Automatic Transfer Switch: ATS configuration changed." + --#SUMMARY "A configuration change has been made on a Automatic Transfer Switch." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 129 + +atsCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communications with the Automatic Transfer Switch has been established." + --#TYPE "APC Automatic Transfer Switch: Communications established." + --#SUMMARY "Communications with the Automatic Transfer Switch has been established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 130 + +atsCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Communications with the Automatic Transfer Switch has been lost." + --#TYPE "APC Automatic Transfer Switch: Communications lost." + --#SUMMARY "Communications with the Automatic Transfer Switch has been lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 131 + +atsOverCurrent TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Output Current has exceeded threshold." + --#TYPE "APC Automatic Transfer Switch: Output Current exceeded threshold" + --#SUMMARY "Output Current has exceeded Threshold. " + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 132 + +atsOverCurrentCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Output Current has returned below threshold." + --#TYPE "APC Automatic Transfer Switch: Output Current below threshold." + --#SUMMARY "Output Current has returned below threshold." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 133 + +atsPowerSupplyFailure TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The Automatic Transfer Switch Power Supply has failed. + The first variable is an integer representing the Power Supply which + has failed: 0=24V, 1=12V 2=5V." + --#TYPE "APC Automatic Transfer Switch: The ATS Power Supply has failed." + --#SUMMARY "The Automatic Transfer Switch Power Supply has failed." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 134 + +atsPowerSupplyFailureCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The Automatic Transfer Power Supply Failure Cleared. + The first variable is an integer representing the Power Supply which + has cleared: 0=24V, 1=12V 2=5V." + --#TYPE "APC Automatic Transfer Switch: Power Supply Failure Cleared." + --#SUMMARY "The Automatic Transfer Switch Power Supply Failure Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 135 + +dcMainsFailAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Mains Fail alarm is active in the DC power plant." + --#TYPE "APC: A Mains Fail alarm is active in the DC power plant." + --#SUMMARY "A Mains Fail alarm is active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 136 + +dcMainsFailAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Mains Fail alarm is no longer active in the DC power plant." + --#TYPE "APC: Mains Fail alarm is no longer active in the DC power plant." + --#SUMMARY "Mains Fail alarm is no longer active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 137 + +dcFanFailAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Fan Fail alarm is active in the DC power plant." + --#TYPE "APC: A Fan Fail alarm is active in the DC power plant." + --#SUMMARY "A Fan Fail alarm is active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 138 + +dcFanFailAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Fan Fail alarm is no longer active in the DC power plant." + --#TYPE "APC: A Fan Fail alarm is no longer active in the DC power plant." + --#SUMMARY "A Fan Fail alarm is no longer active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 139 + +dcRectifierOvertempAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: Rect. Overtemp alarm is active in the power plant." + --#TYPE "APC: Rect. Overtemp alarm is active in the power plant." + --#SUMMARY "Rect. Overtemp alarm is active in the power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 140 + +dcRectifierOvertempAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Rect. Overtemp alarm is no longer active in the power plant." + --#TYPE "APC: Rect. Overtmp alarm is no longer active in the power plant." + --#SUMMARY "Rect. Overtmp alarm is no longer active in the power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 141 + +dcCurrentLimitAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Current Limit alarm is active in the power plant." + --#TYPE "APC: A Current Limit alarm is active in the power plant." + --#SUMMARY "A Current Limit alarm is active in the power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 142 + +dcCurrentLimitAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Current Limit alarm is no longer active in the power plant." + --#TYPE "APC: Current Limit alarm is no longer active in the power plant." + --#SUMMARY "Current Limit alarm is no longer active in the power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 143 + +dcRectifierFailAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Rect. Fail alarm is active in the power plant." + --#TYPE "APC: A Rect. Fail alarm is active in the power plant." + --#SUMMARY "A Rect. Fail alarm is active in the power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 144 + +dcRectifierFailAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Rect. Fail alarm is no longer active in the power plant." + --#TYPE "APC: Rect. Fail alarm is no longer active in the power plant." + --#SUMMARY "Rect. Fail alarm is no longer active in the power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 145 + +dcMultRectFailAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: Multiple Rect. Fail alarm is active in the powerplant." + --#TYPE "APC: Multiple Rect. Fail alarm is active in the powerplant." + --#SUMMARY "Multiple Rect. Fail alarm is active in the powerplant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 146 + +dcMultRectFailAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Mult Rect Fail alarm is no longer active in the powerplant." + --#TYPE "APC: Mult Rect Fail alarm is no longer active in the powerplant." + --#SUMMARY "Mult Rect Fail alarm is no longer active in the powerplant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 147 + +dcBatteryBreakerAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: Batt. Breaker alarm is active in the power plant." + --#TYPE "APC: Batt. Breaker alarm is active in the power plant." + --#SUMMARY "Batt. Breaker alarm is active in the power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 148 + +dcBatteryBreakerAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Batt. Breaker alarm is no longer active in the power plant." + --#TYPE "APC: Batt. Breaker alarm is no longer active in the power plant." + --#SUMMARY "Batt. Breaker alarm is no longer active in the power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 149 + +dcRectifierOVPAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Rect. OVP alarm is active in the power plant." + --#TYPE "APC: A Rect. OVP alarm is active in the power plant." + --#SUMMARY "A Rect. OVP alarm is active in the power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 150 + +dcRectifierOVPAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Rect. OVP alarm is no longer active in the power plant." + --#TYPE "APC: A Rect. OVP alarm is no longer active in the power plant." + --#SUMMARY "A Rect. OVP alarm is no longer active in the power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 151 + +dcLVDImminentAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A LVD Imminent alarm is active in the powerplant." + --#TYPE "APC: A LVD Imminent alarm is active in the powerplant." + --#SUMMARY "A LVD Imminent alarm is active in the powerplant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 152 + +dcLVDImminentAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A LVD Imminent alarm is no longer active in the powerplant." + --#TYPE "APC: A LVD Imminent alarm is no longer active in the powerplant." + --#SUMMARY "A LVD Imminent alarm is no longer active in the powerplant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 153 + +dcFuseCBAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Fuse/CB alarm is active in the DC power plant." + --#TYPE "APC: A Fuse/CB alarm alarm is active in the DC power plant." + --#SUMMARY "A Fuse/CB alarm is active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 154 + +dcFuseCBAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Fuse/CB alarm is no longer active in the DC power plant." + --#TYPE "APC: A Fuse/CB alarm is no longer active in the DC power plant." + --#SUMMARY "A Fuse/CB alarm is no longer active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 155 + +dcBatteryTestFail TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Battery Test failed in the DC power plant." + --#TYPE "APC: A Battery Test failed in the DC power plant." + --#SUMMARY "A Battery Test failed in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 156 + +dcTemperatureAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Temperature is active in the power plant." + --#TYPE "APC: A Temperature alarm is active in the power plant." + --#SUMMARY "A Temperature alarm is active in the power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 157 + +dcTemperatureAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Temperature alarm is no longer active in the power plant." + --#TYPE "APC: A Temperature alarm is no longer active in the power plant." + --#SUMMARY "A Temperature alarm is no longer active in the power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 158 + +dcHumidityAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: A Humidity alarm is active in the DC power plant." + --#TYPE "APC: A Humidity alarm is active in the DC power plant." + --#SUMMARY "A Humidity alarm is active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 159 + +dcHumidityAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Humidity alarm is no longer active in the DC power plant." + --#TYPE "APC: A Humidity alarm is no longer active in the DC power plant." + --#SUMMARY "A Humidity alarm is no longer active in the DC power plant." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 160 + +dcBBCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Power plant bridging board communications established." + --#TYPE "APC: Power plant bridging board communications established." + --#SUMMARY "Power plant bridging board communications established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 161 + +dcBBCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "SEVERE: Power plant bridging board communications lost." + --#TYPE "APC: Power plant bridging board communications lost." + --#SUMMARY "Power plant bridging board communications lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 162 + +iemHighTempThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusProbeCurrentTemp, iemStatusProbeTempUnits, iemStatusProbeNumber, + iemStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: High temperature threshold violated on Integrated + Environmental Monitor probe. The first variable is the + current temperature. The second variable is the temperature + scale. The third variable is the probe number. The fourth + variable is the probe name." + --#TYPE "APC IEM: High temperature threshold violation." + --#SUMMARY "High temperature threshold violation." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 163 + +iemHighTempThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusProbeNumber, iemStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: High temperature threshold violated on Integrated + Environmental Monitor probe has been cleared. The first variable + is the probe number. The second variable is the probe name." + --#TYPE "APC IEM: High temperature threshold violation cleared." + --#SUMMARY "High temperature threshold violation has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 164 + +iemLowTempThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusProbeCurrentTemp, iemStatusProbeTempUnits, iemStatusProbeNumber, + iemStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Low temperature threshold violated on integrated + probe. The first variable is the current temperature. The + second variable is the temperature scale. The third + variable is the probe number. The fourth variable is the + probe name." + --#TYPE "APC IEM: Low temperature threshold violation." + --#SUMMARY "Low temperature threshold violation." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 165 + +iemLowTempThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusProbeNumber, iemStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Low temperature threshold violated on integrated + probe has been cleared. The first variable is the probe number. + The second variable is the probe name." + --#TYPE "APC IEM: Low temperature threshold violation cleared." + --#SUMMARY "Low temperature threshold violation has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 166 + +iemHighHumidThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusProbeCurrentHumid, iemStatusProbeNumber, iemStatusProbeName, + mtrapargsString } + DESCRIPTION + "SEVERE: High humidity threshold violated on integrated + probe. The first variable is the current humidity. The + second variable is the probe number. The third variable + is the probe name." + --#TYPE "APC IEM: High humidity threshold violation." + --#SUMMARY "High humidity threshold violation." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 167 + +iemHighHumidThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusProbeNumber, iemStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: High humidity threshold violated on integrated + probe cleared. The first variable is the probe number. The second + variable is the probe name." + --#TYPE "APC IEM: High humidity threshold violation cleared." + --#SUMMARY "High humidity threshold violation has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 168 + +iemLowHumidThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusProbeCurrentHumid, iemStatusProbeNumber, iemStatusProbeName, + mtrapargsString } + DESCRIPTION + "SEVERE: Low humidity threshold violated on integrated + probe. The first variable is the current humidity. The + second variable is the probe number. The third variable + is the probe name." + --#TYPE "APC IEM: Low humidity threshold violation." + --#SUMMARY "Low humidity threshold violation." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 169 + +iemLowHumidThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusProbeNumber, iemStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Low humidity threshold violated on integrated + probe cleared. The first variable is the probe number. The second + variable is the probe name." + --#TYPE "APC IEM: Low humidity threshold violation cleared." + --#SUMMARY "Low humidity threshold violation has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 170 + +iemProbeDisconnected TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The temperature/humidity probe on the Integrated + Environmental Monitor has been disconnected. This trap is + generated when a probe that has been in communication with + the Environmental Monitor has been disconnected or can no + longer communicate." + --#TYPE "APC IEM: Probe disconnected." + --#SUMMARY "Probe has been disconnected." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 171 + +iemProbeConnected TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The temperature/humidity probe on the Integrated + Environmental Monitor has been connected. This trap is generated + when the Environmental Monitor establishes communication with a + probe that had previously not been connected." + --#TYPE "APC IEM: Probe Connected." + --#SUMMARY "Probe has been connected." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 172 + +iemContactFault TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusContactNumber, iemStatusContactName, mtrapargsString } + DESCRIPTION + "SEVERE: There is a contact fault on the Integrated + Environmental Monitor. The first argument is the number + of the contact. The second argument is the name of the + contact." + --#TYPE "APC IEM: Contact fault." + --#SUMMARY "Contact fault." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 173 + +iemContactFaultCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusContactNumber, iemStatusContactName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The contact fault on the Integrated + Environmental Monitor has been cleared. The first + argument is the number of the contact. The second + argument is the name of the contact." + --#TYPE "APC IEM: Contact fault." + --#SUMMARY "Contact fault cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 174 + +iemRelayFault TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusRelayNumber, iemStatusRelayName, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: The output relay on the Integrated Environmental + Monitor has switched to the fault state. The first + argument is the number of the output relay. The second + argument is the name of the output relay. The third + argument is the event that caused the fault." + --#TYPE "APC IEM: Output relay fault." + --#SUMMARY "Output relay has faulted." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 175 + +iemRelayFaultCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { iemStatusRelayNumber, iemStatusRelayName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The fault condition on the output relay on the + Integrated Environmental Monitor has cleared. The first + argument is the number of the output relay. The second + argument is the name of the output relay." + --#TYPE "APC IEM: Output relay fault condition cleared." + --#SUMMARY "Output relay fault cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 176 + +bmBatManCommEstab TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Serial Communications Established with Battery Manager." + --#TYPE "BatMan : Communications Established." + --#SUMMARY "Communications Established." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 177 + +bmBatManCommLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Serial Communications Lost with Battery Manager." + --#TYPE "BatMan : Communications Lost." + --#SUMMARY "Communications Lost." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 178 + +bmBatManKneeAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Battery Voltage Knee Threshold Alarm Detected." + --#TYPE "BatMan : Knee Alarm Detected." + --#SUMMARY "Knee Alarm Detected." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 179 + +bmBatManKneeAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Battery Voltage Knee Threshold Alarm Cleared." + --#TYPE "BatMan : Knee Alarm Cleared." + --#SUMMARY "Knee Alarm Cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 180 + +bmBatManChargerAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: Charger Alarm Detected." + --#TYPE "BatMan : Charger Alarm Detected." + --#SUMMARY "Charger Alarm Detected." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 181 + +bmBatManChargerAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Charger Alarm Cleared." + --#TYPE "BatMan : Charger Alarm Cleared." + --#SUMMARY "Charger Alarm Cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 182 + +bmBatManBatteryAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: Battery Alarm Detected." + --#TYPE "BatMan : Battery Alarm Detected." + --#SUMMARY "Battery Alarm Detected." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 183 + +bmBatManBatteryAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Battery Alarm Cleared." + --#TYPE "BatMan : Battery Alarm Cleared." + --#SUMMARY "Battery Alarm Cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 184 + +bmBatManEnvironmentAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: Environment Alarm Detected." + --#TYPE "BatMan : Environment Alarm Detected." + --#SUMMARY "Environment Alarm Detected." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 185 + +bmBatManEnvironmentAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Environment Alarm Cleared." + --#TYPE "BatMan : Environment Alarm Cleared." + --#SUMMARY "Environment Alarm Cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 186 + +bmBatManMaintenanceAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Maintenance Alarm Detected." + --#TYPE "BatMan : Maintenance Due Alarm Detected." + --#SUMMARY "Maintenance Due Alarm Detected." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 187 + +bmBatManMaintenanceAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Maintenance Alarm Cleared." + --#TYPE "BatMan : Maintenance Due Alarm Cleared." + --#SUMMARY "Maintenance Due Alarm Cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 188 + +pduCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communication Established. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Communication Established." + --#SUMMARY "Communication Established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 189 + +pduCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: Communication Lost. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Communication Lost." + --#SUMMARY "Communication Lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 190 + +pduUtilityLineUndervoltage TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Utility Line Undervoltage. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Utility Line Undervoltage." + --#SUMMARY "Utility Line Undervoltage." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 191 + +pduUtilityLineUndervoltageCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Utility Line Undervoltage Cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Utility Line Undervoltage Cleared." + --#SUMMARY "Utility Line Undervoltage Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 192 + +pduUtilityLineOvervoltage TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Utility Line Overvoltage. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Utility Line Overvoltage." + --#SUMMARY "Utility Line Overvoltage." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 193 + +pduUtilityLineOvervoltageCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Utility Line Overvoltage Cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Utility Line Overvoltage Cleared." + --#SUMMARY "Utility Line Overvoltage Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 194 + +pduGroundOvercurrent TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: Ground Overcurrent. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Ground Overcurrent." + --#SUMMARY "Ground Overcurrent." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 195 + +pduGroundOvercurrentCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Ground Overcurrent Cleared. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Ground Overcurrent Cleared." + --#SUMMARY "Ground Overcurrent Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 196 + +pduCircuitPanelInputUndervoltage TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Circuit Panel Input Undervoltage. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Circuit Panel Input Undervoltage." + --#SUMMARY "Circuit Panel Input Undervoltage." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 197 + +pduCircuitPanelInputUndervoltageCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Circuit Panel Input Undervoltage Cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Circuit Panel Input Undervoltage Cleared." + --#SUMMARY "Circuit Panel Input Undervoltage Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 198 + +pduCircuitPanelInputOvervoltage TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Circuit Panel Input Overvoltage. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Circuit Panel Input Overvoltage." + --#SUMMARY "Circuit Panel Input Overvoltage." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 199 + +pduCircuitPanelInputOvervoltageCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Circuit Panel Input Overvoltage Cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Circuit Panel Input Overvoltage Cleared." + --#SUMMARY "Circuit Panel Input Overvoltage Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 200 + +pduCircuitPanelInputUndercurrent TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Circuit Panel Input Undercurrent. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Circuit Panel Input Undercurrent." + --#SUMMARY "Circuit Panel Input Undercurrent." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 201 + +pduCircuitPanelInputUndercurrentCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Circuit Panel Input Undercurrent Cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Circuit Panel Input Undercurrent Cleared." + --#SUMMARY "Circuit Panel Input Undercurrent Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 202 + +pduCircuitPanelInputOvercurrent TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Circuit Panel Input Overcurrent. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Circuit Panel Input Overcurrent." + --#SUMMARY "Circuit Panel Input Overcurrent." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 203 + +pduCircuitPanelInputOvercurrentCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Circuit Panel Input Overcurrent Cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: Circuit Panel Input Overcurrent Cleared." + --#SUMMARY "Circuit Panel Input Overcurrent Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 204 + +pduCircuitPanelFrequencyOutOfRange TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: Circuit Panel Input Frequency Out Of Range. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Circuit Panel Input Frequency Out Of Range." + --#SUMMARY "Circuit Panel Input Frequency Out Of Range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 205 + +pduCircuitPanelFrequencyOutofRangeCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Circuit Panel Input Frequency No Longer Out Of Range. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Circuit Panel Input Frequency No Longer Out Of Range." + --#SUMMARY "Circuit Panel Input Frequency No Longer Out Of Range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 206 + +pduCircuitPanelNeutralOvercurrent TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: Circuit Panel Input Neutral Overcurrent. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Circuit Panel Input Neutral Overcurrent." + --#SUMMARY "Circuit Panel Input Neutral Overcurrent." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 207 + +pduCircuitPanelNeutralOvercurrentCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Circuit Panel Input Neutral Overcurrent Cleared. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Circuit Panel Input Neutral Overcurrent Cleared." + --#SUMMARY "Circuit Panel Input Neutral Overcurrent Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 208 + +pduSystemOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: PDU System Off. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: System Off." + --#SUMMARY "PDU System Off." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 209 + +pduOnBatteryMode TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: PDU is in On Battery Mode. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: On Battery Mode." + --#SUMMARY "PDU is in On Battery Mode." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 210 + +pduMaintenanceBypassMode TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: PDU is in Maintenance Bypass Mode. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Maintenance Bypass Mode." + --#SUMMARY "PDU is in Maintenance Bypass Mode." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 211 + +pduAtypicalBypassMode TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "WARNING: PDU is in Atypical Bypass Mode. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Atypical Bypass Mode." + --#SUMMARY "PDU is in Atypical Bypass Mode." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 212 + +pduNoPanelFeedMode TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: PDU is in No Panel Feed Mode. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: No Panel Feed Mode." + --#SUMMARY "PDU is in No Panel Feed Mode." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 213 + +pduUpsOperationMode TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: PDU is in Ups Operation Mode. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Ups Operation Mode." + --#SUMMARY "PDU is in Ups Operation Mode." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 214 + +pduForcedBypassMode TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "WARNING: PDU is in Forced Bypass Mode. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Forced Bypass Mode." + --#SUMMARY "PDU is in Forced Bypass Mode." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 215 + +pduInputTransformerOverTemperature TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: Input Transformer Over Temperature. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Input Transformer Over Temperature." + --#SUMMARY "Input Transformer Over Temperature." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 216 + +pduInputTransformerOverTemperatureCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Input Transformer Over Temperature Cleared. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC PDU: Input Transformer Over Temperature Cleared." + --#SUMMARY "Input Transformer Over Temperature Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 217 + +pduUPSInputVoltageLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: UPS Input Voltage phase-N Lost. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: UPS Input Voltage phase-N Lost." + --#SUMMARY "UPS Input Voltage phase-N Lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 218 + +pduUPSInputVoltageRestored TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: UPS Input Voltage phase-N Restored. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC PDU: UPS Input Voltage phase-N Restored." + --#SUMMARY "UPS Input Voltage phase-N Restored." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 219 + +pduContactFault TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: A contact closure in the PDU is in an abnormal position. + The first argument is the serial number. + The second argument is the device name. + The third argument is the number of the contact." + --#TYPE "APC PDU: Contact Abnormal." + --#SUMMARY "Contact Abnormal." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 220 + +pduContactFaultCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A contact closure in the PDU is in a normal position. + The first argument is the serial number. + The second argument is the device name. + The third argument is the number of the contact." + --#TYPE "APC PDU: Contact Normal." + --#SUMMARY "Contact Normal." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 221 + +rPDUBankPhaseLowLoad TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusBankNumber, rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "WARNING: A bank or phase on the Rack PDU has violated the low load threshold. + The first argument is the serial number. + The second argument is the device name. + The third argument is the bank number (0 if this is phase data). + The fourth argument is the phase number (0 if this is bank data)." + --#TYPE "APC Rack PDU: Violation of bank or phase low load threshold." + --#SUMMARY "A bank or phase on the Rack PDU has violated the low load threshold." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 222 + +rPDUBankPhaseLowLoadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusBankNumber, rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The bank or phase low load condition on a Rack PDU has been + cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the bank number (0 if this is phase data). + The fourth argument is the phase number (0 if this is bank data)." + --#TYPE "APC Rack PDU: Bank or phase low load condition cleared." + --#SUMMARY "The bank or phase low load condition on a Rack PDU has been cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 223 + +rPDUBankPhaseNearOverload TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusBankNumber, rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "WARNING: A bank or phase of the Rack PDU is near an overload condition. + The first argument is the serial number. + The second argument is the device name. + The third argument is the bank number (0 if this is phase data). + The fourth argument is the phase number (0 if this is bank data)." + --#TYPE "APC Rack PDU: Bank or phase near an overload condition." + --#SUMMARY "A bank or phase of the Rack PDU is near an overload condition." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 224 + +rPDUBankPhaseNearOverloadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusBankNumber, rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The bank or phase near overload condition on a Rack PDU has + been cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the bank number (0 if this is phase data). + The fourth argument is the phase number (0 if this is bank data)." + --#TYPE "APC Rack PDU: Bank or phase near overload condition has cleared." + --#SUMMARY "Rack PDU bank or phase near overload condition has cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 225 + +rPDUBankPhaseOverload TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusBankNumber, rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "SEVERE: A bank or phase of the Rack PDU is in an overload condition. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number. + The third argument is the bank number (0 if this is phase data). + The fourth argument is the phase number (0 if this is bank data)." + --#TYPE "APC Rack PDU: Bank or phase overload condition." + --#SUMMARY "A bank or phase of the Rack PDU is in an overload condition." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 226 + +rPDUBankPhaseOverloadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusBankNumber, rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The bank or phase overload condition on a Rack PDU has been + cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the bank number (0 if this is phase data). + The fourth argument is the phase number (0 if this is bank data)." + --#TYPE "APC Rack PDU: Bank or phase overload condition has cleared." + --#SUMMARY "The bank or phase overload condition on a Rack PDU has cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 227 + +aruDeviceConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Remote ARU Device Configurtion change. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: ARU Device configuration change." + --#SUMMARY "ARU device configuration change." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 228 + +rmPDUCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString03, mtrapargsString02, mtrapargsString } + DESCRIPTION + "SEVERE: Communication Lost. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC RM PDU: Communication Lost." + --#SUMMARY "Communication Lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 229 + +emsCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communication Established. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC EMS: Communication Established." + --#SUMMARY "Communication Established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 230 + +emsCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "SEVERE: Communication Lost. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC EMS: Communication Lost." + --#SUMMARY "Communication Lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 231 + +emsProbeConnected TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A probe has been connected to the EMS. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the probe number. + The fourth argument is the probe name." + --#TYPE "APC EMS: Probe Connected." + --#SUMMARY "Probe Connected." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 232 + +emsProbeDisconnected TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: A probe has been disconnected from the EMS. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the probe number. + The fourth argument is the probe name." + --#TYPE "APC EMS: Probe Disconnected." + --#SUMMARY "Probe Disconnected." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 233 + +emsSensorConnected TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + emsSensorStatusSensorIndex, emsSensorStatusSensorName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A sensor has been connected to the EMS. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the sensor number. + The fourth argument is the sensor name." + --#TYPE "APC EMS: Sensor Connected." + --#SUMMARY "Sensor Connected." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 234 + +emsSensorDisconnected TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + emsSensorStatusSensorIndex, emsSensorStatusSensorName, mtrapargsString } + DESCRIPTION + "SEVERE: A sensor has been disconnected from the EMS. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the sensor number. + The fourth argument is the sensor name." + --#TYPE "APC EMS: Sensor Disconnected." + --#SUMMARY "Sensor Disconnected." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 235 + +emsSensorFault TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + emsSensorStatusSensorIndex, emsSensorStatusSensorName, mtrapargsString } + DESCRIPTION + "SEVERE: A EMS sensor is in the fault condition. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the sensor number. + The fourth argument is the sensor name." + --#TYPE "APC EMS: Sensor Fault." + --#SUMMARY "Sensor Fault." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 236 + +emsSensorFaultCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + emsSensorStatusSensorIndex, emsSensorStatusSensorName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A EMS sensor fault condition has cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the sensor number. + The fourth argument is the sensor name." + --#TYPE "APC EMS: Sensor Fault Cleared." + --#SUMMARY "Sensor Fault Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 237 + +emsBeaconConnected TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A beacon has been connected to the EMS. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC EMS: Beacon Connected." + --#SUMMARY "Beacon Connected." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 238 + +emsBeaconDisconnected TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "SEVERE: A beacon has been disconnected from the EMS. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC EMS: Beacon Disconnected." + --#SUMMARY "Beacon Disconnected." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 239 + +emsBeaconOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A EMS beacon has gone on. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC EMS: Beacon On." + --#SUMMARY "Beacon On." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 240 + +emsBeaconOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A EMS beacon has gone off. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC EMS: Beacon Off." + --#SUMMARY "Beacon Off." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 241 + +emsMajorAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "SEVERE: A Major Alarm is present in the EMS. + The first argument is the EMS serial number. + The second argument is the EMS name." + --#TYPE "APC EMS: Major Alarm." + --#SUMMARY "Major Alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 242 + +emsMajorAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Major Alarm condition has been cleared in the EMS. + The first argument is the EMS serial number. + The second argument is the EMS name." + --#TYPE "APC EMS: Major Alarm Cleared." + --#SUMMARY "Major Alarm Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 243 + +emsMinorAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "SEVERE: A Minor Alarm is present in the EMS. + The first argument is the EMS serial number. + The second argument is the EMS name." + --#TYPE "APC EMS: Minor Alarm." + --#SUMMARY "Minor Alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 244 + +emsMinorAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Minor Alarm condition has been cleared in the EMS. + The first argument is the EMS serial number. + The second argument is the EMS name." + --#TYPE "APC EMS: Minor Alarm Cleared." + --#SUMMARY "Minor Alarm Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 245 + +emsOutletStateAbnormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsOutletStatusOutletIndex, emsOutletStatusOutletName, + emsOutletStatusOutletState, emsOutletStatusOutletNormalState, mtrapargsString } + DESCRIPTION + "WARNING: An outlet on the EMS has changed to its abnormal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the outlet number. + The fourth argument is the outlet name. + The fifth argument is the current outlet state (1=ON, 2=OFF). + The sixth argument is the configured normal outlet state (1=ON, 2=OFF)." + --#TYPE "APC EMS: Outlet has changed to its abnormal state." + --#SUMMARY "Outlet has changed to its abnormal state." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 246 + +emsOutletStateNormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsOutletStatusOutletIndex, emsOutletStatusOutletName, + emsOutletStatusOutletState, emsOutletStatusOutletNormalState, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet on the EMS has changed to its normal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the outlet number. + The fourth argument is the outlet name. + The fifth argument is the current outlet state (1=ON, 2=OFF). + The sixth argument is the configured normal outlet state (1=ON, 2=OFF)." + --#TYPE "APC EMS: Outlet has changed to its normal state." + --#SUMMARY "Outlet has changed to its normal state." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 247 + +emsInputContactStateAbnormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsInputContactStatusInputContactIndex, + emsInputContactStatusInputContactName, emsInputContactStatusInputContactState, + emsInputContactStatusInputContactNormalState, mtrapargsString } + DESCRIPTION + "WARNING: An input contact on the EMS has changed to its abnormal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the input contact number. + The fourth argument is the input contact name. + The fifth argument is the input contact state (1=CLOSED, 2=OPEN). + The sixth argument is the configured normal input contact state (1=CLOSED, 2=OPEN)." + --#TYPE "APC EMS: Input contact has changed to its abnormal state." + --#SUMMARY "Input contact has changed to its abnormal state." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 248 + +emsInputContactStateNormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsInputContactStatusInputContactIndex, + emsInputContactStatusInputContactName, emsInputContactStatusInputContactState, + emsInputContactStatusInputContactNormalState, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An input contact on the EMS has changed to its normal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the input contact number. + The fourth argument is the input contact name. + The fifth argument is the input contact state (1=CLOSED, 2=OPEN). + The sixth argument is the configured normal input contact state (1=CLOSED, 2=OPEN)." + --#TYPE "APC EMS: Input contact has changed to its normal state." + --#SUMMARY "Input contact has changed to its normal state." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 249 + +emsOutputRelayStateAbnormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsOutputRelayStatusOutputRelayIndex, + emsOutputRelayStatusOutputRelayName, emsOutputRelayStatusOutputRelayState, + emsOutputRelayStatusOutputRelayNormalState, mtrapargsString } + DESCRIPTION + "WARNING: An output relay on the EMS has changed to its abnormal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the output relay number. + The fourth argument is the output relay name. + The fifth argument is the current output relay state (1=CLOSED, 2=OPEN). + The sixth argument is the configured normal output relay state (1=CLOSED, 2=OPEN)." + --#TYPE "APC EMS: Output Relay has changed to its abnormal state." + --#SUMMARY "Output Relay has changed to its abnormal state." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 250 + +emsOutputRelayStateNormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsOutputRelayStatusOutputRelayIndex, + emsOutputRelayStatusOutputRelayName, emsOutputRelayStatusOutputRelayState, + emsOutputRelayStatusOutputRelayNormalState, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An output relay on the EMS has changed to its normal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the output relay number. + The fourth argument is the output relay name. + The fifth argument is the current output relay state (1=CLOSED, 2=OPEN). + The sixth argument is the configured normal output relay state (1=CLOSED, 2=OPEN)." + --#TYPE "APC EMS: Output Relay has changed to its normal state." + --#SUMMARY "Output Relay has changed to its normal state." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 251 + +emsDeviceConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A device configuration change has been made on the EMS. + The first argument is the EMS serial number. + The second argument is the EMS name." + --#TYPE "APC: A device configuration change on a EMS." + --#SUMMARY "A device configuration change has been made on a EMS." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 252 + +envHighTempThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: High temperature threshold violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: High temperature threshold violation." + --#SUMMARY "High temperature threshold violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 253 + +envHighTempThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: High temperature threshold violation cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: High temperature threshold violation cleared." + --#SUMMARY "High temperature threshold violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 254 + +envLowTempThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Low temperature threshold violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Low temperature threshold violation." + --#SUMMARY "Low temperature threshold violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 255 + +envLowTempThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Low temperature threshold violation cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Low temperature threshold violation cleared." + --#SUMMARY "Low temperature threshold violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 256 + +envHighHumidityThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeHumidity, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: High humidity threshold violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current humidity + The fourth argument is the probe number. + The fifth argument is the probe name." + --#TYPE "APC ENV: High humidity threshold violation." + --#SUMMARY "High humidity threshold violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 257 + +envHighHumidityThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeHumidity, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: High humidity threshold violation cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current humidity. + The fourth argument is the probe number. + The fifth argument is the probe name." + --#TYPE "APC ENV: High humidity threshold violation cleared." + --#SUMMARY "High humidity threshold violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 258 + +envLowHumidityThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeHumidity, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Low humidity threshold violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current humidity + The fourth argument is the probe number. + The fifth argument is the probe name." + --#TYPE "APC ENV: Low humidity threshold violation." + --#SUMMARY "Low humidity threshold violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 259 + +envLowHumidityThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeHumidity, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Low humidity threshold violation cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current humidity. + The fourth argument is the probe number. + The fifth argument is the probe name." + --#TYPE "APC ENV: Low humidity threshold violation cleared." + --#SUMMARY "Low humidity threshold violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 260 + + +-- Switched and Metered Rack PDU Traps + +rPDUCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Communication with a Rack PDU has been established. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC Rack PDU: Communication established." + --#SUMMARY "Communication with a Rack PDU established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 266 + +rPDUCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, mtrapargsString } + DESCRIPTION + "SEVERE: Communication with a Rack PDU has been lost. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC Rack PDU: Communication lost." + --#SUMMARY "Communication with a Rack PDU has been lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 267 + +rPDUOutletOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDUOutletControlIndex, rPDUOutletControlOutletName, + mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet on a Switched Rack PDU has turned on. + The first argument is the serial number. + The second argument is the device name. + The third argument is the outlet index number. + The fourth argument is the outlet name." + --#TYPE "APC Switched Rack PDU: An outlet has turned on." + --#SUMMARY "An outlet on a Switched Rack PDU has turned on." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 268 + +rPDUOutletOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDUOutletControlIndex, rPDUOutletControlOutletName, + mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet on a Switched Rack PDU has turned off. + The first argument is the serial number. + The second argument is the device name. + The third argument is the outlet index number. + The fourth argument is the outlet name." + --#TYPE "APC Switched Rack PDU: An outlet has turned off." + --#SUMMARY "An outlet on a Switched Rack PDU has turned off." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 269 + +rPDUDeviceConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A device configuration change has been made on a + Rack PDU. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC Rack PDU: Device configuration change made." + --#SUMMARY "Device configuration change has been made on a Rack PDU." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 270 + +rPDUOutletConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDUOutletControlIndex, rPDUOutletControlOutletName, + mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An outlet configuration change has been made on a + Switched Rack PDU. + The first argument is the serial number. + The second argument is the device name. + The third argument is the outlet index number. + The fourth argument is the outlet name." + --#TYPE "APC Switched Rack PDU: Outlet configuration change made." + --#SUMMARY "Outlet configuration change has been made on a Switched Rack PDU." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 271 + +rPDULowLoad TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "WARNING: A Rack PDU has violated the low load threshold. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC Rack PDU: Violation of low load threshold." + --#SUMMARY "A Rack PDU has violated the low load threshold." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 272 + +rPDULowLoadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The low load condition on a Rack PDU has been + cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC Rack PDU: Low load condition cleared." + --#SUMMARY "The low load condition on a Rack PDU has been cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 273 + +rPDUNearOverload TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "WARNING: A Rack PDU is near an overload condition. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC Rack PDU: Near an overload condition." + --#SUMMARY "A Rack PDU is near an overload condition." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 274 + +rPDUNearOverloadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The near overload condition on a Rack PDU has + been cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC Rack PDU: Near overload condition has cleared." + --#SUMMARY "Rack PDU near overload condition has cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 275 + +rPDUOverload TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "SEVERE: A Rack PDU is in an overload condition. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC Rack PDU: Overload condition." + --#SUMMARY "A Rack PDU is in an overload condition." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 276 + +rPDUOverloadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadStatusPhaseNumber, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The overload condition on a Rack PDU has been + cleared. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase number." + --#TYPE "APC Rack PDU: Overload condition has cleared." + --#SUMMARY "The overload condition on a Rack PDU has cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 277 + +rPDUPowerSupply1Fail TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, mtrapargsString } + DESCRIPTION + "SEVERE: Power Supply 1 on Rack PDU is in FAIL state. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC Rack PDU: Power Supply 1 is in FAIL state." + --#SUMMARY "Power Supply 1 on Rack PDU is in FAIL state." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 278 + +rPDUPowerSupply1Ok TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Power Supply 1 on Rack PDU is operating normally. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC Rack PDU: Power Supply 1 is operating normally." + --#SUMMARY "Power Supply 1 on Rack PDU is operating normally." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 279 + +rPDUPowerSupply2Fail TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, mtrapargsString } + DESCRIPTION + "SEVERE: Power Supply 2 on Rack PDU is in FAIL state. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC Rack PDU: Power Supply 2 is in FAIL state." + --#SUMMARY "Power Supply 2 on Rack PDU is in FAIL state." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 280 + +rPDUPowerSupply2Ok TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Power Supply 2 on Rack PDU is operating normally. + The first argument is the serial number. + The second argument is the device name." + --#TYPE "APC Rack PDU: Power Supply 2 is operating normally." + --#SUMMARY "Power Supply 2 on Rack PDU is operating normally." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 281 + +rPDUPhaseConfigChange TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDULoadPhaseConfigIndex, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A phase configuration change has been made on a + Rack PDU. + The first argument is the serial number. + The second argument is the device name. + The third argument is the phase index number." + --#TYPE "APC Rack PDU: Phase configuration change made." + --#SUMMARY "Phase configuration change has been made on a Rack PDU." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 282 + +rPDUCancelPendingCommand TRAP-TYPE + ENTERPRISE apc + VARIABLES { rPDUIdentSerialNumber, rPDUIdentName, + rPDUOutletControlIndex, rPDUOutletControlOutletName, + mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A cancel pending command has been made on a + Switched Rack PDU. + The first argument is the serial number. + The second argument is the device name. + The third argument is the outlet index number (0 indicates all outlets). + The fourth argument is the outlet name (or device name if all outlets)." + --#TYPE "APC Switched Rack PDU: Cancel Pending Command made." + --#SUMMARY "A Cancel Pending Command has been made on a Switched Rack PDU." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 283 + +aruAlinkCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Remote ARU Communication Established. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: Communication Established." + --#SUMMARY "Communication Established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 284 + +aruAlinkCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "SEVERE: Remote ARU Communication Lost. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: Communication Lost." + --#SUMMARY "Communication Lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 285 + +aruFanFail TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "SEVERE: Remote ARU Fan Fail. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: Fan Fail." + --#SUMMARY "Fan Fail." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 286 + +aruFanFailCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Remote ARU Fan Fail Cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: Fan Fail Cleared." + --#SUMMARY "Fan Fail Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 287 + +aruSmokeAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "SEVERE: Remote ARU Smoke Alarm. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: Smoke Alarm." + --#SUMMARY "Smoke Alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 288 + +aruSmokeAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Remote ARU Smoke Alarm Cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: Smoke Alarm Cleared." + --#SUMMARY "Smoke Alarm Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 289 + +aruHighTemperatureAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "SEVERE: Remote ARU High Temperature Alarm. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: High Temperature Alarm." + --#SUMMARY "High Temperature Alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 290 + +aruHighTemperatureAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Remote ARU High Temperature Alarm Cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: High Temperature Alarm Cleared." + --#SUMMARY "High Temperature Alarm Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 291 + +aruExhaustTemperatureAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "SEVERE: Remote ARU Exhaust Temperature Alarm. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: Exhaust Temperature Alarm." + --#SUMMARY "Exhaust Temperature Alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 292 + +aruExhaustTemperatureAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + rARUStatusAruIndex, rARUStatusAruName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Remote ARU Exhaust Temperature Alarm Cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the ARU number. + The fourth argument is the ARU name." + --#TYPE "APC ARU: Exhaust Temperature Alarm Cleared." + --#SUMMARY "Exhaust Temperature Alarm Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 293 + +envAlinkCommunicationEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Remote Probe Communication Established. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the probe number. + The fourth argument is the probe name." + --#TYPE "APC ENV: Communication Established." + --#SUMMARY "Communication Established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 294 + +envAlinkCommunicationLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Remote Probe Communication Lost. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the probe number. + The fourth argument is the probe name." + --#TYPE "APC ENV: Communication Lost." + --#SUMMARY "Communication Lost." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 295 + +emsAlinkPowerOverload TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "SEVERE: Alink Power Overload. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC EMS: Alink Power Overload." + --#SUMMARY "Alink Power Overload." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 296 + +emsAlinkPowerOverloadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Alink Power Overload Cleared. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC EMS: Alink Power Overload Cleared." + --#SUMMARY "Alink Power Overload Cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 297 + +upsOutletGroupTurnedOn TRAP-TYPE + ENTERPRISE apc + VARIABLES { upsOutletGroupControlIndex, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The specified Outlet Group turned on." + --#TYPE "APC UPS: Outlet Group turned on." + --#SUMMARY "Outlet Group turned on" + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 298 + +upsOutletGroupTurnedOff TRAP-TYPE + ENTERPRISE apc + VARIABLES { upsOutletGroupControlIndex, mtrapargsString } + DESCRIPTION + "WARNING: The specified Outlet Group turned off." + --#TYPE "APC UPS: Outlet Group turned off." + --#SUMMARY "Outlet Group turned off." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 299 + +smwCriticalCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsGauge, mtrapargsString } + DESCRIPTION + "SEVERE: A Symmetra MW UPS critical condition has been detected. + The first variable is the fault condition." + --#TYPE "APC Symmetra MW UPS: A critical condition has been detected." + --#SUMMARY "A critical condition has been detected." + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 300 + +smwCriticalConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsGauge, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Symmetra MW UPS critical condition has been cleared. + The first variable is the fault condition." + --#TYPE "APC Symmetra MW UPS: A critical condition has been cleared." + --#SUMMARY "A critical condition has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 301 + +smwWarningCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsGauge, mtrapargsString } + DESCRIPTION + "WARNING: A Symmetra MW UPS warning condition has been detected. + The first variable is the fault condition." + --#TYPE "APC Symmetra MW UPS: A warning condition has been detected." + --#SUMMARY "A warning condition has been detected." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 302 + +smwWarningConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsGauge, mtrapargsString } + DESCRIPTION + "WARNING: A Symmetra MW UPS warning condition has been cleared. + The first variable is the fault condition." + --#TYPE "APC Symmetra MW UPS: A warning condition has been cleared." + --#SUMMARY "A warning condition has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 303 + +smwInformationalCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsGauge, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Symmetra MW UPS informational condition has been detected. + The first variable is the fault condition." + --#TYPE "APC Symmetra MW UPS: Informational condition detected." + --#SUMMARY "An informational condition has been detected." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 304 + +smwInformationalConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsGauge, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Symmetra MW UPS informational condition has been cleared. + The first variable is the fault condition." + --#TYPE "APC Symmetra MW UPS: Informational condition cleared." + --#SUMMARY "An informational condition has been cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 305 + +airCriticalCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: An Air critical condition was detected. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC Air: A critical condition was detected. " + --#SUMMARY "A critical condition was detected. " + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 306 + +airCriticalConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An Air critical condition was cleared. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC Air: A critical condition was cleared. " + --#SUMMARY "A critical condition was cleared. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 307 + +airWarningCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: An Air warning condition was detected. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC Air: A warning condition was detected. " + --#SUMMARY "A warning condition was detected. " + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 308 + +airWarningConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: An Air warning condition was cleared. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC Air: A warning condition was cleared. " + --#SUMMARY "A warning condition was cleared. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 309 + +airInformationalCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An Air informational condition was detected. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC Air: Informational condition detected. " + --#SUMMARY "An informational condition was detected. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 310 + +airInformationalConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An Air informational condition was cleared. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC Air: Informational condition was cleared. " + --#SUMMARY "An informational condition was cleared. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 311 + +-- xPDU Traps (part 1) + +xPDUInputVoltageLowAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "WARNING: Three-phase input voltage to the device is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase + (1=L1-N, 2=L2-N, 3=L3-N, 4=unused, 5=L1-L2, 6=L2-L3, 7=L3-L1). + The fourth argument is the measured voltage in tenths of Volts. + The fifth argument is the threshold, in tenths of Volts, from which the alarm was generated." + --#TYPE "APC XPDU: Main input voltage out-of-range alarm." + --#SUMMARY "Input voltage is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 312 + +xPDUInputVoltageLowAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Three-phase input voltage to the device is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N, 4=unused, 5=L1-L2, 6=L2-L3, 7=L3-L1). + The fourth argument is the measured voltage in tenths of Volts." + --#TYPE "APC XPDU: Main input voltage back in range." + --#SUMMARY "Input voltage in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 313 + + +xPDUInputVoltageHighAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "WARNING: Three-phase input voltage to the device is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase + (1=L1-N, 2=L2-N, 3=L3-N, 4=unused, 5=L1-L2, 6=L2-L3, 7=L3-L1). + The fourth argument is the measured voltage in tenths of Volts. + The fifth argument is the threshold, in tenths of Volts, above which the alarm was generated." + --#TYPE "APC XPDU: Main input voltage out-of-range alarm." + --#SUMMARY "Input voltage is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 314 + +xPDUInputVoltageHighAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Three-phase input voltage to the device is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N, 4=unused, 5=L1-L2, 6=L2-L3, 7=L3-L1). + The fourth argument is the measured voltage in tenths of Volts." + --#TYPE "APC XPDU: Main input voltage back in range." + --#SUMMARY "Input voltage in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 315 + +xPDUBypassVoltageLowAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "WARNING: Three-phase bypass input voltage to the device is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N). + The fourth argument is the measured voltage in tenths of Volts. + The fifth argument is the threshold, in tenths of Volts, from which the alarm was generated." + --#TYPE "APC XPDU: Bypass input voltage out-of-range alarm." + --#SUMMARY "Bypass input voltage is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 316 + +xPDUBypassVoltageLowAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Three-phase bypass input voltage to the device is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N). + The fourth argument is the measured voltage in tenths of Volts." + --#TYPE "APC XPDU: Bypass input voltage back in range." + --#SUMMARY "Bypass input voltage in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 317 + +xPDUBypassVoltageHighAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "WARNING: Three-phase bypass input voltage to the device is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N). + The fourth argument is the measured voltage in tenths of Volts. + The fifth argument is the threshold, in tenths of Volts, above which the alarm was generated." + --#TYPE "APC XPDU: Bypass input voltage out-of-range alarm." + --#SUMMARY "Bypass input voltage is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 318 + +xPDUBypassVoltageHighAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Three-phase bypass input voltage to the device is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N). + The fourth argument is the measured voltage in tenths of Volts." + --#TYPE "APC XPDU: Bypass input voltage back in range." + --#SUMMARY "Bypass input voltage in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 319 + +xPDUOutputVoltageLowAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "WARNING: The device three-phase output voltage of the device is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N). + The fourth argument is the measured voltage in tenths of Volts. + The fifth argument is the threshold, in tenths of Volts, from which the alarm was generated." + --#TYPE "APC XPDU: Output voltage out-of-range alarm." + --#SUMMARY "Output voltage is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 320 + +xPDUOutputVoltageLowAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices three-phase output voltage is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N). + The fourth argument is the measured voltage in tenths of Volts." + --#TYPE "APC XPDU: Output voltage back in range." + --#SUMMARY "Output voltage in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 321 + +xPDUOutputVoltageHighAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "WARNING: The device three-phase output voltage of the device is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N). + The fourth argument is the measured voltage in tenths of Volts. + The fifth argument is the threshold, in tenths of Volts, above which the alarm was generated." + --#TYPE "APC XPDU: Output voltage out-of-range alarm." + --#SUMMARY "Output voltage is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 322 + +xPDUOutputVoltageHighAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices three-phase output voltage is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N). + The fourth argument is the measured voltage in tenths of Volts." + --#TYPE "APC XPDU: Output voltage back in range." + --#SUMMARY "Output voltage in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 323 + +xPDUOutputCurrentLowAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "SEVERE: The devices three-phase load current is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3). + The fourth argument is the measured current in tenths of Amps. + The fifth argument is the threshold, in Amps, from which the alarm was generated." + --#TYPE "APC XPDU: Output (load) current out-of-range alarm." + --#SUMMARY "Output current is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 324 + +xPDUOutputCurrentLowAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices three-phase output current is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3). + The fourth argument is the measured current in tenths of Amps." + --#TYPE "APC XPDU: Output (load) current back in range." + --#SUMMARY "Output current in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 325 + +xPDUOutputCurrentHighAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "SEVERE: The devices three-phase load current is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3). + The fourth argument is the measured current in tenths of Amps. + The fifth argument is the threshold, in Amps, above which the alarm was generated." + --#TYPE "APC XPDU: Output (load) current out-of-range alarm." + --#SUMMARY "Output current is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 326 + +xPDUOutputCurrentHighAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices three-phase output current is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3). + The fourth argument is the measured current in tenths of Amps." + --#TYPE "APC XPDU: Output (load) current back in range." + --#SUMMARY "Output current in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 327 + +xPDUOutputFrequencyAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The devices output frequency is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the frequency deviation from the nominal in tenths of Hertz." + --#TYPE "APC XPDU: Output frequency out-of-range alarm." + --#SUMMARY "Output frequency is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 328 + +xPDUOutputFrequencyAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices output frequency is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Output frequency back in range." + --#SUMMARY "Output frequency in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 329 + +xPDUSystemGroundCurrentAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The devices earth ground current is over the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the measured current in tenths of Amps." + --#TYPE "APC XPDU: Earth ground current over range alarm." + --#SUMMARY "Earth ground current is over limit." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 330 + +xPDUSystemGroundCurrentAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices earth ground current is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the measured current in tenths of Amps." + --#TYPE "APC XPDU: Earth ground current back in range." + --#SUMMARY "Earth ground current in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 331 + +xPDUInputContactStateAbnormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsString02, mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "WARNING: A user input contact on the device has changed to its abnormal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the input contact number. + The fourth argument is the input contact name. + The fifth argument is the input contact state (1=OPEN, 2=CLOSED). + The sixth argument is the configured normal input contact state (1=OPEN, 2=CLOSED)." + --#TYPE "APC XPDU: Input contact has changed to its abnormal state." + --#SUMMARY "Input contact has changed to its abnormal state." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 332 + +xPDUInputContactStateNormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsString02, mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A user input contact on the device has changed to its normal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the input contact number. + The fourth argument is the input contact name. + The fifth argument is the input contact state (1=CLOSED, 2=OPEN). + The sixth argument is the configured normal input contact state (1=OPEN, 2=CLOSED)." + --#TYPE "APC XPDU: Input contact has changed to its normal state." + --#SUMMARY "Input contact has changed to its normal state." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 333 + +xPDUOutputRelayStateAbnormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsString02, mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "WARNING: An Output Relay on the device has changed to its abnormal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the Output Relay number. + The fourth argument is the Output Relay name. + The fifth argument is the current Output Relay state (1=OPEN, 2=CLOSED). + The sixth argument is the configured normal Output Relay state (1=OPEN, 2=CLOSED)." + --#TYPE "APC XPDU: Output Relay has changed to its abnormal state." + --#SUMMARY "Output Relay has changed to its abnormal state." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 334 + +xPDUOutputRelayStateNormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsString02, mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: An Output Relay on the device has changed to its normal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the Output Relay number. + The fourth argument is the Output Relay name. + The fifth argument is the current Output Relay state (1=OPEN, 2=CLOSED). + The sixth argument is the configured normal Output Relay state (1=OPEN, 2=CLOSED)." + --#TYPE "APC XPDU: Output Relay has changed to its normal state." + --#SUMMARY "Output Relay has changed to its normal state." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 335 + +xPDUCoolingFanAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: The device's internal cooling fans have failed. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Cooling fan failure alarm." + --#SUMMARY "Cooling fan failure." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 336 + +xPDUCoolingFanAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The device's cooling fans are now functioning properly. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Cooling fan alarm cleared." + --#SUMMARY "Cooling fan alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 337 + +xPDUTransformerTempAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: The device's isolation transformer is over temperature. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Isolation transformer over temperature alarm." + --#SUMMARY "Transformer temp alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 338 + +xPDUTransformerTempAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The device's isolation transformer is no longer over temperature. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Isolation transformer over temperature alarm cleared." + --#SUMMARY "Transformer temp alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 339 + +xPDUBranchCurrentLowAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "SEVERE: The current in a branch circuit is outside the limits specified for that + branch circuit. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the panel position of the branch circuit (1-based index). + The fourth argument is the measured current in tenths of Amps. + The fifth argument is the threshold, in tenth of Amps, from which the alarm was generated." + --#TYPE "APC XPDU: Branch circuit current out-of-range alarm." + --#SUMMARY "Branch circuit current is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 340 + +xPDUBranchCurrentLowAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The current in a branch circuit is back within the limits + specified for that branch circuit. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the panel position of the branch circuit (1-based index). + The fourth argument is the measured current in tenths of Amps." + --#TYPE "APC XPDU: Branch circuit current back in range." + --#SUMMARY "Branch circuit current in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 341 + +xPDUBranchCurrentHighAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "SEVERE: The current in a branch circuit is outside the limits specified for that + branch circuit. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the panel position of the branch circuit (1-based index). + The fourth argument is the measured current in tenths of Amps. + The fifth argument is the threshold, in tenth of Amps, above which the alarm was generated." + --#TYPE "APC XPDU: Branch circuit current out-of-range alarm." + --#SUMMARY "Branch circuit current is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 342 + +xPDUBranchCurrentHighAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The current in a branch circuit is back within the limits + specified for that branch circuit. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the panel position of the branch circuit (1-based index). + The fourth argument is the measured current in tenths of Amps." + --#TYPE "APC XPDU: Branch circuit current back in range." + --#SUMMARY "Branch circuit current in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 343 + + +xPDUInternalCommError TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: There is an internal communication error in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Internal communication error." + --#SUMMARY "Internal communication error." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 344 + +emsHardwareStateAbnormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "SEVERE: The device's hardware is improperly configured and operating outside + normal bounds for the hardware. This can be caused by improper devices being + connected to the EMS ports or Alink Current limit detection." + --#TYPE "APC EMS: Hardware is in an abnormal state." + --#SUMMARY "Hardware is in an abnormal state." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 345 + +emsHardwareStateNormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The device's hardware is in its normal operational state. + The first argument is the host device serial number." + --#TYPE "APC EMS: Hardware is in a normal state." + --#SUMMARY "Hardware is in its normal state." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 346 + +ceSevereCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: A Custom Event severe condition was detected. + The first variable is the custom event text message. + The second variable is the custom event number." + --#TYPE "APC CustomEvent: A severe condition was detected. " + --#SUMMARY "A severe condition was detected. " + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 347 + +ceSevereConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Custom Event severe condition was cleared. + The first variable is the custom event text message. + The second variable is the custom event number." + --#TYPE "APC CustomEvent: A severe condition was cleared. " + --#SUMMARY "A severe condition was cleared. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 348 + +ceWarningCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: A Custom Event warning condition was detected. + The first variable is the custom event text message. + The second variable is the custom event number." + --#TYPE "APC CustomEvent: A warning condition was detected. " + --#SUMMARY "A warning condition was detected. " + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 349 + +ceWarningConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Custom Event warning condition was cleared. + The first variable is the custom event text message. + The second variable is the custom event number." + --#TYPE "APC CustomEvent: A warning condition was cleared. " + --#SUMMARY "A warning condition was cleared. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 350 + +ceInformationalCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Custom Event informational condition was detected. + The first variable is the custom event text message. + The second variable is the custom event number." + --#TYPE "APC CustomEvent: Informational condition detected. " + --#SUMMARY "An informational condition was detected. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 351 + +ceInformationalConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Custom Event informational condition was cleared. + The first variable is the custom event text message. + The second variable is the custom event number." + --#TYPE "APC CustomEvent: Informational condition was cleared. " + --#SUMMARY "An informational condition was cleared. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 352 + +upsInternalOverTemperature TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "WARNING: The internal over temperature condition exists." + --#TYPE "APC UPS: The internal over temperature condition exists." + --#SUMMARY "The internal over temperature condition exists." + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 353 + +upsInternalOverTemperatureCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The internal over temperature condition cleared." + --#TYPE "APC UPS: The internal over temperature condition cleared." + --#SUMMARY "The internal over temperature condition cleared." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 354 + +upsMpuReset TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The MPU has been reset." + --#TYPE "APC UPS: The MPU has been reset." + --#SUMMARY "The MPU has been reset." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 355 + +upsOutputSwitchClosed TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The Output Switch is closed." + --#TYPE "APC UPS: The Output Switch is closed." + --#SUMMARY "The Output Switch is closed." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 356 + +upsOutputSwitchOpened TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The Output Switch is open." + --#TYPE "APC UPS: The Output Switch is open." + --#SUMMARY "The Output Switch is open." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 357 + +upsCalibrationStackChanged TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A calibration value in the stack was changed." + --#TYPE "APC UPS: A calibration value in the stack was changed." + --#SUMMARY "A calibration value in the stack was changed." + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 358 + + +-- Upgraded EMS now has more env traps + +envMaxTempThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Max temperature threshold violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Max temperature threshold violation." + --#SUMMARY "Max temperature threshold violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 359 + +envMaxTempThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Max temperature threshold violation cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Max temperature threshold violation cleared." + --#SUMMARY "Max temperature threshold violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 360 + +envMinTempThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Min temperature threshold violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Min temperature threshold violation." + --#SUMMARY "Min temperature threshold violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 361 + +envMinTempThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Min temperature threshold violation cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Min temperature threshold violation cleared." + --#SUMMARY "Min temperature threshold violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 362 + +envMaxHumidityThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeHumidity, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Max humidity threshold violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current humidity + The fourth argument is the probe number. + The fifth argument is the probe name." + --#TYPE "APC ENV: Max humidity threshold violation." + --#SUMMARY "Max humidity threshold violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 363 + +envMaxHumidityThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeHumidity, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Max humidity threshold violation cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current humidity. + The fourth argument is the probe number. + The fifth argument is the probe name." + --#TYPE "APC ENV: Max humidity threshold violation cleared." + --#SUMMARY "Max humidity threshold violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 364 + +envMinHumidityThresholdViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeHumidity, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Min humidity threshold violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current humidity + The fourth argument is the probe number. + The fifth argument is the probe name." + --#TYPE "APC ENV: Min humidity threshold violation." + --#SUMMARY "Min humidity threshold violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 365 + +envMinHumidityThresholdViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeHumidity, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Min humidity threshold violation cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current humidity. + The fourth argument is the probe number. + The fifth argument is the probe name." + --#TYPE "APC ENV: Min humidity threshold violation cleared." + --#SUMMARY "Min humidity threshold violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 366 + +envSTIncTempRateViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Short-term increasing temperature rate violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Short-term inc. temp rate violation." + --#SUMMARY "Short-term inc. temp rate violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 367 + +envSTIncTempRateViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Short-term increasing temperature rate cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Short-term inc. temp rate violation cleared." + --#SUMMARY "Short-term inc. temp rate violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 368 + +envSTDecTempRateViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Short-term decreasing temperature rate violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Short-term dec. temp rate violation." + --#SUMMARY "Short-term dec. temp rate violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 369 + +envSTDecTempRateViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Short-term decreasing temperature rate cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Short-term dec. temp rate violation cleared." + --#SUMMARY "Short-term dec. temp rate violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 370 + +envLTIncTempRateViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Long-term increasing temperature rate violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Long-term inc. temp rate violation." + --#SUMMARY "Long-term inc. temp rate violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 371 + +envLTIncTempRateViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Long-term increasing temperature rate cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Long-term inc. temp rate violation cleared." + --#SUMMARY "Long-term inc. temp rate violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 372 + +envLTDecTempRateViolation TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "SEVERE: Long-term decreasing temperature rate violated on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Long-term dec. temp rate violation." + --#SUMMARY "Long-term dec. temp rate violation." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 373 + +envLTDecTempRateViolationCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { emsIdentSerialNumber, emsIdentEMSName, emsProbeStatusProbeTemperature, emsStatusSysTempUnits, + emsProbeStatusProbeIndex, emsProbeStatusProbeName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Long-term decreasing temperature rate cleared on the probe. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the current temperature. + The fourth argument is the temperature scale. + The fifth argument is the probe number. + The sixth argument is the probe name." + --#TYPE "APC ENV: Long-term dec. temp rate violation cleared." + --#SUMMARY "Long-term dec. temp rate violation cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 374 + +-- Battery Management System Traps + +bmsCriticalCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: A Battery Management System critical condition was detected. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC BMS: A critical condition was detected. " + --#SUMMARY "A critical condition was detected. " + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 375 + +bmsCriticalConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Battery Management System critical condition was cleared. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC BMS: A critical condition was cleared. " + --#SUMMARY "A critical condition was cleared. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 376 + +bmsWarningCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: A Battery Management System warning condition was detected. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC BMS: A warning condition was detected. " + --#SUMMARY "A warning condition was detected. " + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 377 + +bmsWarningConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: A Battery Management System warning condition was cleared. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC BMS: A warning condition was cleared. " + --#SUMMARY "A warning condition was cleared. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 378 + +bmsInformationalCondition TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Battery Management System informational condition was detected. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC BMS: Informational condition detected. " + --#SUMMARY "An informational condition was detected. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 379 + +bmsInformationalConditionCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsString02, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A Battery Management System informational condition was cleared. + The first variable is the error condition text message. + The second variable is the error number." + --#TYPE "APC BMS: Informational condition was cleared. " + --#SUMMARY "An informational condition was cleared. " + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 380 + +-- xATS Traps + +xATSOutputVoltageLowAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "SEVERE: The device three-phase output voltage of the device is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N, 4=unused, 5=L1-L2, 6=L2-L3, 7=L3-L1). + The fourth argument is the measured voltage in tenths of Volts. + The fifth argument is the threshold, in tenths of Volts, from which the alarm was generated." + --#TYPE "APC XATS: Output voltage out-of-range alarm." + --#SUMMARY "Output voltage is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 381 + +xATSOutputVoltageLowAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices three-phase output voltage is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N, 4=unused, 5=L1-L2, 6=L2-L3, 7=L3-L1). + The fourth argument is the measured voltage in tenths of Volts." + --#TYPE "APC XATS: Output voltage back in range." + --#SUMMARY "Output voltage in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 382 + +xATSOutputVoltageHighAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "SEVERE: The device three-phase output voltage of the device is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N, 4=unused, 5=L1-L2, 6=L2-L3, 7=L3-L1). + The fourth argument is the measured voltage in tenths of Volts. + The fifth argument is the threshold, in tenths of Volts, above which the alarm is generated." + --#TYPE "APC XATS: Output voltage out-of-range alarm." + --#SUMMARY "Output voltage is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 383 + +xATSOutputVoltageHighAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices three-phase output voltage is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1-N, 2=L2-N, 3=L3-N, 4=unused, 5=L1-L2, 6=L2-L3, 7=L3-L1). + The fourth argument is the measured voltage in tenths of Volts." + --#TYPE "APC XATS: Output voltage back in range." + --#SUMMARY "Output voltage in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 384 + +xATSOutputCurrentLowAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "SEVERE: The devices three-phase load current is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3, 4=Neutral, 5=L1-2, 6=L2-3, 7=L3-1). + The fourth argument is the measured current in Amps. + The fifth argument is the threshold, in Amps, from which the alarm was generated." + --#TYPE "APC XATS: Output (load) current out-of-range alarm." + --#SUMMARY "Output current is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 385 + +xATSOutputCurrentLowAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices three-phase output current is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3, 4=Neutral). + The fourth argument is the measured current in Amps." + --#TYPE "APC XATS: Output (load) current back in range." + --#SUMMARY "Output current in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 386 + +xATSOutputCurrentHighAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "SEVERE: The devices three-phase load current is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3, 4=Neutral). + The fourth argument is the measured current in Amps. + The fifth argument is the threshold, in Amps, from which the alarm was generated." + --#TYPE "APC XATS: Output (load) current out-of-range alarm." + --#SUMMARY "Output current is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 387 + +xATSOutputCurrentHighAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices three-phase output current is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3, 4=Neutral). + The fourth argument is the measured current in Amps." + --#TYPE "APC XATS: Output (load) current back in range." + --#SUMMARY "Output current in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 388 + + +xATSOutputFrequencyAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "SEVERE: The devices output frequency is outside the specified limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the frequency deviation from the nominal in tenths of Hertz. + The fourth argument is the frequency deviation threshold in tenths of Hertz, + from which the alarm was generated." + --#TYPE "APC XATS: Output frequency out-of-range alarm." + --#SUMMARY "Output frequency is out-of-range." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 389 + +xATSOutputFrequencyAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The devices output frequency is back within the specified limits. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Output frequency back in range." + --#SUMMARY "Output frequency in range." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 390 + +xATSInternalCommError TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: There is an internal communication error in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Internal communication error." + --#SUMMARY "Internal communication error." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 391 + +xATSInternalCommErrorCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Internal communication has been restored. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Internal Communication error cleared." + --#SUMMARY "ATS Communication error cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 392 + +xATSDataCommMismatchError TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: A data incompatibility exists within the device. This + is typically the result of mismatches between firmware revisions + of the transfer switch controller and the Network Management interface. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Data mismatch error." + --#SUMMARY "ATS data mismatch error." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 393 + +xATSDataCommMismatchErrorCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The internal data incompatibility has been resolved. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: data mismatch error cleared." + --#SUMMARY "ATS data mismatch error cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 394 + +xATSGenCommLost TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "WARNING: The XATS cannot communicate with the generator. + This will make unavailable all the xATSGenerator OIDs. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: No communication with generator." + --#SUMMARY "ATS/Generator communication lost." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 395 + +xATSGenCommEstablished TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The XATS has established communication with the generator. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Communication with generator established." + --#SUMMARY "ATS/generator communication established." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 396 + +xATSNeutralPosition TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsString } + DESCRIPTION + "WARNING: XATS has transferred to neutral position. + In this position neither Source 1 nor Source 2 is selected, + and the XATS will have no output voltage. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the mode in which the switch is operating + (1=Auto, 2=Not-in-Auto, Abnormal Condition 3=Not-in-Auto, manual)." + --#TYPE "APC XATS: Transferred to the neutral (no output power) position." + --#SUMMARY "Transferred to neutral." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 397 + +xATSSwitchTransferEvent TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: XATS has transferred from one source to the other. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the mode in which the switch is operating. + (1=Auto, 2=Not-in-Auto, Abnormal Condition 3=Not-in-Auto, manual). + The fourth argument is the input source selected (1=Source 1, 2=Source 2). + The fifth argument is type of transfer that took place. (1=Closed, 2=Open, 3=Unknown)" + --#TYPE "APC XATS: Transferred from Source-X to Source-Y." + --#SUMMARY "Source-to-Source transfer." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 398 + +xATSInternalATSFault TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: An internal XATS fault has been detected. + The XATS may have forced itself to not-in-auto mode (abnormal condition), + as indicated by the xATSSwitchStatusAutoSwitchOperationalMode OID. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument indicates the detected fault. + + 1=Cannot Close S1 + 2=Cannot Close S2 + 3=Cannot Open S1 + 4=Cannot Open S2 + 5=Cannot Trip Open S1 + 6=Cannot Trip Open S2 + 7=Start Contact Failure + 8=Voltage Sensing Failure" + + --#TYPE "APC XATS: Internal fault detected." + --#SUMMARY "ATS internal fault detected." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 399 + +xATSInternalATSFaultCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected internal XATS fault has been cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument indicates the detected fault. + + 1=Cannot Close S1 + 2=Cannot Close S2 + 3=Cannot Open S1 + 4=Cannot Open S2 + 5=Cannot Trip Open S1 + 6=Cannot Trip Open S2 + 7=Start Contact Failure + 8=Voltage Sensing Failure" + + --#TYPE "APC XATS: Internal fault cleared." + --#SUMMARY "ATS internal fault cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 400 + +xATSEngineStartAsserted TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The XATS has asserted the Engine Start contact. + This should result in the generator producing output voltage. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument indicates the reason that the start signal was asserted + 1=Unknown, 2=S1 Low Voltage, 3=S1 High Voltage, 4=S1 Line Imbalance, + 5=S1 Freq Range, 6=S1 Bad Rotation." + --#TYPE "APC XATS: Engine Start signal asserted." + --#SUMMARY "Engine Start asserted." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 401 + +xATSEngineStopAsserted TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The XATS has de-asserted the Engine Start contact. + This should result in the generator shutting down, and producing no output voltage. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Engine Stop signal asserted." + --#SUMMARY "Engine Stop asserted." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 402 + +xATSStartFailure TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: The generator failed to start. After assertion of the + Engine Start signal, the quality of Source 2 was not seen as good. + This alarm can be cleared using the xATSSwitchStatusClearLatchedAlarms OID. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument indicates the line quality at S2 + 1=Unknown, 2=S2 Low Voltage, 3=S2 High Voltage, 4=S2 Line Imbalance, + 4=S2 Freq Range, 5=S2 Bad Rotation." + --#TYPE "APC XATS: Generator failed to start alarm." + --#SUMMARY "Generator failed to start." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 403 + +xATSStopFailure TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "WARNING: The generator failed to stop. After de-assertion of the + Engine Start signal, the quality of Source 2 continued to be seen as good. + This alarm can be cleared using the xATSSwitchStatusClearLatchedAlarms OID. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Generator failed to stop alarm." + --#SUMMARY "Generator failed to stop." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 404 + +xATSNotInAutomaticMode TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: Automatic Transfer Switch is not in automatic mode. + The first argument is the host device serial number. + The second argument is the host device name. + The xATSSwitchStatusAutoSwitchStatus OID and the + xATSSwitchStatusAutoSwitchOperationalMode OID + can provide more information about the state of the XATS." + --#TYPE "APC XATS: XATS is not-in-automatic mode." + --#SUMMARY "ATS not in auto." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 405 + +xATSNotInAutomaticModeCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Automatic Transfer Switch is in automatic mode. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: XATS in auto mode." + --#SUMMARY "ATS in auto mode." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 406 + +xATSEpoTripped TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: The device's Emergency Power Off (EPO) circuit is tripped. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Emergency Power Off (EPO) tripped." + --#SUMMARY "EPO tripped." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 407 + +xATSEpoReset TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The device's Emergency Power Off (EPO) circuit has been + reset to the armed position. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Emergency Power Off (EPO) reset." + --#SUMMARY "EPO armed." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 408 + +xATSEpoTestMode TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "WARNING: The device's Emergency Power Off (EPO) circuit has been + switched back to the test position. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Emergency Power Off (EPO) in test mode." + --#SUMMARY "EPO disabled." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 409 + +xATSEpoArmed TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The device's Emergency Power Off (EPO) circuit has been + switched back to the armed position. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Emergency Power Off (EPO) enabled." + --#SUMMARY "EPO armed." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 410 + +xATSTestInitiated TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A scheduled test has been initiated. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the type of test initiated (1=scheduled, 2=manual)." + --#TYPE "APC XATS: Test initiated." + --#SUMMARY "Test initiated." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 411 + +xATSTestCancelled TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The scheduled test has been canceled + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the type of test initiated (1=scheduled, 2=manual)." + --#TYPE "APC XATS: Test cancelled." + --#SUMMARY "Test cancelled." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 412 + +xATSTestFailed TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: The initiated test has failed. + This alarm can be cleared using the xATSSwitchStatusClearLatchedAlarms OID. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Initiated test failed." + --#SUMMARY "Initiated test failed." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 413 + +xATSTestPassed TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The initiated test has passed + switched back to the armed position. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Initiated test passed." + --#SUMMARY "Initiated test passed." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 414 + +xATSInputContactStateAbnormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsString02, mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "SEVERE: A user input contact on the device has changed to its abnormal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the input contact number. + The fourth argument is the input contact name. + The fifth argument is the input contact state (1=OPEN, 2=CLOSED). + The sixth argument is the configured normal input contact state (1=OPEN, 2=CLOSED)." + --#TYPE "APC XATS: Input contact has changed to its abnormal state." + --#SUMMARY "Input contact has changed to its abnormal state." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 415 + +xATSInputContactStateNormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, + mtrapargsString02, mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A user input contact on the device has changed to its normal state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the input contact number. + The fourth argument is the input contact name. + The fifth argument is the input contact state (1=OPEN, 2=CLOSED). + The sixth argument is the configured normal input contact state (1=OPEN, 2=CLOSED)." + --#TYPE "APC XATS: Input contact has changed to its normal state." + --#SUMMARY "Input contact has changed to its normal state." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 416 + +xATSRemoteStartContactMismatch TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: The state of the generator's Remote Start input + and the ATS's Engine Start output do not match. + This indicates something wrong in the Engine Start wiring, + which must be corrected. This condition will prevent the + generator from being started when needed. + + (See also: xATSGeneratorStatusRemoteStart + and xATSSwitchStatusEngineStartSignal OIDs) + + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Generator/ATS start contact mismatch." + --#SUMMARY "Generator/ATS start contact mismatch." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 417 + +xATSRemoteStartContactMismatchCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Mismatch in the state of the generator's + Remote Start input and the ATS's Engine Start output as been resolved. + This indicates something wrong in the Engine Start wiring, + which must be corrected. This condition will prevent the + generator from being started when needed. + + (See also: xATSGeneratorStatusRemoteStart + and xATSSwitchStatusEngineStartSignal OIDs) + + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Generator/ATS start contact mismatch cleared." + --#SUMMARY "Generator/ATS start contact mismatch cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 418 + +xATSDoorOpenAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "WARNING: The XATS exterior panel door is open. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Panel door is open alarm." + --#SUMMARY "Panel door open alarm." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 419 + +xATSDoorOpenAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The external door to the device is closed. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Panel door open alarm cleared." + --#SUMMARY "Panel door open alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 420 + +xATSDCBackupAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "WARNING: The XATS's DC backup has been lost. The XATS will lose power + on Source 1 failure, causing the Engine Start signal to be asserted. + The XATS will then restart from Source 2. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: DC backup failure." + --#SUMMARY "ATS DC backup failure." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 421 + +xATSDCBackupAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: DC backup alarm has been cleared in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: DC backup alarm cleared." + --#SUMMARY "DC backup alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 422 + +-- xATS Generator Traps + +xATSGeneratorLowCoolantLevelAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Low coolant level has been detected in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low coolant level alarm." + --#SUMMARY "Generator low coolant level alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 423 + +xATSGeneratorLowCoolantLevelAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected low coolant level has been cleared in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low coolant level alarm cleared." + --#SUMMARY "Generator low coolant level alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 424 + +xATSGeneratorVeryLowCoolantLevelAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Very low coolant level has been detected in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator very low coolant level alarm." + --#SUMMARY "Generator very low coolant level alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 425 + +xATSGeneratorVeryLowCoolantLevelAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected Very low coolant level has been cleared in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator very low coolant level alarm cleared." + --#SUMMARY "Generator very low coolant level alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 426 + +xATSGeneratorHighCoolantTempAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: High coolant temperature has been detected in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator high coolant temperature alarm." + --#SUMMARY "Generator high coolant temperature alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 427 + +xATSGeneratorHighCoolantTempAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected high coolant temperature has been cleared in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator high coolant temperature alarm cleared." + --#SUMMARY "Generator high coolant temperature alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 428 + +xATSGeneratorVeryHighCoolantTempAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Very high coolant temperature has been detected in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator very high coolant temperature alarm." + --#SUMMARY "Generator very high coolant temperature alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 429 + +xATSGeneratorVeryHighCoolantTempAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The Very high coolant temperature condition has been cleared in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator very high coolant temperature alarm cleared." + --#SUMMARY "Generator very high coolant temperature alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 430 + +xATSGeneratorLowCoolantTempAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: Low coolant temperature has been detected in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low coolant temperature alarm." + --#SUMMARY "Generator low coolant temperature alarm." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 431 + +xATSGeneratorLowCoolantTempAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The low coolant temperature condition has been cleared in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low coolant temperature alarm cleared." + --#SUMMARY "Generator low coolant temperature alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 432 + +xATSGeneratorLowOilLevelAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: Low oil level has been detected in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low oil level alarm." + --#SUMMARY "Generator low oil level alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 433 + +xATSGeneratorLowOilLevelAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Low oil level alarm has been cleared in the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low oil level alarm cleared." + --#SUMMARY "Generator low oil level alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 434 + +xATSGeneratorLowBatteryVoltDuringCrankAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator's battery voltage has been detected + as low while cranking the engine. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Low batt. voltage while cranking alarm." + --#SUMMARY "Generator low battery volts while cranking alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 435 + +xATSGeneratorLowBatteryVoltDuringCrankAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The generator's low battery voltage while + cranking condition has been cleared. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "XGEN: Generator low batt. voltage while cranking alarm cleared." + --#SUMMARY "Generator low battery volts while cranking alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 436 + +xATSGeneratorVeryLowBatteryVoltDuringCrankAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator's battery voltage has been detected + as very low while cranking the engine. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "XGEN: Generator v.low battery voltage while cranking alarm." + --#SUMMARY "Generator v.low battery volts while cranking alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 437 + +xATSGeneratorVeryLowBatteryVoltDuringCrankAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The generator's high battery voltage while + cranking condition has been cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "XGEN: Generator v.low batt volt, while cranking alarm cleared." + --#SUMMARY "Generator v.low battery volts while cranking alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 438 + +xATSGeneratorEStop TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "SEVERE: The generator's emergency stop input has been activated. + After the emergency stop signal has been removed, the E-Stop condition + must be cleared before the generator can be started again. + E-Stop conditions can only be cleared via the generator front panel. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code. + The fourth argument is the type of E-Stop (1=LOCAL, 2=REMOTE)." + --#TYPE "APC XGEN: Generator emergency stop engaged." + --#SUMMARY "Generator emergency stop engaged." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE NONOPERATIONAL + ::= 439 + +xATSGeneratorEStopCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The generator's emergency stop condition has been cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code. + The fourth argument is the type of E-Stop (1=LOCAL, 2=REMOTE)." + --#TYPE "APC XGEN: Generator emergency stop condition cleared." + --#SUMMARY "Generator emergency stop condition cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 440 + +xATSGeneratorHighBatteryVolt TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: The generator's battery voltage has been detected as high. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator high battery voltage." + --#SUMMARY "Generator high battery volts." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 441 + +xATSGeneratorHighBatteryVoltCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected high battery voltage has been cleared, on the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator high battery voltage condition cleared." + --#SUMMARY "Generator high battery volts condition cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 442 + +xATSGeneratorLowBatteryVolt TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator's battery voltage has been detected as low. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low battery voltage." + --#SUMMARY "Generator low battery volts." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 443 + +xATSGeneratorLowBatteryVoltCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected low battery voltage has been cleared, on the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low battery voltage condition cleared." + --#SUMMARY "Generator low battery volts condition cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 444 + +xATSGeneratorControlSwitchNotAuto TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The control switch on the generator is not in auto position. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator not-in-automatic mode." + --#SUMMARY "Generator not-in-auto." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 445 + +xATSGeneratorControlSwitchNotAutoCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The control switch on the generator is in auto position. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator automatic mode restored." + --#SUMMARY "Generator not-in-auto cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 446 + +xATSGeneratorLowOilPressure TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator's oil pressure has been detected as low. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low oil pressure." + --#SUMMARY "Generator low oil pressure." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 447 + +xATSGeneratorLowOilPressureCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected low oil pressure has been cleared, on the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator low oil pressure condition cleared." + --#SUMMARY "Generator low oil pressure condition cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 448 + +xATSGeneratorVeryLowOilPressure TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator's oil pressure has been detected as very low. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator v.low oil pressure." + --#SUMMARY "Generator v.low oil pressure." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 449 + +xATSGeneratorVeryLowOilPressureCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected v.low oil pressure has been cleared, on the generator. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator v.low oil pressure condition cleared." + --#SUMMARY "Generator v.low oil pressure condition cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 450 + +xATSGeneratorOverload TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator is overloaded. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator is in overload event." + --#SUMMARY "Generator on overload event." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 451 + +xATSGeneratorOverloadCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The generator is running within loading limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator is in overload event cleared." + --#SUMMARY "Generator on overload event cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 452 + +xATSGeneratorLowACVEvent TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator AC voltage is outside the acceptable bounds. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: State of the Generator ac voltage." + --#SUMMARY " State of the Generator ac voltage." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 453 + +xATSGeneratorLowACVEventCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The generator AC voltage is within normal bounds. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: State of the Generator ac voltage cleared." + --#SUMMARY "State of the Generator ac voltage cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 454 + +xATSGeneratorHighACVEvent TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator AC voltage is outside the acceptable bounds. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: State of the Generator ac voltage." + --#SUMMARY " State of the Generator ac voltage." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 455 + +xATSGeneratorHighACVEventCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The generator AC voltage is within normal bounds. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: State of the Generator ac voltage cleared." + --#SUMMARY "State of the Generator ac voltage cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 456 + +xATSGeneratorOverspeed TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator is running over the acceptable RPM. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator overspeed condition." + --#SUMMARY "Generator overspeed condition." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 457 + +xATSGeneratorOverspeedCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The generator overspeed shutdown has been cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator overspeed condition cleared." + --#SUMMARY "Generator overspeed condition cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 458 + +xATSGeneratorEngineCold TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator engine is cold, may not start. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator engine is cold, may not start." + --#SUMMARY "Generator engine is cold." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 459 + +xATSGeneratorEngineColdCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The engine is not cold to start. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Engine is cold to start condition cleared." + --#SUMMARY "Engine is cold to start condition cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 460 + +xATSGeneratorOutputBreakerOpen TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generators output breaker has been detected as open. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator output breaker open alarm." + --#SUMMARY "Generator output breaker open." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE NONOPERATIONAL + ::= 461 + +xATSGeneratorOutputBreakerOpenCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The engine is not cold to start. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator output breaker open alarm cleared." + --#SUMMARY "Generator output breaker open cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 462 + +xATSGeneratorLowFuelLevelAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: The tank fuel level is below the limits specified + in the xATSGeneratorFuelSystemLowFuelLevelThreshold OID. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the measured fuel level in percent of full." + --#TYPE "APC XGEN: Low fuel level alarm." + --#SUMMARY "Generator low fuel level alarm." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 463 + +xATSGeneratorLowFuelLevelAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The tank fuel level is back above the specified limit. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XGEN: Low fuel level alarm cleared." + --#SUMMARY "Generator low fuel level alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 464 + +xATSGeneratorVeryLowFuelLevelAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The tank fuel level is below the low threshold limits. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the measured tank fuel level in percent of full." + --#TYPE "APC XGEN: Very Low fuel level alarm." + --#SUMMARY "Generator very low fuel level alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 465 + +xATSGeneratorVeryLowFuelLevelAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected low tank level has been cleared in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XGEN: Very low fuel level alarm cleared." + --#SUMMARY "Generator very low fuel level alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 466 + +xATSGeneratorLowRunTimeAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: The estimated runtime is below the limits specified. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the estimated runtime in hours." + --#TYPE "APC XGEN: Low run time alarm." + --#SUMMARY "Generator low run time alarm." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 467 + +xATSGeneratorLowRunTimeAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected low runtime has been cleared in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XGEN: Low run time alarm cleared." + --#SUMMARY "Generator low run time alarm." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 468 + +xATSGeneratorVeryLowRunTimeAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The estimated runtime is below the limits specified + in the xATSGeneratorFuelSystemVeryLowRunTimeThreshold OID. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the estimated runtime in hours." + --#TYPE "APC XGEN: Very low run time alarm." + --#SUMMARY "Generator very low run time alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 469 + +xATSGeneratorVeryLowRunTimeAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The detected low runtime has been cleared in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XGEN: Very low run time alarm cleared." + --#SUMMARY "Generator very low run time alarm." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 470 + +xATSGeneratorServiceDueAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "WARNING: The generator is due for scheduled service. + Generation of this alarm is based on calender days since + and/or actual generator run-hours since last service. + This alarm is cleared using the xATSGeneratorServiceResetRecord OID. + + (See also: xATSGeneratorServiceCalendarIntervalThreshold + and xATSGeneratorServiceRunHoursThreshold OIDs) + + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Generator scheduled maintenance is due." + --#SUMMARY "Generator maintenance due." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 471 + +xATSGeneratorServiceDueAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The generator's service registers have been reset. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Generator service due alarm is cleared." + --#SUMMARY "Generator service alarm is cleard." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 472 + +xATSGeneratorShutdown TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator is shutdown. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator shutdown." + --#SUMMARY "Generator shutdown" + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 473 + +xATSGeneratorShutdownCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The generator shutdown alarm is cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator shutdown is cleared." + --#SUMMARY "Generator shutdown is cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 474 + +xATSGeneratorBatteryCharger TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: The generator battery charger is nonfunctional. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator batt. charger is nonfunctional." + --#SUMMARY "Generator battery charger is nonfunctional" + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 475 + +xATSGeneratorBatteryChargerCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: nonfunctionality of the generator battery is cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: " Nonfunctionality of battery charger is cleared." + --#SUMMARY "non-functionality of Generator battery charger is cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 476 + +xATSGeneratorGenericEvent TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: Any generic generator event. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generator generic event." + --#SUMMARY "Generator generic event." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 477 + +xATSGeneratorGenericEventCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xATSIdentSerialNumber, xATSIdentProductName, mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Generated generic generator event is cleared. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the OEM's fault/event code." + --#TYPE "APC XGEN: Generic generator event is cleared." + --#SUMMARY "Generic generator event is cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 478 + +-- xPDU Traps (part 2) + +xPDUInternalCommErrorCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Internal communication has been restored. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Internal Communication error cleared." + --#SUMMARY "Communication error cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 479 + +xPDUSystemStateAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, + mtrapargsInteger, mtrapargsString } + DESCRIPTION + "WARNING: The PDU's breakers (Q1, Q2 & Q3) are in a configuration that might lead + to system unavailability. it may signify a temporary condition, when the breakers + are placed in an atypical manner as the user transitions to (UPS OPERATION or MAINTENANCE BYPASS) + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the type of alarm + (1=NO UPS INPUT, 2=NO PANEL FEED, 3=ATYPICAL BYPASS MODE)." + --#TYPE "APC XPDU: System state alarm ." + --#SUMMARY "PDU state alarm." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 480 + +xPDUSystemStateNormal TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, + mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The PDU's breakers (Q1, Q2 & Q3) are set in a configuration + that is a non-alarm state. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the type of alarm (1=UPS OPERATION, 2=MAINTENANCE BYPASS)." + --#TYPE "APC XPDU: System state returned to normal." + --#SUMMARY "PDU state normal." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 481 + +xPDUEpoTestMode TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "WARNING: The device's Emergency Power Off (EPO) circuit has been + switched back to the test position. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Emergency Power Off (EPO) in test mode." + --#SUMMARY "EPO disabled." + --#ARGUMENTS { } + --#SEVERITY WARNING + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 482 + +xPDUEpoArmed TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: The device's Emergency Power Off (EPO) circuit has been + switched back to the armed position. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Emergency Power Off (EPO) enabled." + --#SUMMARY "EPO armed." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 483 + +xPDUFuseBlownAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, + mtrapargsInteger, mtrapargsString } + DESCRIPTION + "SEVERE: One or more fuses in this PDU have been detected as open. + These fuses are in the feed to the UPS associated with this PDU. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3)." + --#TYPE "APC XPDU: Check fuse alarm." + --#SUMMARY "Fuse detected opened." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 484 + +xPDUFuseBlownAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, + mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A previous check fuse alarm in this PDU has cleared. + These fuses are in the feed to the UPS associated with this PDU. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the phase (1=L1, 2=L2, 3=L3)." + --#TYPE "APC XPDU: Check fuse alarm cleared." + --#SUMMARY "Fuse alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 485 + +xPDUBreakerPositionAlarm TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, + mtrapargsInteger, mtrapargsInteger02, mtrapargsString } + DESCRIPTION + "SEVERE: A PDU breaker is in a state that compromises system availability. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the breaker (1=MAIN INPUT, 2=BYPASS INPUT, 3=CROSS TIE). + The fourth argument is the breaker position (1=OPEN, 2=CLOSED)." + --#TYPE "APC XPDU: Breaker position alarm." + --#SUMMARY "Breaker position alarm." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 486 + +xPDUBreakerPositionAlarmCleared TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, + mtrapargsInteger, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A PDU breaker is no longer in a state that compromises system availability. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the breaker (1=MAIN INPUT, 2=BYPASS INPUT, 3=CROSS TIE)." + --#TYPE "APC XPDU: Breaker position alarm cleared." + --#SUMMARY "Breaker alarm cleared." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 487 + +xPDUBreakerChangeEvent TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsInteger, + mtrapargsInteger02, mtrapargsInteger03, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: A system breaker or switch within the device has changed state. + They are generated when any of the Q1, Q2 or Q3 breakers have changed states. + The first argument is the host device serial number. + The second argument is the host device name. + The third argument is the breaker that has changed + (1=UPS FEED (Q1), 2=UPS OUTPUT(Q2), 3=MAINTENANCE BYPASS (Q3). + The fourth argument is the state of the breaker that has changed (1=OPEN, 2=CLOSED). + The fifth argument is a 8-bit field representing the state of all breakers in the system, + when any of one of the Q1, Q2 or Q3 breakers have changed state. + + The bit map is represented in the following manner (b7, b6 ... b0) + b0 - UPS FEED (Q1) + b1 - MAINTENANCE BYPASS (Q3) + b2 - UPS OUTPUT (Q2) + b3 - MAIN INPUT + b4 - BYPASS INPUT + b5 - CROSS-TIE OUTPUT + + Example: value of 60 (0x3C) indicates that the CROSS_TIE, BYPASS and MAIN INPUT, and Q2 breakers + are CLOSED and Q2, Q1 breakers are OPEN." + --#TYPE "APC XPDU: Breaker/switch change event." + --#SUMMARY "Breaker/switch change event." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 488 + +xPDUControllerFirmwareUpdateTransferStart TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Start Controller firmware transfer in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Start controller firmware transfer." + --#SUMMARY "Start controller firmware transfer." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 489 + +xPDUControllerFirmwareUpdateTransferComplete TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Transfer of Controller firmware was completed in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Controller firmware transfer completed." + --#SUMMARY "Controller firmware transfer completed." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 490 + +xPDUControllerFirmwareUpdateTransferFailed TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: Transfer of Controller firmware has failed in the PDU. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XPDU: Controller firmware transfer failed." + --#SUMMARY "Controller firmware transfer failed." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 491 + +xATSControllerFirmwareUpdateTransferStart TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Start Controller firmware transfer in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Start controller firmware transfer." + --#SUMMARY "Start controller firmware transfer." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 492 + +xATSControllerFirmwareUpdateTransferComplete TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "INFORMATIONAL: Transfer of Controller firmware was completed in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Controller firmware transfer completed." + --#SUMMARY "Controller firmware transfer completed." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 493 + +xATSControllerFirmwareUpdateTransferFailed TRAP-TYPE + ENTERPRISE apc + VARIABLES { xPDUIdentSerialNumber, xPDUIdentProductName, mtrapargsString } + DESCRIPTION + "SEVERE: Transfer of Controller firmware has failed in the device. + The first argument is the host device serial number. + The second argument is the host device name." + --#TYPE "APC XATS: Controller firmware transfer failed." + --#SUMMARY "Controller firmware transfer failed." + --#ARGUMENTS { } + --#SEVERITY SEVERE + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE DEGRADED + ::= 494 + +apcDeviceShutdownHeartbeat TRAP-TYPE + ENTERPRISE apc + VARIABLES { mtrapargsInteger, mtrapargsTimeTicks, mtrapargsString} + DESCRIPTION + "INFORMATIONAL: " + --#TYPE "APC X:" + --#SUMMARY "." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 999 + +apcDiscoveryAlarmStateTableUpdate TRAP-TYPE + ENTERPRISE apc + VARIABLES { apcDiscoveryDeviceAlarmStateChangeCount } + DESCRIPTION + "INTERNAL: A Discovery Alarm State Table Update trap is sent + when any data alarm state is added, removed, or its parameters + are changed in the condition table. This trap is + only for machine-to-machine communication. " + --#TYPE "APC X:" + --#SUMMARY "." + --#ARGUMENTS { } + --#SEVERITY INFORMATIONAL + --#TIMEINDEX 1 + --#HELP "" + --#HELPTAG 0 + --#STATE OPERATIONAL + ::= 1000 + +END diff --git a/agents/autodetect/a.py b/agents/autodetect/a.py new file mode 100644 index 0000000..608d0f8 --- /dev/null +++ b/agents/autodetect/a.py @@ -0,0 +1,8 @@ +from b import myf + +def maf(): + return 5 + +def maf2(): + return myf() +
\ No newline at end of file diff --git a/agents/autodetect/autodetect.py b/agents/autodetect/autodetect.py new file mode 100755 index 0000000..24d9a73 --- /dev/null +++ b/agents/autodetect/autodetect.py @@ -0,0 +1,255 @@ +#!/usr/bin/python + +import pexpect +import re +import logging +import time +import sys +import fencing + +import fence_apc +import fence_bladecenter +import fence_brocade +import fence_rsa + +def check_agent(conn, options, found_prompt, prompts, test_fn, eol=None): + options["--action"] = "list" + options["--command-prompt"] = found_prompt + if any(x in options["--command-prompt"][0] for x in prompts): + options["--command-prompt"] = prompts + + return test_fn(conn, options) + return False + +def get_list(conn, options, found_prompt, prompts, list_fn, eol=None): + def test_fn(conn, options): + if len(list_fn(conn, options)) > 0: + return True + else: + return False + + return check_agent(conn, options, found_prompt, prompts, test_fn, eol) + +""" *************************** MAIN ******************************** """ + + +def detect_login_telnet(options): + options["--ipport"] = 23 + re_login_string = r"([\r\n])((?!Last )login\s*:)|((?!Last )Login Name: )|(username: )|(User Name :)" + re_login = re.compile(re_login_string, re.IGNORECASE) + re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE) + + options["eol"] = "\r\n" + conn = fencing.fspawn(options, options["--telnet-path"]) + conn.send("set binary\n") + conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) + + conn.log_expect(re_login, int(options["--login-timeout"])) + conn.send_eol(options["--username"]) + + ## automatically change end of line separator + screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) + if re_login.search(screen) != None: + options["eol"] = "\n" + conn.send_eol(options["--username"]) + conn.log_expect(re_pass, int(options["--login-timeout"])) + elif re_pass.search(screen) == None: + conn.log_expect(re_pass, int(options["--shell-timeout"])) + + try: + conn.send_eol(options["--password"]) + valid_password = conn.log_expect([re_login] + \ + [pexpect.TIMEOUT], int(options["--shell-timeout"])) + if valid_password == 0: + ## password is invalid or we have to change EOL separator + options["eol"] = "\r" + conn.send_eol("") + screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) + ## after sending EOL the fence device can either show 'Login' or 'Password' + if re_login.search(conn.after + screen) != None: + conn.send_eol("") + conn.send_eol(options["--username"]) + conn.log_expect(re_pass, int(options["--login-timeout"])) + conn.send_eol(options["--password"]) + conn.log_expect(pexpect.TIMEOUT, int(options["--login-timeout"])) + except KeyError: + fencing.fail(fencing.EC_PASSWORD_MISSING) + + found_cmd_prompt = guess_prompt(conn, options, conn.before) + return (found_cmd_prompt, conn) + +def guess_prompt(conn, options, before=""): + time.sleep(2) + conn.send_eol("") + conn.send_eol("") + + conn.log_expect(pexpect.TIMEOUT, int(options["--login-timeout"])) + lines = re.split(r'\r|\n', before + conn.before) + logging.info("Cmd-prompt candidate: %s" % (lines[-1])) + if lines.count(lines[-1]) >= 3: + found_cmd_prompt = ["\n" + lines[-1]] + else: + if lines.count(lines[-1]) == 2: + conn.log_expect(lines[-1], int(options["--shell-timeout"])) + conn.log_expect(lines[-1], int(options["--shell-timeout"])) + options["eol"] = "\r" + conn.send_eol("") + time.sleep(0.1) + conn.send_eol("") + time.sleep(0.1) + conn.send_eol("") + time.sleep(0.1) + conn.log_expect(pexpect.TIMEOUT, int(options["--login-timeout"])) + lines = re.split(r'\r|\n', conn.before) + logging.info("Cmd-prompt candidate: %s" % (lines[1])) + if lines.count(lines[-1]) >= 3: + found_cmd_prompt = ["\n" + lines[-1]] + else: + print "Unable to obtain command prompt automatically" + sys.exit(1) + else: + print "Unable to obtain command prompt automatically" + print lines[-1] + print conn.before + sys.exit(1) + + conn.log_expect(found_cmd_prompt, int(options["--shell-timeout"])) + conn.log_expect(found_cmd_prompt, int(options["--shell-timeout"])) + conn.log_expect(found_cmd_prompt, int(options["--shell-timeout"])) + + # Handle situation when CR/LF is interpreted as ENTER, ENTER + # In such case we will have get two additional command prompts to get on right position + res = conn.log_expect([pexpect.TIMEOUT] + found_cmd_prompt, int(options["--shell-timeout"])) + if res > 0: + # @note: store that information? + print "CMD twice" + conn.log_expect(found_cmd_prompt, int(options["--shell-timeout"])) + return found_cmd_prompt + +def detect_login_ssh(options, version=2): + options["--ipport"] = 22 + if version == "1": + command = '%s %s@%s -p %s -1 -c blowfish -o PubkeyAuthentication=no' % (options["--ssh-path"], options["--username"], options["--ip"], options["--ipport"]) + else: + command = '%s %s@%s -p %s -o PubkeyAuthentication=no' % (options["--ssh-path"], options["--username"], options["--ip"], options["--ipport"]) + + conn = fencing.fspawn(options, command) + result = conn.log_expect(["ssword:", "Are you sure you want to continue connecting (yes/no)?"], int(options["--login-timeout"])) + if result == 1: + conn.send("yes\n") + conn.log_expect("ssword:", int(options["--login-timeout"])) + + conn.send(options["--password"] + "\n") + + found_cmd_prompt = guess_prompt(conn, options, conn.before) + return (found_cmd_prompt, conn) + +def detect_device(conn, options, found_cmd_prompt): + if get_list(conn, options, found_cmd_prompt, prompts=["\n>", "\napc>"], list_fn=fence_apc.get_power_status): + fencing.fence_logout(conn, "4") + return "fence_apc # older serie" + + if get_list(conn, options, found_cmd_prompt, prompts=["\n>", "\napc>"], list_fn=fence_apc.get_power_status5): + fencing.fence_logout(conn, "exit") + return "fence_apc # v5+" + + ## Test fence_lpar with list action (HMC version 3 and 4) + def test_lpar(conn, options): + conn.send_eol("lssyscfg; echo $?") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + if "\n0\r\n" in conn.before: + return True + else: + return False + + if check_agent(conn, options, found_cmd_prompt, [r":~>", r"]\$", r"\$ "], test_lpar): + fencing.fence_logout(conn, "quit") + return "fence_lpar # 2" + + if get_list(conn, options, found_cmd_prompt, prompts=["system>"], list_fn=fence_bladecenter.get_blades_list): + fencing.fence_logout(conn, "exit") + return "fence_bladecenter #2" + + if get_list(conn, options, found_cmd_prompt, prompts=["> "], list_fn=fence_brocade.get_power_status, eol="\n"): + fencing.fence_logout(conn, "exit") + return "fence_brocade #2" + + if get_list(conn, options, found_cmd_prompt, prompts=["> "], list_fn=fence_rsa.get_power_status): + fencing.fence_logout(conn, "exit") + return "fence_rsa" + + return None + +# Test fence ilo moonshot +#cmd_possible = ["MP>", "hpiLO->"] +#options["--action"] = "list" +#options["--command-prompt"] = found_cmd_prompt +#options["eol"] = "\n" +#if any(x in options["--command-prompt"][0] for x in cmd_possible): +# options["--command-prompt"] = cmd_possible +# +# plugs = fence_ilo_moonshot.get_power_status(conn, options) +# if len(plugs) > 0: +# print "fence_ilo_moonshot # " +# fencing.fence_logout(conn, "exit") +# sys.exit(0) + +def xxx(): + ## login mechanism as in fencing.py.py - differences is that we do not know command prompt + #logging.getLogger().setLevel(logging.DEBUG) + options = {} + options["--ssh-path"] = "/usr/bin/ssh" + options["--telnet-path"] = "/usr/bin/telnet" + + # virtual machine + #options["--username"] = "marx" + #options["--ip"] = "localhost" + #options["--password"] = "batalion" + + # APC + #options["--username"] = "labuser" + #options["--ip"] = "pdu-bar.englab.brq.redhat.com" + #options["--password"] = "labuser" + + # LPAR + options["--username"] = "rhts" + options["--ip"] = "ppc-hmc-01.mgmt.lab.eng.bos.redhat.com" + #options["--ip"] = "ibm-js22-vios-02.rhts.eng.bos.redhat.com" + options["--password"] = "100yard-" + + # Bladecenter + options["--ip"] = "blade-mm.englab.brq.redhat.com" + + # Brocade + #options["--ip"] = "hp-fcswitch-01.lab.bos.redhat.com" + #options["--password"] = "password" + #options["--username"] = "admin" + + # iLO Moonshot - chova sa to divne + #options["--password"] = "Access@gis" + #options["--username"] = "rcuser" + #options["--ip"] = "hp-m1500-mgmt.gsslab.pnq.redhat.com" + + #options["--ip"] = "ibm-x3755-01-rsa.ovirt.rhts.eng.bos.redhat.com" + #options["--username"] = "USERID" + #options["--password"] = "PASSW0RD" + + options["--login-timeout"] = "10" + options["--shell-timeout"] = "5" + options["--power-timeout"] = "10" + + options["eol"] = "\r\n" + + (found_cmd_prompt, conn) = detect_login_telnet(options) + #(found_cmd_prompt, conn) = detect_login_ssh(options) + + res = detect_device(conn, options, found_cmd_prompt) + if not res is None: + print res + sys.exit(0) + else: + ## Nothing found + sys.exit(2) + +if __name__ == "__main__": + xxx() diff --git a/agents/autodetect/autodetect_test.py b/agents/autodetect/autodetect_test.py new file mode 100755 index 0000000..a18aaed --- /dev/null +++ b/agents/autodetect/autodetect_test.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +import unittest +import autodetect as detect + +class TestDetectDevice(unittest.TestCase): + options = {} + + def setUp(self): + self.options = {} + self.options["--ssh-path"] = "/usr/bin/ssh" + self.options["--telnet-path"] = "/usr/bin/telnet" + self.options["--login-timeout"] = "10" + self.options["--shell-timeout"] = "5" + self.options["--power-timeout"] = "10" + self.options["eol"] = "\r\n" + + def test_bladecenter(self): + self.options["--username"] = "rhts" + self.options["--password"] = "100yard-" + self.options["--ip"] = "blade-mm.englab.brq.redhat.com" + + (found_cmd_prompt, conn) = detect.detect_login_telnet(self.options) + res = detect.detect_device(conn, self.options, found_cmd_prompt) + self.assertEqual('fence_bladecenter', res) + + def test_apc5(self): + self.assertEqual('foo', 'foo') + self.options["c"] = "c" + print self.options + +if __name__ == "__main__": + unittest.main() diff --git a/agents/autodetect/b.py b/agents/autodetect/b.py new file mode 100644 index 0000000..fdfda59 --- /dev/null +++ b/agents/autodetect/b.py @@ -0,0 +1,2 @@ +def myf(): + return 3 diff --git a/agents/autodetect/fence_apc.py b/agents/autodetect/fence_apc.py new file mode 100644 index 0000000..c6dd106 --- /dev/null +++ b/agents/autodetect/fence_apc.py @@ -0,0 +1,259 @@ +#!/usr/bin/python -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## Model Firmware +## +---------------------------------------------+ +## AP7951 AOS v2.7.0, PDU APP v2.7.3 +## AP7941 AOS v3.5.7, PDU APP v3.5.6 +## AP9606 AOS v2.5.4, PDU APP v2.7.3 +## +## @note: ssh is very slow on AP79XX devices protocol (1) and +## cipher (des/blowfish) have to be defined +##### + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, EC_STATUS + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION="New APC Agent - test release on steroids" +REDHAT_COPYRIGHT="" +BUILD_DATE="March, 2008" +#END_VERSION_GENERATION + +def get_power_status(conn, options): + exp_result = 0 + outlets = {} + + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + version = 0 + admin = 0 + switch = 0 + + if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before): + switch = 1 + if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before): + if not options.has_key("--switch"): + fail_usage("Failed: You have to enter physical switch number") + else: + if not options.has_key("--switch"): + options["--switch"] = "1" + + if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before): + version = 2 + else: + version = 3 + + if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before): + admin = 0 + else: + admin = 1 + + if switch == 0: + if version == 2: + if admin == 0: + conn.send_eol("2") + else: + conn.send_eol("3") + else: + conn.send_eol("2") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.send_eol("1") + else: + conn.send_eol(options["--switch"]) + + while True: + exp_result = conn.log_expect( + ["Press <ENTER>"] + options["--command-prompt"], int(options["--shell-timeout"])) + lines = conn.before.split("\n") + show_re = re.compile(r'(^|\x0D)\s*(\d+)- (.*?)\s+(ON|OFF)\s*') + for line in lines: + res = show_re.search(line) + if res != None: + outlets[res.group(2)] = (res.group(3), res.group(4)) + conn.send_eol("") + if exp_result != 0: + break + conn.send(chr(03)) + conn.log_expect("- Logout", int(options["--shell-timeout"])) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + if ["list", "monitor"].count(options["--action"]) == 1: + return outlets + else: + try: + (_, status) = outlets[options["--plug"]] + return status.lower().strip() + except KeyError: + fail(EC_STATUS) + +def set_power_status(conn, options): + action = { + 'on' : "1", + 'off': "2" + }[options["--action"]] + + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + version = 0 + admin2 = 0 + admin3 = 0 + switch = 0 + + if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before): + switch = 1 + ## MasterSwitch has different schema for on/off actions + action = { + 'on' : "1", + 'off': "3" + }[options["--action"]] + if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before): + if not options.has_key("--switch"): + fail_usage("Failed: You have to enter physical switch number") + else: + if not options.has_key("--switch"): + options["--switch"] = 1 + + if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before): + version = 2 + else: + version = 3 + + if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before): + admin2 = 0 + else: + admin2 = 1 + + if switch == 0: + if version == 2: + if admin2 == 0: + conn.send_eol("2") + else: + conn.send_eol("3") + else: + conn.send_eol("2") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + if None == re.compile('.*2- Outlet Restriction.*', re.IGNORECASE | re.S).match(conn.before): + admin3 = 0 + else: + admin3 = 1 + conn.send_eol("1") + else: + conn.send_eol(options["--switch"]) + + while 0 == conn.log_expect( + ["Press <ENTER>"] + options["--command-prompt"], int(options["--shell-timeout"])): + conn.send_eol("") + + conn.send_eol(options["--plug"]+"") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + if switch == 0: + if admin2 == 1: + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + if admin3 == 1: + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + else: + conn.send_eol("1") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + conn.send_eol(action) + conn.log_expect("Enter 'YES' to continue or <ENTER> to cancel :", int(options["--shell-timeout"])) + conn.send_eol("YES") + conn.log_expect("Press <ENTER> to continue...", int(options["--power-timeout"])) + conn.send_eol("") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + conn.send(chr(03)) + conn.log_expect("- Logout", int(options["--shell-timeout"])) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def get_power_status5(conn, options): + outlets = {} + + conn.send_eol("olStatus all") + + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + lines = conn.before.split("\n") + + show_re = re.compile(r'^\s*(\d+): (.*): (On|Off)\s*$', re.IGNORECASE) + + for line in lines: + res = show_re.search(line) + if res != None: + outlets[res.group(1)] = (res.group(2), res.group(3)) + + if ["list", "monitor"].count(options["--action"]) == 1: + return outlets + else: + try: + (_, status) = outlets[options["--plug"]] + return status.lower().strip() + except KeyError: + fail(EC_STATUS) + +def set_power_status5(conn, options): + action = { + 'on' : "olOn", + 'off': "olOff" + }[options["--action"]] + + conn.send_eol(action + " " + options["--plug"]) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "port", "switch", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["\n>", "\napc>"] + all_opt["ssh_options"]["default"] = "-1 -c blowfish" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for APC over telnet/ssh" + docs["longdesc"] = "fence_apc is an I/O Fencing agent \ +which can be used with the APC network power switch. It logs into device \ +via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh connections \ +should be avoided while a GFS cluster is running because the connection \ +will block any necessary fencing actions." + docs["vendorurl"] = "http://www.apc.com" + show_docs(options, docs) + + ## Support for --plug [switch]:[plug] notation that was used before + if (options.has_key("--plug") == 1) and (-1 != options["--plug"].find(":")): + (switch, plug) = options["--plug"].split(":", 1) + options["--switch"] = switch + options["--plug"] = plug + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + + ## Detect firmware version (ASCII menu vs command-line interface) + ## and continue with proper action + #### + result = -1 + firmware_version = re.compile(r'\s*v(\d)*\.').search(conn.before) + if (firmware_version != None) and (firmware_version.group(1) in [ "5", "6" ]): + result = fence_action(conn, options, set_power_status5, get_power_status5, get_power_status5) + else: + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + + fence_logout(conn, "4") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/autodetect/fence_bladecenter.py b/agents/autodetect/fence_bladecenter.py new file mode 100644 index 0000000..d72c07f --- /dev/null +++ b/agents/autodetect/fence_bladecenter.py @@ -0,0 +1,111 @@ +#!/usr/bin/python -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## Model Firmware +## +--------------------+---------------------------+ +## (1) Main application BRET85K, rev 16 +## Boot ROM BRBR67D, rev 16 +## Remote Control BRRG67D, rev 16 +## +##### + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS, EC_GENERIC_ERROR + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION="New Bladecenter Agent - test release on steroids" +REDHAT_COPYRIGHT="" +BUILD_DATE="March, 2008" +#END_VERSION_GENERATION + +def get_power_status(conn, options): + node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" + + conn.send_eol("env -T system:blade[" + options["--plug"] + "]") + i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) + if i == 1: + ## Given blade number does not exist + if options.has_key("--missing-as-off"): + return "off" + else: + fail(EC_STATUS) + conn.send_eol("power -state") + conn.log_expect(node_cmd, int(options["--shell-timeout"])) + status = conn.before.splitlines()[-1] + conn.send_eol("env -T system") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + return status.lower().strip() + +def set_power_status(conn, options): + node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" + + conn.send_eol("env -T system:blade[" + options["--plug"] + "]") + i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) + if i == 1: + ## Given blade number does not exist + if options.has_key("--missing-as-off"): + return + else: + fail(EC_GENERIC_ERROR) + + conn.send_eol("power -"+options["--action"]) + conn.log_expect(node_cmd, int(options["--shell-timeout"])) + conn.send_eol("env -T system") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def get_blades_list(conn, options): + outlets = {} + + node_cmd = "system>" + + conn.send_eol("env -T system") + conn.log_expect(node_cmd, int(options["--shell-timeout"])) + conn.send_eol("list -l 2") + conn.log_expect(node_cmd, int(options["--shell-timeout"])) + + lines = conn.before.split("\r\n") + filter_re = re.compile(r"^\s*blade\[(\d+)\]\s+(.*?)\s*$") + for blade_line in lines: + res = filter_re.search(blade_line) + if res != None: + outlets[res.group(1)] = (res.group(2), "") + + return outlets + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "port", "missing_as_off", "telnet"] + + atexit.register(atexit_handler) + + all_opt["power_wait"]["default"] = "10" + all_opt["cmd_prompt"]["default"] = ["system>"] + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for IBM BladeCenter" + docs["longdesc"] = "fence_bladecenter is an I/O Fencing agent \ +which can be used with IBM Bladecenters with recent enough firmware that \ +includes telnet support. It logs into a Brocade chasis via telnet or ssh \ +and uses the command line interface to power on and off blades." + docs["vendorurl"] = "http://www.ibm.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + ###### + conn = fence_login(options, "(username\s*:\s*)") + result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/autodetect/fence_brocade.py b/agents/autodetect/fence_brocade.py new file mode 100644 index 0000000..5257bcc --- /dev/null +++ b/agents/autodetect/fence_brocade.py @@ -0,0 +1,78 @@ +#!/usr/bin/python -tt + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION="New Brocade Agent - test release on steroids" +REDHAT_COPYRIGHT="" +BUILD_DATE="March, 20013" +#END_VERSION_GENERATION + +def set_power_status(conn, options): + action = { + 'on' : "portCfgPersistentEnable", + 'off': "portCfgPersistentDisable" + }[options["--action"]] + + conn.send_eol(action + " " + options["--plug"]) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +def get_power_status(conn, options): + line_re = re.compile(r'=========', re.IGNORECASE) + outlets = {} + in_index = False + + conn.send_eol("switchshow") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + for line in str(conn.before).split("\n"): + if line_re.search(line): + in_index = True + elif in_index and line.lstrip()[0].isdigit(): + tokens = line.lstrip().split() + status = "off" if len(tokens) > 7 and tokens[7] == "Disabled" else "on" + outlets[tokens[0]] = ("", status) + + if ["list", "monitor"].count(options["--action"]) == 0: + (_, status) = outlets[options["--plug"]] + return status + else: + return outlets + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "port", "fabric_fencing", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["> "] + + options = check_input(device_opt, process_input(device_opt)) + options["eol"] = "\n" + + docs = {} + docs["shortdesc"] = "Fence agent for HP Brocade over telnet/ssh" + docs["longdesc"] = "fence_brocade is an I/O Fencing agent which can be used with Brocade FC switches. \ +It logs into a Brocade switch via telnet and disables a specified port. Disabling the port which a machine is \ +connected to effectively fences that machine. Lengthy telnet connections to the switch should be avoided while \ +a GFS cluster is running because the connection will block any necessary fencing actions. \ +\ +After a fence operation has taken place the fenced machine can no longer connect to the Brocade FC switch. \ +When the fenced machine is ready to be brought back into the GFS cluster (after reboot) the port on the Brocade \ +FC switch needs to be enabled. This can be done by running fence_brocade and specifying the enable action" + docs["vendorurl"] = "http://www.brocade.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/autodetect/fence_ilo_moonshot.py b/agents/autodetect/fence_ilo_moonshot.py new file mode 100644 index 0000000..e161ac6 --- /dev/null +++ b/agents/autodetect/fence_ilo_moonshot.py @@ -0,0 +1,69 @@ +#!/usr/bin/python -tt + +import sys +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION="" +REDHAT_COPYRIGHT="" +BUILD_DATE="" +#END_VERSION_GENERATION + +def get_power_status(conn, options): + conn.send_eol("show node list") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + nodes = {} + for line in conn.before.splitlines(): + if len(line.split()) == 10: + nodes[line.split()[1]] = ("", line.split()[8].lower().strip()) + + if ["list", "monitor"].count(options["--action"]) == 1: + return nodes + else: + try: + (_, status) = nodes[options["--plug"]] + return status.lower() + except KeyError: + fail(EC_STATUS) + +def set_power_status(conn, options): + if options["--action"] == "on": + conn.send_eol("set node power on %s" % (options["--plug"])) + else: + conn.send_eol("set node power off force %s" % (options["--plug"])) + + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + return + +def main(): + device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "port"] + + atexit.register(atexit_handler) + + all_opt["secure"]["default"] = "1" + all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for HP Moonshot iLO" + docs["longdesc"] = "" + docs["vendorurl"] = "http://www.hp.com" + show_docs(options, docs) + + conn = fence_login(options) + + ## + ## Fence operations + #### + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/autodetect/fence_lpar.py b/agents/autodetect/fence_lpar.py new file mode 100644 index 0000000..6676e1c --- /dev/null +++ b/agents/autodetect/fence_lpar.py @@ -0,0 +1,159 @@ +#!/usr/bin/python -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## Version +## +---------------------------------------------+ +## Tested on HMC +## +##### + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, EC_STATUS_HMC + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION="" +REDHAT_COPYRIGHT="" +BUILD_DATE="" +#END_VERSION_GENERATION + +def get_power_status(conn, options): + if options["--hmc-version"] == "3": + conn.send("lssyscfg -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -F name,state\n") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + try: + status = re.compile("^" + options["--plug"] + ",(.*?),.*$", + re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) + except AttributeError: + fail(EC_STATUS_HMC) + elif options["--hmc-version"] == "4": + conn.send("lssyscfg -r lpar -m "+ options["--managed"] + + " --filter 'lpar_names=" + options["--plug"] + "'\n") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + try: + status = re.compile(",state=(.*?),", re.IGNORECASE).search(conn.before).group(1) + except AttributeError: + fail(EC_STATUS_HMC) + + ## + ## Transformation to standard ON/OFF status if possible + if status in ["Running", "Open Firmware", "Shutting Down", "Starting"]: + status = "on" + else: + status = "off" + + return status + +def set_power_status(conn, options): + if options["--hmc-version"] == "3": + conn.send("chsysstate -o " + options["--action"] + " -r lpar -m " + options["--managed"] + + " -n " + options["--plug"] + "\n") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + elif options["--hmc-version"] == "4": + if options["--action"] == "on": + conn.send("chsysstate -o on -r lpar -m " + options["--managed"] + + " -n " + options["--plug"] + + " -f `lssyscfg -r lpar -F curr_profile " + + " -m " + options["--managed"] + + " --filter \"lpar_names=" + options["--plug"] + "\"`\n") + else: + conn.send("chsysstate -o shutdown -r lpar --immed" + + " -m " + options["--managed"] + " -n " + options["--plug"] + "\n") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +def get_lpar_list(conn, options): + outlets = {} + if options["--hmc-version"] == "3": + conn.send("query_partition_names -m " + options["--managed"] + "\n") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + ## We have to remove first 3 lines (command + header) and last line (part of new prompt) + #### + res = re.search("^.+?\n(.+?\n){2}(.*)\n.*$", conn.before, re.S) + + if res == None: + fail_usage("Unable to parse output of list command") + + lines = res.group(2).split("\n") + for outlet_line in lines: + outlets[outlet_line.rstrip()] = ("", "") + elif options["--hmc-version"] == "4": + conn.send("lssyscfg -r lpar -m " + options["--managed"] + + " -F name:state\n") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + ## We have to remove first line (command) and last line (part of new prompt) + #### + res = re.search("^.+?\n(.*)\n.*$", conn.before, re.S) + + if res == None: + fail_usage("Unable to parse output of list command") + + lines = res.group(1).split("\n") + for outlet_line in lines: + (port, status) = outlet_line.split(":") + outlets[port] = ("", status) + + return outlets + +def define_new_opts(): + all_opt["managed"] = { + "getopt" : "s:", + "longopt" : "managed", + "help" : "-s, --managed=[id] Name of the managed system", + "required" : "0", + "shortdesc" : "Managed system name", + "order" : 1} + all_opt["hmc_version"] = { + "getopt" : "H:", + "longopt" : "hmc-version", + "help" : "-H, --hmc-version=[version] Force HMC version to use: (3|4) (default: 4)", + "required" : "0", + "shortdesc" : "Force HMC version to use", + "default" : "4", + "choices" : ["3", "4"], + "order" : 1} + +def main(): + device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", \ + "port", "managed", "hmc_version"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["login_timeout"]["default"] = "15" + all_opt["secure"]["default"] = "1" + all_opt["cmd_prompt"]["default"] = [r":~>", r"]\$", r"\$ "] + + options = check_input(device_opt, process_input(device_opt), other_conditions = True) + + docs = {} + docs["shortdesc"] = "Fence agent for IBM LPAR" + docs["longdesc"] = "" + docs["vendorurl"] = "http://www.ibm.com" + show_docs(options, docs) + + if not options.has_key("--managed"): + fail_usage("Failed: You have to enter name of managed system") + + if options["--action"] == "validate-all": + sys.exit(0) + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, get_lpar_list) + fence_logout(conn, "quit\r\n") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/autodetect/fencing.py b/agents/autodetect/fencing.py new file mode 100644 index 0000000..ea21ace --- /dev/null +++ b/agents/autodetect/fencing.py @@ -0,0 +1,1393 @@ +#!/usr/bin/python -tt + +import sys, getopt, time, os, uuid, pycurl, stat +import pexpect, re, syslog +import logging +import subprocess +import threading +import shlex +import exceptions +import socket +import textwrap +import __main__ + +## do not add code here. +#BEGIN_VERSION_GENERATION +RELEASE_VERSION="4.0.21.23-eaa13" +BUILD_DATE="(built Wed Nov 4 13:28:43 CET 2015)" +REDHAT_COPYRIGHT="Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved." +#END_VERSION_GENERATION + +__all__ = ['atexit_handler', 'check_input', 'process_input', 'all_opt', 'show_docs', + 'fence_login', 'fence_action', 'fence_logout'] + +EC_OK = 0 +EC_GENERIC_ERROR = 1 +EC_BAD_ARGS = 2 +EC_LOGIN_DENIED = 3 +EC_CONNECTION_LOST = 4 +EC_TIMED_OUT = 5 +EC_WAITING_ON = 6 +EC_WAITING_OFF = 7 +EC_STATUS = 8 +EC_STATUS_HMC = 9 +EC_PASSWORD_MISSING = 10 +EC_INVALID_PRIVILEGES = 11 + +all_opt = { + "help" : { + "getopt" : "h", + "longopt" : "help", + "help" : "-h, --help Display this help and exit", + "required" : "0", + "shortdesc" : "Display help and exit", + "order" : 54}, + "version" : { + "getopt" : "V", + "longopt" : "version", + "help" : "-V, --version Display version information and exit", + "required" : "0", + "shortdesc" : "Display version information and exit", + "order" : 53}, + "verbose" : { + "getopt" : "v", + "longopt" : "verbose", + "help" : "-v, --verbose Verbose mode", + "required" : "0", + "order" : 51}, + "debug" : { + "getopt" : "D:", + "longopt" : "debug-file", + "help" : "-D, --debug-file=[debugfile] Debugging to output file", + "required" : "0", + "shortdesc" : "Write debug information to given file", + "order" : 52}, + "delay" : { + "getopt" : ":", + "longopt" : "delay", + "help" : "--delay=[seconds] Wait X seconds before fencing is started", + "required" : "0", + "default" : "0", + "order" : 200}, + "agent" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "web" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "force_on" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "action" : { + "getopt" : "o:", + "longopt" : "action", + "help" : "-o, --action=[action] Action: status, reboot (default), off or on", + "required" : "1", + "shortdesc" : "Fencing action", + "default" : "reboot", + "order" : 1}, + "fabric_fencing" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "ipaddr" : { + "getopt" : "a:", + "longopt" : "ip", + "help" : "-a, --ip=[ip] IP address or hostname of fencing device", + "required" : "1", + "order" : 1}, + "ipport" : { + "getopt" : "u:", + "longopt" : "ipport", + "help" : "-u, --ipport=[port] TCP/UDP port to use for connection", + "required" : "0", + "shortdesc" : "TCP/UDP port to use for connection with device", + "order" : 1}, + "login" : { + "getopt" : "l:", + "longopt" : "username", + "help" : "-l, --username=[name] Login name", + "required" : "?", + "order" : 1}, + "no_login" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "no_password" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "no_port" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "no_status" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "no_on" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "no_off" : { + "getopt" : "", + "help" : "", + "order" : 1}, + "telnet" : { + "getopt" : "", + "help" : "", + "order" : ""}, + "passwd" : { + "getopt" : "p:", + "longopt" : "password", + "help" : "-p, --password=[password] Login password or passphrase", + "required" : "0", + "order" : 1}, + "passwd_script" : { + "getopt" : "S:", + "longopt" : "password-script", + "help" : "-S, --password-script=[script] Script to run to retrieve password", + "required" : "0", + "order" : 1}, + "identity_file" : { + "getopt" : "k:", + "longopt" : "identity-file", + "help" : "-k, --identity-file=[filename] Identity file (private key) for SSH", + "required" : "0", + "order" : 1}, + "cmd_prompt" : { + "getopt" : "c:", + "longopt" : "command-prompt", + "help" : "-c, --command-prompt=[prompt] Force Python regex for command prompt", + "required" : "0", + "order" : 1}, + "secure" : { + "getopt" : "x", + "longopt" : "ssh", + "help" : "-x, --ssh Use SSH connection", + "required" : "0", + "order" : 1}, + "ssh_options" : { + "getopt" : ":", + "longopt" : "ssh-options", + "help" : "--ssh-options=[options] SSH options to use", + "required" : "0", + "order" : 1}, + "ssl" : { + "getopt" : "z", + "longopt" : "ssl", + "help" : "-z, --ssl Use SSL connection with verifying certificate", + "required" : "0", + "order" : 1}, + "ssl_insecure" : { + "getopt" : "", + "longopt" : "ssl-insecure", + "help" : "--ssl-insecure Use SSL connection without verifying certificate", + "required" : "0", + "order" : 1}, + "ssl_secure" : { + "getopt" : "", + "longopt" : "ssl-secure", + "help" : "--ssl-secure Use SSL connection with verifying certificate", + "required" : "0", + "order" : 1}, + "notls" : { + "getopt" : "t", + "longopt" : "notls", + "help" : "-t, --notls " + "Disable TLS negotiation and force SSL3.0. " + "This should only be used for devices that do not support TLS1.0 and up.", + "required" : "0", + "order" : 1}, + "tls1.0" : { + "getopt" : "", + "longopt" : "tls1.0", + "help" : "--tls1.0 " + "Disable TLS negotiation and force TLS1.0. " + "This should only be used for devices that do not support TLS1.1 and up.", + "required" : "0", + "order" : 1}, + "port" : { + "getopt" : "n:", + "longopt" : "plug", + "help" : "-n, --plug=[id] " + "Physical plug number on device, UUID or identification of machine", + "required" : "1", + "order" : 1}, + "switch" : { + "getopt" : "s:", + "longopt" : "switch", + "help" : "-s, --switch=[id] Physical switch number on device", + "required" : "0", + "order" : 1}, + "exec" : { + "getopt" : "e:", + "longopt" : "exec", + "help" : "-e, --exec=[command] Command to execute", + "required" : "0", + "order" : 1}, + "vmware_type" : { + "getopt" : "d:", + "longopt" : "vmware_type", + "help" : "-d, --vmware_type=[type] Type of VMware to connect", + "required" : "0", + "order" : 1}, + "vmware_datacenter" : { + "getopt" : "s:", + "longopt" : "vmware-datacenter", + "help" : "-s, --vmware-datacenter=[dc] VMWare datacenter filter", + "required" : "0", + "order" : 2}, + "snmp_version" : { + "getopt" : "d:", + "longopt" : "snmp-version", + "help" : "-d, --snmp-version=[version] Specifies SNMP version to use (1|2c|3)", + "required" : "0", + "shortdesc" : "Specifies SNMP version to use", + "choices" : ["1", "2c", "3"], + "order" : 1}, + "community" : { + "getopt" : "c:", + "longopt" : "community", + "help" : "-c, --community=[community] Set the community string", + "required" : "0", + "order" : 1}, + "snmp_auth_prot" : { + "getopt" : "b:", + "longopt" : "snmp-auth-prot", + "help" : "-b, --snmp-auth-prot=[prot] Set authentication protocol (MD5|SHA)", + "required" : "0", + "shortdesc" : "Set authentication protocol", + "choices" : ["MD5", "SHA"], + "order" : 1}, + "snmp_sec_level" : { + "getopt" : "E:", + "longopt" : "snmp-sec-level", + "help" : "-E, --snmp-sec-level=[level] " + "Set security level (noAuthNoPriv|authNoPriv|authPriv)", + "required" : "0", + "shortdesc" : "Set security level", + "choices" : ["noAuthNoPriv", "authNoPriv", "authPriv"], + "order" : 1}, + "snmp_priv_prot" : { + "getopt" : "B:", + "longopt" : "snmp-priv-prot", + "help" : "-B, --snmp-priv-prot=[prot] Set privacy protocol (DES|AES)", + "required" : "0", + "shortdesc" : "Set privacy protocol", + "choices" : ["DES", "AES"], + "order" : 1}, + "snmp_priv_passwd" : { + "getopt" : "P:", + "longopt" : "snmp-priv-passwd", + "help" : "-P, --snmp-priv-passwd=[pass] Set privacy protocol password", + "required" : "0", + "order" : 1}, + "snmp_priv_passwd_script" : { + "getopt" : "R:", + "longopt" : "snmp-priv-passwd-script", + "help" : "-R, --snmp-priv-passwd-script Script to run to retrieve privacy password", + "required" : "0", + "order" : 1}, + "inet4_only" : { + "getopt" : "4", + "longopt" : "inet4-only", + "help" : "-4, --inet4-only Forces agent to use IPv4 addresses only", + "required" : "0", + "order" : 1}, + "inet6_only" : { + "getopt" : "6", + "longopt" : "inet6-only", + "help" : "-6, --inet6-only Forces agent to use IPv6 addresses only", + "required" : "0", + "order" : 1}, + "separator" : { + "getopt" : "C:", + "longopt" : "separator", + "help" : "-C, --separator=[char] Separator for CSV created by 'list' operation", + "default" : ",", + "required" : "0", + "order" : 100}, + "login_timeout" : { + "getopt" : ":", + "longopt" : "login-timeout", + "help" : "--login-timeout=[seconds] Wait X seconds for cmd prompt after login", + "default" : "5", + "required" : "0", + "order" : 200}, + "shell_timeout" : { + "getopt" : ":", + "longopt" : "shell-timeout", + "help" : "--shell-timeout=[seconds] Wait X seconds for cmd prompt after issuing command", + "default" : "3", + "required" : "0", + "order" : 200}, + "power_timeout" : { + "getopt" : ":", + "longopt" : "power-timeout", + "help" : "--power-timeout=[seconds] Test X seconds for status change after ON/OFF", + "default" : "20", + "required" : "0", + "order" : 200}, + "power_wait" : { + "getopt" : ":", + "longopt" : "power-wait", + "help" : "--power-wait=[seconds] Wait X seconds after issuing ON/OFF", + "default" : "0", + "required" : "0", + "order" : 200}, + "missing_as_off" : { + "getopt" : "", + "longopt" : "missing-as-off", + "help" : "--missing-as-off Missing port returns OFF instead of failure", + "required" : "0", + "order" : 200}, + "retry_on" : { + "getopt" : ":", + "longopt" : "retry-on", + "help" : "--retry-on=[attempts] Count of attempts to retry power on", + "default" : "1", + "required" : "0", + "order" : 201}, + "session_url" : { + "getopt" : "s:", + "longopt" : "session-url", + "help" : "-s, --session-url URL to connect to XenServer on", + "required" : "1", + "order" : 1}, + "sudo" : { + "getopt" : "", + "longopt" : "use-sudo", + "help" : "--use-sudo Use sudo (without password) when calling 3rd party software", + "required" : "0", + "order" : 205}, + "method" : { + "getopt" : "m:", + "longopt" : "method", + "help" : "-m, --method=[method] Method to fence (onoff|cycle) (Default: onoff)", + "required" : "0", + "shortdesc" : "Method to fence", + "default" : "onoff", + "choices" : ["onoff", "cycle"], + "order" : 1}, + "telnet_path" : { + "getopt" : ":", + "longopt" : "telnet-path", + "help" : "--telnet-path=[path] Path to telnet binary", + "required" : "0", + "default" : "/usr/bin/telnet", + "order": 300}, + "ssh_path" : { + "getopt" : ":", + "longopt" : "ssh-path", + "help" : "--ssh-path=[path] Path to ssh binary", + "required" : "0", + "default" : "/usr/bin/ssh", + "order": 300}, + "gnutlscli_path" : { + "getopt" : ":", + "longopt" : "gnutlscli-path", + "help" : "--gnutlscli-path=[path] Path to gnutls-cli binary", + "required" : "0", + "default" : "/usr/bin/gnutls-cli", + "order": 300}, + "sudo_path" : { + "getopt" : ":", + "longopt" : "sudo-path", + "help" : "--sudo-path=[path] Path to sudo binary", + "required" : "0", + "default" : "/usr/bin/sudo", + "order": 300}, + "snmpwalk_path" : { + "getopt" : ":", + "longopt" : "snmpwalk-path", + "help" : "--snmpwalk-path=[path] Path to snmpwalk binary", + "required" : "0", + "default" : "/usr/bin/snmpwalk", + "order" : 300}, + "snmpset_path" : { + "getopt" : ":", + "longopt" : "snmpset-path", + "help" : "--snmpset-path=[path] Path to snmpset binary", + "required" : "0", + "default" : "/usr/bin/snmpset", + "order" : 300}, + "snmpget_path" : { + "getopt" : ":", + "longopt" : "snmpget-path", + "help" : "--snmpget-path=[path] Path to snmpget binary", + "required" : "0", + "default" : "/usr/bin/snmpget", + "order" : 300}, + "snmp": { + "getopt" : "", + "help" : "", + "order" : 1}, + "port_as_ip": { + "getopt" : "", + "longopt" : "port-as-ip", + "help" : "--port-as-ip Make \"port/plug\" to be an alias to IP address", + "required" : "0", + "order" : 200}, + "on_target": { + "getopt" : "", + "help" : "", + "order" : 1}, + "quiet": { + "getopt" : "q", + "longopt": "quiet", + "help" : "-q, --quiet Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog.", + "required" : "0", + "order" : 50} +} + +# options which are added automatically if 'key' is encountered ("default" is always added) +DEPENDENCY_OPT = { + "default" : ["help", "debug", "verbose", "version", "action", "agent", \ + "power_timeout", "shell_timeout", "login_timeout", "power_wait", "retry_on", \ + "delay", "quiet"], + "passwd" : ["passwd_script"], + "sudo" : ["sudo_path"], + "secure" : ["identity_file", "ssh_options", "ssh_path"], + "telnet" : ["telnet_path"], + "ipaddr" : ["ipport", "inet4_only", "inet6_only"], + "port" : ["separator"], + "ssl" : ["ssl_secure", "ssl_insecure", "gnutlscli_path"], + "snmp" : ["snmp_auth_prot", "snmp_sec_level", "snmp_priv_prot", \ + "snmp_priv_passwd", "snmp_priv_passwd_script", "community", \ + "snmpset_path", "snmpget_path", "snmpwalk_path"] + } + +class fspawn(pexpect.spawn): + def __init__(self, options, command): + logging.info("Running command: %s", command) + pexpect.spawn.__init__(self, command) + self.opt = options + + def log_expect(self, pattern, timeout): + result = self.expect(pattern, timeout) + logging.debug("Received: %s", str(self.before) + str(self.after)) + return result + + def send(self, message): + logging.debug("Sent: %s", message) + return pexpect.spawn.send(self, message) + + # send EOL according to what was detected in login process (telnet) + def send_eol(self, message): + return self.send(message + self.opt["eol"]) + +def atexit_handler(): + try: + sys.stdout.close() + os.close(1) + except IOError: + logging.error("%s failed to close standard output\n", sys.argv[0]) + sys.exit(EC_GENERIC_ERROR) + +def _add_dependency_options(options): + ## Add also options which are available for every fence agent + added_opt = [] + for opt in options + ["default"]: + if DEPENDENCY_OPT.has_key(opt): + added_opt.extend([y for y in DEPENDENCY_OPT[opt] if options.count(y) == 0]) + + if not "port" in (options + added_opt) and \ + not "nodename" in (options + added_opt) and \ + "ipaddr" in (options + added_opt): + added_opt.append("port_as_ip") + all_opt["port"]["help"] = "-n, --plug=[ip] IP address or hostname of fencing device " \ + "(together with --port-as-ip)" + + return added_opt + +def fail_usage(message="", stop=True): + if len(message) > 0: + logging.error("%s\n", message) + if stop: + logging.error("Please use '-h' for usage\n") + sys.exit(EC_GENERIC_ERROR) + +def fail(error_code): + message = { + EC_LOGIN_DENIED : "Unable to connect/login to fencing device", + EC_CONNECTION_LOST : "Connection lost", + EC_TIMED_OUT : "Connection timed out", + EC_WAITING_ON : "Failed: Timed out waiting to power ON", + EC_WAITING_OFF : "Failed: Timed out waiting to power OFF", + EC_STATUS : "Failed: Unable to obtain correct plug status or plug is not available", + EC_STATUS_HMC : "Failed: Either unable to obtain correct plug status, " + "partition is not available or incorrect HMC version used", + EC_PASSWORD_MISSING : "Failed: You have to set login password", + EC_INVALID_PRIVILEGES : "Failed: The user does not have the correct privileges to do the requested action." + }[error_code] + "\n" + logging.error("%s\n", message) + sys.exit(EC_GENERIC_ERROR) + +def usage(avail_opt): + print "Usage:" + print "\t" + os.path.basename(sys.argv[0]) + " [options]" + print "Options:" + + sorted_list = [(key, all_opt[key]) for key in avail_opt] + sorted_list.sort(lambda x, y: cmp(x[1]["order"], y[1]["order"])) + + for key, value in sorted_list: + if len(value["help"]) != 0: + print " " + _join_wrap([value["help"]], first_indent=3) + +def metadata(avail_opt, docs): + # avail_opt has to be unique, if there are duplicities then they should be removed + sorted_list = [(key, all_opt[key]) for key in list(set(avail_opt))] + sorted_list.sort(lambda x, y: cmp(x[0], y[0])) + sorted_list.sort(lambda x, y: cmp(x[1]["order"], y[1]["order"])) + + print "<?xml version=\"1.0\" ?>" + print "<resource-agent name=\"" + os.path.basename(sys.argv[0]) + \ + "\" shortdesc=\"" + docs["shortdesc"] + "\" >" + for (symlink, desc) in docs.get("symlink", []): + print "<symlink name=\"" + symlink + "\" shortdesc=\"" + desc + "\"/>" + print "<longdesc>" + docs["longdesc"] + "</longdesc>" + print "<vendor-url>" + docs["vendorurl"] + "</vendor-url>" + print "<parameters>" + for option, _ in sorted_list: + if all_opt[option].has_key("help") and len(all_opt[option]["help"]) > 0: + print "\t<parameter name=\"" + option + "\" unique=\"0\" required=\"" + all_opt[option]["required"] + "\">" + + default = "" + if all_opt[option].has_key("default"): + default = "default=\"" + _encode_html_entities(str(all_opt[option]["default"])) + "\" " + + mixed = all_opt[option]["help"] + ## split it between option and help text + res = re.compile(r"^(.*?--\S+)\s+", re.IGNORECASE | re.S).search(mixed) + if None != res: + mixed = res.group(1) + mixed = _encode_html_entities(mixed) + + if not "shortdesc" in all_opt[option]: + shortdesc = re.sub("\s\s+", " ", all_opt[option]["help"][31:]) + else: + shortdesc = all_opt[option]["shortdesc"] + + print "\t\t<getopt mixed=\"" + mixed + "\" />" + if all_opt[option].has_key("choices"): + print "\t\t<content type=\"select\" "+default+" >" + for choice in all_opt[option]["choices"]: + print "\t\t\t<option value=\"%s\" />" % (choice) + print "\t\t</content>" + elif all_opt[option]["getopt"].count(":") > 0: + print "\t\t<content type=\"string\" "+default+" />" + else: + print "\t\t<content type=\"boolean\" "+default+" />" + print "\t\t<shortdesc lang=\"en\">" + shortdesc + "</shortdesc>" + print "\t</parameter>" + print "</parameters>" + print "<actions>" + + (available_actions, _) = _get_available_actions(avail_opt) + + if "on" in available_actions: + available_actions.remove("on") + on_target = ' on_target="1"' if avail_opt.count("on_target") else '' + print "\t<action name=\"on\"%s automatic=\"%d\"/>" % (on_target, avail_opt.count("fabric_fencing")) + + for action in available_actions: + print "\t<action name=\"%s\" />" % (action) + print "</actions>" + print "</resource-agent>" + +def process_input(avail_opt): + avail_opt.extend(_add_dependency_options(avail_opt)) + + # @todo: this should be put elsewhere? + os.putenv("LANG", "C") + os.putenv("LC_ALL", "C") + + if "port_as_ip" in avail_opt: + avail_opt.append("port") + + if len(sys.argv) > 1: + opt = _parse_input_cmdline(avail_opt) + else: + opt = _parse_input_stdin(avail_opt) + + if "--port-as-ip" in opt and "--plug" in opt: + opt["--ip"] = opt["--plug"] + + return opt + +## +## This function checks input and answers if we want to have same answers +## in each of the fencing agents. It looks for possible errors and run +## password script to set a correct password +###### +def check_input(device_opt, opt, other_conditions = False): + device_opt.extend(_add_dependency_options(device_opt)) + + options = dict(opt) + options["device_opt"] = device_opt + + _update_metadata(options) + options = _set_default_values(options) + options["--action"] = options["--action"].lower() + + ## In special cases (show help, metadata or version) we don't need to check anything + ##### + # OCF compatibility + if options["--action"] == "meta-data": + options["--action"] = "metadata" + + if options["--action"] == "metadata" or any(options.has_key(k) for k in ("--help", "--version")): + return options + + if options.has_key("--verbose"): + logging.getLogger().setLevel(logging.DEBUG) + + ## add logging to syslog + logging.getLogger().addHandler(SyslogLibHandler()) + if not options.has_key("--quiet"): + ## add logging to stderr + logging.getLogger().addHandler(logging.StreamHandler(sys.stderr)) + + (acceptable_actions, _) = _get_available_actions(device_opt) + + if 1 == device_opt.count("fabric_fencing"): + acceptable_actions.extend(["enable", "disable"]) + + if 0 == acceptable_actions.count(options["--action"]): + fail_usage("Failed: Unrecognised action '" + options["--action"] + "'") + + ## Compatibility layer + ##### + if options["--action"] == "enable": + options["--action"] = "on" + if options["--action"] == "disable": + options["--action"] = "off" + + + if options["--action"] == "validate-all" and not other_conditions: + _validate_input(options, False) + sys.exit(EC_OK) + else: + _validate_input(options, True) + + if options.has_key("--debug-file"): + try: + debug_file = logging.FileHandler(options["--debug-file"]) + debug_file.setLevel(logging.DEBUG) + logging.getLogger().addHandler(debug_file) + except IOError: + logging.error("Unable to create file %s", options["--debug-file"]) + fail_usage("Failed: Unable to create file " + options["--debug-file"]) + + if options.has_key("--snmp-priv-passwd-script"): + options["--snmp-priv-passwd"] = os.popen(options["--snmp-priv-passwd-script"]).read().rstrip() + + if options.has_key("--password-script"): + options["--password"] = os.popen(options["--password-script"]).read().rstrip() + + return options + +## Obtain a power status from possibly more than one plug +## "on" is returned if at least one plug is ON +###### +def get_multi_power_fn(connection, options, get_power_fn): + status = "off" + plugs = options["--plugs"] if options.has_key("--plugs") else [""] + + for plug in plugs: + try: + options["--uuid"] = str(uuid.UUID(plug)) + except ValueError: + pass + except KeyError: + pass + + options["--plug"] = plug + plug_status = get_power_fn(connection, options) + if plug_status != "off": + status = plug_status + + return status + +def set_multi_power_fn(connection, options, set_power_fn, get_power_fn, retry_attempts=1): + plugs = options["--plugs"] if options.has_key("--plugs") else [""] + + for _ in range(retry_attempts): + for plug in plugs: + try: + options["--uuid"] = str(uuid.UUID(plug)) + except ValueError: + pass + except KeyError: + pass + + options["--plug"] = plug + set_power_fn(connection, options) + time.sleep(int(options["--power-wait"])) + + for _ in xrange(int(options["--power-timeout"])): + if get_multi_power_fn(connection, options, get_power_fn) != options["--action"]: + time.sleep(1) + else: + return True + return False + +def show_docs(options, docs=None): + device_opt = options["device_opt"] + + if docs == None: + docs = {} + docs["shortdesc"] = "Fence agent" + docs["longdesc"] = "" + + if options.has_key("--help"): + usage(device_opt) + sys.exit(0) + + if options.get("--action", "") == "metadata": + if "port_as_ip" in device_opt: + device_opt.remove("separator") + metadata(device_opt, docs) + sys.exit(0) + + if options.has_key("--version"): + print __main__.RELEASE_VERSION, __main__.BUILD_DATE + print __main__.REDHAT_COPYRIGHT + sys.exit(0) + +def fence_action(connection, options, set_power_fn, get_power_fn, get_outlet_list=None, reboot_cycle_fn=None): + result = 0 + + try: + if options.has_key("--plug"): + options["--plugs"] = options["--plug"].split(",") + + ## Process options that manipulate fencing device + ##### + if (options["--action"] in ["list", "list-status"]) or \ + ((options["--action"] == "monitor") and 1 == options["device_opt"].count("port") and \ + 0 == options["device_opt"].count("port_as_ip")): + + if 0 == options["device_opt"].count("port"): + print "N/A" + elif get_outlet_list == None: + ## @todo: exception? + ## This is just temporal solution, we will remove default value + ## None as soon as all existing agent will support this operation + print "NOTICE: List option is not working on this device yet" + else: + options["--original-action"] = options["--action"] + options["--action"] = "list" + outlets = get_outlet_list(connection, options) + options["--action"] = options["--original-action"] + del options["--original-action"] + + ## keys can be numbers (port numbers) or strings (names of VM, UUID) + for outlet_id in outlets.keys(): + (alias, status) = outlets[outlet_id] + if status is None or (not status.upper() in ["ON", "OFF"]): + status = "UNKNOWN" + status = status.upper() + + if options["--action"] == "list": + print outlet_id + options["--separator"] + alias + elif options["--action"] == "list-status": + print outlet_id + options["--separator"] + alias + options["--separator"] + status + + return + + if options["--action"] == "monitor" and not "port" in options["device_opt"] and "no_status" in options["device_opt"]: + # Unable to do standard monitoring because 'status' action is not available + return 0 + + status = None + if not "no_status" in options["device_opt"]: + status = get_multi_power_fn(connection, options, get_power_fn) + if status != "on" and status != "off": + fail(EC_STATUS) + + if options["--action"] == status: + if not (status == "on" and "force_on" in options["device_opt"]): + print "Success: Already %s" % (status.upper()) + return 0 + + if options["--action"] == "on": + if set_multi_power_fn(connection, options, set_power_fn, get_power_fn, 1 + int(options["--retry-on"])): + print "Success: Powered ON" + else: + fail(EC_WAITING_ON) + elif options["--action"] == "off": + if set_multi_power_fn(connection, options, set_power_fn, get_power_fn): + print "Success: Powered OFF" + else: + fail(EC_WAITING_OFF) + elif options["--action"] == "reboot": + power_on = False + if options.get("--method", "").lower() == "cycle" and reboot_cycle_fn is not None: + for _ in range(1, 1 + int(options["--retry-on"])): + if reboot_cycle_fn(connection, options): + power_on = True + break + + if not power_on: + fail(EC_TIMED_OUT) + + else: + if status != "off": + options["--action"] = "off" + if not set_multi_power_fn(connection, options, set_power_fn, get_power_fn): + fail(EC_WAITING_OFF) + + options["--action"] = "on" + + try: + power_on = set_multi_power_fn(connection, options, set_power_fn, get_power_fn, int(options["--retry-on"])) + except Exception, ex: + # an error occured during power ON phase in reboot + # fence action was completed succesfully even in that case + logging.warning("%s", str(ex)) + + if power_on == False: + # this should not fail as node was fenced succesfully + logging.error('Timed out waiting to power ON\n') + + print "Success: Rebooted" + elif options["--action"] == "status": + print "Status: " + status.upper() + if status.upper() == "OFF": + result = 2 + elif options["--action"] == "monitor": + pass + except pexpect.EOF: + fail(EC_CONNECTION_LOST) + except pexpect.TIMEOUT: + fail(EC_TIMED_OUT) + except pycurl.error, ex: + logging.error("%s\n", str(ex)) + fail(EC_TIMED_OUT) + except socket.timeout, ex: + logging.error("%s\n", str(ex)) + fail(EC_TIMED_OUT) + + return result + +def fence_login(options, re_login_string=r"(login\s*: )|((?!Last )Login Name: )|(username: )|(User Name :)"): + run_delay(options) + + if not options.has_key("eol"): + options["eol"] = "\r\n" + + if options.has_key("--command-prompt") and type(options["--command-prompt"]) is not list: + options["--command-prompt"] = [options["--command-prompt"]] + + try: + if options.has_key("--ssl"): + conn = _open_ssl_connection(options) + elif options.has_key("--ssh") and not options.has_key("--identity-file"): + conn = _login_ssh_with_password(options, re_login_string) + elif options.has_key("--ssh") and options.has_key("--identity-file"): + conn = _login_ssh_with_identity_file(options) + else: + conn = _login_telnet(options, re_login_string) + except pexpect.EOF, exception: + logging.debug("%s", str(exception)) + fail(EC_LOGIN_DENIED) + except pexpect.TIMEOUT, exception: + logging.debug("%s", str(exception)) + fail(EC_LOGIN_DENIED) + return conn + +def is_executable(path): + if os.path.exists(path): + stats = os.stat(path) + if stat.S_ISREG(stats.st_mode) and os.access(path, os.X_OK): + return True + return False + +def run_command(options, command, timeout=None, env=None, log_command=None): + if timeout is None and "--power-timeout" in options: + timeout = options["--power-timeout"] + if timeout is not None: + timeout = float(timeout) + + logging.info("Executing: %s\n", log_command or command) + + try: + process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + except OSError: + fail_usage("Unable to run %s\n" % command) + + thread = threading.Thread(target=process.wait) + thread.start() + thread.join(timeout) + if thread.is_alive(): + process.kill() + fail(EC_TIMED_OUT) + + status = process.wait() + + (pipe_stdout, pipe_stderr) = process.communicate() + process.stdout.close() + process.stderr.close() + + logging.debug("%s %s %s\n", str(status), str(pipe_stdout), str(pipe_stderr)) + + return (status, pipe_stdout, pipe_stderr) + +def run_delay(options): + ## Delay is important for two-node clusters fencing but we do not need to delay 'status' operations + if options["--action"] in ["off", "reboot"]: + logging.info("Delay %s second(s) before logging in to the fence device", options["--delay"]) + time.sleep(int(options["--delay"])) + +def fence_logout(conn, logout_string, sleep=0): + # Logout is not required part of fencing but we should attempt to do it properly + # In some cases our 'exit' command is faster and we can not close connection as it + # was already closed by fencing device + try: + conn.send_eol(logout_string) + time.sleep(sleep) + conn.close() + except exceptions.OSError: + pass + except pexpect.ExceptionPexpect: + pass + +# Convert array of format [[key1, value1], [key2, value2], ... [keyN, valueN]] to dict, where key is +# in format a.b.c.d...z and returned dict has key only z +def array_to_dict(array): + return dict([[x[0].split(".")[-1], x[1]] for x in array]) + +## Own logger handler that uses old-style syslog handler as otherwise everything is sourced +## from /dev/syslog +class SyslogLibHandler(logging.StreamHandler): + """ + A handler class that correctly push messages into syslog + """ + def emit(self, record): + syslog_level = { + logging.CRITICAL:syslog.LOG_CRIT, + logging.ERROR:syslog.LOG_ERR, + logging.WARNING:syslog.LOG_WARNING, + logging.INFO:syslog.LOG_INFO, + logging.DEBUG:syslog.LOG_DEBUG, + logging.NOTSET:syslog.LOG_DEBUG, + }[record.levelno] + + msg = self.format(record) + + # syslos.syslog can not have 0x00 character inside or exception is thrown + syslog.syslog(syslog_level, msg.replace("\x00", "\n")) + return + +def _open_ssl_connection(options): + gnutls_opts = "" + ssl_opts = "" + + if options.has_key("--notls"): + gnutls_opts = "--priority \"NORMAL:-VERS-TLS1.2:-VERS-TLS1.1:-VERS-TLS1.0:+VERS-SSL3.0\"" + elif options.has_key("--tls1.0"): + gnutls_opts = "--priority \"NORMAL:-VERS-TLS1.2:-VERS-TLS1.1:+VERS-TLS1.0:%LATEST_RECORD_VERSION\"" + + # --ssl is same as the --ssl-secure; it means we want to verify certificate in these cases + if options.has_key("--ssl-insecure"): + ssl_opts = "--insecure" + + command = '%s %s %s --crlf -p %s %s' % \ + (options["--gnutlscli-path"], gnutls_opts, ssl_opts, options["--ipport"], options["--ip"]) + try: + conn = fspawn(options, command) + except pexpect.ExceptionPexpect, ex: + logging.error("%s\n", str(ex)) + sys.exit(EC_GENERIC_ERROR) + + return conn + +def _login_ssh_with_identity_file(options): + if options.has_key("--inet6-only"): + force_ipvx = "-6 " + elif options.has_key("--inet4-only"): + force_ipvx = "-4 " + else: + force_ipvx = "" + + command = '%s %s %s@%s -i %s -p %s' % \ + (options["--ssh-path"], force_ipvx, options["--username"], options["--ip"], \ + options["--identity-file"], options["--ipport"]) + if options.has_key("--ssh-options"): + command += ' ' + options["--ssh-options"] + + conn = fspawn(options, command) + + result = conn.log_expect(["Enter passphrase for key '" + options["--identity-file"] + "':", \ + "Are you sure you want to continue connecting (yes/no)?"] + \ + options["--command-prompt"], int(options["--login-timeout"])) + if result == 1: + conn.sendline("yes") + result = conn.log_expect( + ["Enter passphrase for key '" + options["--identity-file"]+"':"] + \ + options["--command-prompt"], int(options["--login-timeout"])) + if result == 0: + if options.has_key("--password"): + conn.sendline(options["--password"]) + conn.log_expect(options["--command-prompt"], int(options["--login-timeout"])) + else: + fail_usage("Failed: You have to enter passphrase (-p) for identity file") + + return conn + +def _login_telnet(options, re_login_string): + re_login = re.compile(re_login_string, re.IGNORECASE) + re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE) + + conn = fspawn(options, options["--telnet-path"]) + conn.send("set binary\n") + conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) + + conn.log_expect(re_login, int(options["--login-timeout"])) + conn.send_eol(options["--username"]) + + ## automatically change end of line separator + screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) + if re_login.search(screen) != None: + options["eol"] = "\n" + conn.send_eol(options["--username"]) + conn.log_expect(re_pass, int(options["--login-timeout"])) + elif re_pass.search(screen) == None: + conn.log_expect(re_pass, int(options["--shell-timeout"])) + + try: + conn.send_eol(options["--password"]) + valid_password = conn.log_expect([re_login] + \ + options["--command-prompt"], int(options["--shell-timeout"])) + if valid_password == 0: + ## password is invalid or we have to change EOL separator + options["eol"] = "\r" + conn.send_eol("") + screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) + ## after sending EOL the fence device can either show 'Login' or 'Password' + if re_login.search(conn.after + screen) != None: + conn.send_eol("") + conn.send_eol(options["--username"]) + conn.log_expect(re_pass, int(options["--login-timeout"])) + conn.send_eol(options["--password"]) + conn.log_expect(options["--command-prompt"], int(options["--login-timeout"])) + except KeyError: + fail(EC_PASSWORD_MISSING) + + return conn + +def _login_ssh_with_password(options, re_login_string): + re_login = re.compile(re_login_string, re.IGNORECASE) + re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE) + + if options.has_key("--inet6-only"): + force_ipvx = "-6 " + elif options.has_key("--inet4-only"): + force_ipvx = "-4 " + else: + force_ipvx = "" + + command = '%s %s %s@%s -p %s -o PubkeyAuthentication=no' % \ + (options["--ssh-path"], force_ipvx, options["--username"], options["--ip"], options["--ipport"]) + if options.has_key("--ssh-options"): + command += ' ' + options["--ssh-options"] + + conn = fspawn(options, command) + + if options.has_key("telnet_over_ssh"): + # This is for stupid ssh servers (like ALOM) which behave more like telnet + # (ignore name and display login prompt) + result = conn.log_expect( \ + [re_login, "Are you sure you want to continue connecting (yes/no)?"], + int(options["--login-timeout"])) + if result == 1: + conn.sendline("yes") # Host identity confirm + conn.log_expect(re_login, int(options["--login-timeout"])) + + conn.sendline(options["--username"]) + conn.log_expect(re_pass, int(options["--login-timeout"])) + else: + result = conn.log_expect( \ + ["ssword:", "Are you sure you want to continue connecting (yes/no)?"], + int(options["--login-timeout"])) + if result == 1: + conn.sendline("yes") + conn.log_expect("ssword:", int(options["--login-timeout"])) + + conn.sendline(options["--password"]) + conn.log_expect(options["--command-prompt"], int(options["--login-timeout"])) + + return conn + +# +# To update metadata, we change values in all_opt +def _update_metadata(options): + device_opt = options["device_opt"] + + if device_opt.count("login") and device_opt.count("no_login") == 0: + all_opt["login"]["required"] = "1" + else: + all_opt["login"]["required"] = "0" + + if device_opt.count("port_as_ip"): + all_opt["ipaddr"]["required"] = "0" + all_opt["port"]["required"] = "0" + + (available_actions, default_value) = _get_available_actions(device_opt) + all_opt["action"]["default"] = default_value + + actions_with_default = \ + [x if not x == all_opt["action"]["default"] else x + " (default)" for x in available_actions] + all_opt["action"]["help"] = \ + "-o, --action=[action] Action: %s" % (_join_wrap(actions_with_default, last_separator=" or ")) + + if device_opt.count("ipport"): + default_value = None + default_string = None + + if all_opt["ipport"].has_key("default"): + default_value = all_opt["ipport"]["default"] + elif device_opt.count("web") and device_opt.count("ssl"): + default_value = "80" + default_string = "(default 80, 443 if --ssl option is used)" + elif device_opt.count("telnet") and device_opt.count("secure"): + default_value = "23" + default_string = "(default 23, 22 if --ssh option is used)" + else: + tcp_ports = {"community" : "161", "secure" : "22", "telnet" : "23", "web" : "80", "ssl" : "443"} + # all cases where next command returns multiple results are covered by previous blocks + protocol = [x for x in ["community", "secure", "ssl", "web", "telnet"] if device_opt.count(x)][0] + default_value = tcp_ports[protocol] + + if default_string is None: + all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default %s)" % \ + (default_value) + else: + all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use\n" + " "*40 + default_string + +def _set_default_values(options): + if "ipport" in options["device_opt"]: + if not "--ipport" in options: + if "default" in all_opt["ipport"]: + options["--ipport"] = all_opt["ipport"]["default"] + elif "community" in options["device_opt"]: + options["--ipport"] = "161" + elif "--ssh" in options or all_opt["secure"].get("default", "0") == "1": + options["--ipport"] = "22" + elif "--ssl" in options or all_opt["ssl"].get("default", "0") == "1": + options["--ipport"] = "443" + elif "--ssl-secure" in options or all_opt["ssl_secure"].get("default", "0") == "1": + options["--ipport"] = "443" + elif "--ssl-insecure" in options or all_opt["ssl_insecure"].get("default", "0") == "1": + options["--ipport"] = "443" + elif "web" in options["device_opt"]: + options["--ipport"] = "80" + elif "telnet" in options["device_opt"]: + options["--ipport"] = "23" + + if "--ipport" in options: + all_opt["ipport"]["default"] = options["--ipport"] + + for opt in options["device_opt"]: + if all_opt[opt].has_key("default") and not opt == "ipport": + getopt_long = "--" + all_opt[opt]["longopt"] + if not options.has_key(getopt_long): + options[getopt_long] = all_opt[opt]["default"] + + return options + +# stop = True/False : exit fence agent when problem is encountered +def _validate_input(options, stop = True): + device_opt = options["device_opt"] + valid_input = True + + if not options.has_key("--username") and \ + device_opt.count("login") and (device_opt.count("no_login") == 0): + valid_input = False + fail_usage("Failed: You have to set login name", stop) + + if device_opt.count("ipaddr") and not options.has_key("--ip") and not options.has_key("--managed"): + valid_input = False + fail_usage("Failed: You have to enter fence address", stop) + + if device_opt.count("no_password") == 0: + if 0 == device_opt.count("identity_file"): + if not (options.has_key("--password") or options.has_key("--password-script")): + valid_input = False + fail_usage("Failed: You have to enter password or password script", stop) + else: + if not (options.has_key("--password") or \ + options.has_key("--password-script") or options.has_key("--identity-file")): + valid_input = False + fail_usage("Failed: You have to enter password, password script or identity file", stop) + + if not options.has_key("--ssh") and options.has_key("--identity-file"): + valid_input = False + fail_usage("Failed: You have to use identity file together with ssh connection (-x)", stop) + + if options.has_key("--identity-file") and not os.path.isfile(options["--identity-file"]): + valid_input = False + fail_usage("Failed: Identity file " + options["--identity-file"] + " does not exist", stop) + + if (0 == ["list", "list-status", "monitor"].count(options["--action"])) and \ + not options.has_key("--plug") and device_opt.count("port") and \ + device_opt.count("no_port") == 0 and not device_opt.count("port_as_ip"): + valid_input = False + fail_usage("Failed: You have to enter plug number or machine identification", stop) + + if options.has_key("--plug") and len(options["--plug"].split(",")) > 1 and \ + options.has_key("--method") and options["--method"] == "cycle": + valid_input = False + fail_usage("Failed: Cannot use --method cycle for more than 1 plug", stop) + + for failed_opt in _get_opts_with_invalid_choices(options): + valid_input = False + fail_usage("Failed: You have to enter a valid choice for %s from the valid values: %s" % \ + ("--" + all_opt[failed_opt]["longopt"], str(all_opt[failed_opt]["choices"])), stop) + + return valid_input + +def _encode_html_entities(text): + return text.replace("&", "&").replace('"', """).replace('<', "<"). \ + replace('>', ">").replace("'", "'") + +def _prepare_getopt_args(options): + getopt_string = "" + longopt_list = [] + for k in options: + if all_opt.has_key(k) and all_opt[k]["getopt"] != ":": + # getopt == ":" means that opt is without short getopt, but has value + getopt_string += all_opt[k]["getopt"] + elif not all_opt.has_key(k): + fail_usage("Parse error: unknown option '"+k+"'") + + if all_opt.has_key(k) and all_opt[k].has_key("longopt"): + if all_opt[k]["getopt"].endswith(":"): + longopt_list.append(all_opt[k]["longopt"] + "=") + else: + longopt_list.append(all_opt[k]["longopt"]) + + return (getopt_string, longopt_list) + +def _parse_input_stdin(avail_opt): + opt = {} + name = "" + for line in sys.stdin.readlines(): + line = line.strip() + if (line.startswith("#")) or (len(line) == 0): + continue + + (name, value) = (line + "=").split("=", 1) + value = value[:-1] + + if avail_opt.count(name) == 0 and name in ["nodename"]: + continue + elif avail_opt.count(name) == 0: + logging.warning("Parse error: Ignoring unknown option '%s'\n", line) + continue + + if all_opt[name]["getopt"].endswith(":"): + opt["--"+all_opt[name]["longopt"].rstrip(":")] = value + elif value.lower() in ["1", "yes", "on", "true"]: + opt["--"+all_opt[name]["longopt"]] = "1" + else: + logging.warning("Parse error: Ignoring option '%s' because it does not have value\n", name) + return opt + +def _parse_input_cmdline(avail_opt): + filtered_opts = {} + _verify_unique_getopt(avail_opt) + (getopt_string, longopt_list) = _prepare_getopt_args(avail_opt) + + try: + (entered_opt, left_arg) = getopt.gnu_getopt(sys.argv[1:], getopt_string, longopt_list) + if len(left_arg) > 0: + logging.warning("Unused arguments on command line: %s" % (str(left_arg))) + except getopt.GetoptError, error: + fail_usage("Parse error: " + error.msg) + + for opt in avail_opt: + filtered_opts.update({opt : all_opt[opt]}) + + # Short and long getopt names are changed to consistent "--" + long name (e.g. --username) + long_opts = {} + for arg_name in dict(entered_opt).keys(): + all_key = [key for (key, value) in filtered_opts.items() \ + if "--" + value.get("longopt", "") == arg_name or "-" + value.get("getopt", "").rstrip(":") == arg_name][0] + long_opts["--" + filtered_opts[all_key]["longopt"]] = dict(entered_opt)[arg_name] + + # This test is specific because it does not apply to input on stdin + if "port_as_ip" in avail_opt and not "--port-as-ip" in long_opts and "--plug" in long_opts: + fail_usage("Parser error: option -n/--plug is not recognized") + + return long_opts + +# for ["John", "Mary", "Eli"] returns "John, Mary and Eli" +def _join2(words, normal_separator=", ", last_separator=" and "): + if len(words) <= 1: + return "".join(words) + else: + return last_separator.join([normal_separator.join(words[:-1]), words[-1]]) + +def _join_wrap(words, normal_separator=", ", last_separator=" and ", first_indent=42): + x = _join2(words, normal_separator, last_separator) + wrapper = textwrap.TextWrapper() + wrapper.initial_indent = " "*first_indent + wrapper.subsequent_indent = " "*40 + wrapper.width = 85 + wrapper.break_on_hyphens = False + wrapper.break_long_words = False + wrapped_text = "" + for line in wrapper.wrap(x): + wrapped_text += line + "\n" + return wrapped_text.lstrip().rstrip("\n") + +def _get_opts_with_invalid_choices(options): + options_failed = [] + device_opt = options["device_opt"] + + for opt in device_opt: + if all_opt[opt].has_key("choices"): + longopt = "--" + all_opt[opt]["longopt"] + possible_values_upper = [y.upper() for y in all_opt[opt]["choices"]] + if options.has_key(longopt): + options[longopt] = options[longopt].upper() + if not options["--" + all_opt[opt]["longopt"]] in possible_values_upper: + options_failed.append(opt) + return options_failed + +def _verify_unique_getopt(avail_opt): + used_getopt = set() + + for opt in avail_opt: + getopt_value = all_opt[opt].get("getopt", "").rstrip(":") + if getopt_value and getopt_value in used_getopt: + fail_usage("Short getopt for %s (-%s) is not unique" % (opt, getopt_value)) + else: + used_getopt.add(getopt_value) + +def _get_available_actions(device_opt): + available_actions = ["on", "off", "reboot", "status", "list", "list-status", \ + "monitor", "metadata", "validate-all"] + default_value = "reboot" + + if device_opt.count("fabric_fencing"): + available_actions.remove("reboot") + default_value = "off" + if device_opt.count("no_status"): + available_actions.remove("status") + if device_opt.count("no_on"): + available_actions.remove("on") + if device_opt.count("no_off"): + available_actions.remove("off") + if not device_opt.count("separator"): + available_actions.remove("list") + available_actions.remove("list-status") + + return (available_actions, default_value) diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py new file mode 100644 index 0000000..c947bf2 --- /dev/null +++ b/agents/aws/fence_aws.py @@ -0,0 +1,223 @@ +#!@PYTHON@ -tt + +import sys, re +import logging +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, run_delay, EC_STATUS, SyslogLibHandler + +import requests +from requests import HTTPError + +try: + import boto3 + from botocore.exceptions import ConnectionError, ClientError, EndpointConnectionError, NoRegionError +except ImportError: + pass + +logger = logging.getLogger("fence_aws") +logger.propagate = False +logger.setLevel(logging.INFO) +logger.addHandler(SyslogLibHandler()) +logging.getLogger('botocore.vendored').propagate = False + +def get_instance_id(): + try: + token = requests.put('http://169.254.169.254/latest/api/token', headers={"X-aws-ec2-metadata-token-ttl-seconds" : "21600"}).content.decode("UTF-8") + r = requests.get('http://169.254.169.254/latest/meta-data/instance-id', headers={"X-aws-ec2-metadata-token" : token}).content.decode("UTF-8") + return r + except HTTPError as http_err: + logger.error('HTTP error occurred while trying to access EC2 metadata server: %s', http_err) + except Exception as err: + logger.error('A fatal error occurred while trying to access EC2 metadata server: %s', err) + return None + + +def get_nodes_list(conn, options): + logger.info("Starting monitor operation") + result = {} + try: + if "--filter" in options: + filter_key = options["--filter"].split("=")[0].strip() + filter_value = options["--filter"].split("=")[1].strip() + filter = [{ "Name": filter_key, "Values": [filter_value] }] + for instance in conn.instances.filter(Filters=filter): + result[instance.id] = ("", None) + else: + for instance in conn.instances.all(): + result[instance.id] = ("", None) + except ClientError: + fail_usage("Failed: Incorrect Access Key or Secret Key.") + except EndpointConnectionError: + fail_usage("Failed: Incorrect Region.") + except ConnectionError as e: + fail_usage("Failed: Unable to connect to AWS: " + str(e)) + except Exception as e: + logger.error("Failed to get node list: %s", e) + logger.debug("Monitor operation OK: %s",result) + return result + +def get_power_status(conn, options): + logger.debug("Starting status operation") + try: + instance = conn.instances.filter(Filters=[{"Name": "instance-id", "Values": [options["--plug"]]}]) + state = list(instance)[0].state["Name"] + logger.info("Status operation for EC2 instance %s returned state: %s",options["--plug"],state.upper()) + if state == "running": + return "on" + elif state == "stopped": + return "off" + else: + return "unknown" + + except ClientError: + fail_usage("Failed: Incorrect Access Key or Secret Key.") + except EndpointConnectionError: + fail_usage("Failed: Incorrect Region.") + except IndexError: + fail(EC_STATUS) + except Exception as e: + logging.error("Failed to get power status: %s", e) + fail(EC_STATUS) + +def get_self_power_status(conn, instance_id): + try: + instance = conn.instances.filter(Filters=[{"Name": "instance-id", "Values": [instance_id]}]) + state = list(instance)[0].state["Name"] + if state == "running": + logging.debug("Captured my (%s) state and it %s - returning OK - Proceeding with fencing",instance_id,state.upper()) + return "ok" + else: + logging.debug("Captured my (%s) state it is %s - returning Alert - Unable to fence other nodes",instance_id,state.upper()) + return "alert" + + except ClientError: + fail_usage("Failed: Incorrect Access Key or Secret Key.") + except EndpointConnectionError: + fail_usage("Failed: Incorrect Region.") + except IndexError: + return "fail" + +def set_power_status(conn, options): + my_instance = get_instance_id() + try: + if (options["--action"]=="off"): + if (get_self_power_status(conn,my_instance) == "ok"): + conn.instances.filter(InstanceIds=[options["--plug"]]).stop(Force=True) + logger.info("Called StopInstance API call for %s", options["--plug"]) + else: + logger.info("Skipping fencing as instance is not in running status") + elif (options["--action"]=="on"): + conn.instances.filter(InstanceIds=[options["--plug"]]).start() + except Exception as e: + logger.error("Failed to power %s %s: %s", \ + options["--action"], options["--plug"], e) + +def define_new_opts(): + all_opt["region"] = { + "getopt" : "r:", + "longopt" : "region", + "help" : "-r, --region=[region] Region, e.g. us-east-1", + "shortdesc" : "Region.", + "required" : "0", + "order" : 2 + } + all_opt["access_key"] = { + "getopt" : "a:", + "longopt" : "access-key", + "help" : "-a, --access-key=[key] Access Key", + "shortdesc" : "Access Key.", + "required" : "0", + "order" : 3 + } + all_opt["secret_key"] = { + "getopt" : "s:", + "longopt" : "secret-key", + "help" : "-s, --secret-key=[key] Secret Key", + "shortdesc" : "Secret Key.", + "required" : "0", + "order" : 4 + } + all_opt["filter"] = { + "getopt" : ":", + "longopt" : "filter", + "help" : "--filter=[key=value] Filter (e.g. vpc-id=[vpc-XXYYZZAA]", + "shortdesc": "Filter for list-action", + "required": "0", + "order": 5 + } + all_opt["boto3_debug"] = { + "getopt" : "b:", + "longopt" : "boto3_debug", + "help" : "-b, --boto3_debug=[option] Boto3 and Botocore library debug logging", + "shortdesc": "Boto Lib debug", + "required": "0", + "default": "False", + "order": 6 + } + +# Main agent method +def main(): + conn = None + + device_opt = ["port", "no_password", "region", "access_key", "secret_key", "filter", "boto3_debug"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["power_timeout"]["default"] = "60" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for AWS (Amazon Web Services)" + docs["longdesc"] = "fence_aws is an I/O Fencing agent for AWS (Amazon Web\ +Services). It uses the boto3 library to connect to AWS.\ +\n.P\n\ +boto3 can be configured with AWS CLI or by creating ~/.aws/credentials.\n\ +For instructions see: https://boto3.readthedocs.io/en/latest/guide/quickstart.html#configuration" + docs["vendorurl"] = "http://www.amazon.com" + show_docs(options, docs) + + run_delay(options) + + if options.get("--verbose") is not None: + lh = logging.FileHandler('/var/log/fence_aws_debug.log') + logger.addHandler(lh) + lhf = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + lh.setFormatter(lhf) + logger.setLevel(logging.DEBUG) + + if options["--boto3_debug"].lower() not in ["1", "yes", "on", "true"]: + boto3.set_stream_logger('boto3',logging.INFO) + boto3.set_stream_logger('botocore',logging.CRITICAL) + logging.getLogger('botocore').propagate = False + logging.getLogger('boto3').propagate = False + else: + log_format = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s') + logging.getLogger('botocore').propagate = False + logging.getLogger('boto3').propagate = False + fdh = logging.FileHandler('/var/log/fence_aws_boto3.log') + fdh.setFormatter(log_format) + logging.getLogger('boto3').addHandler(fdh) + logging.getLogger('botocore').addHandler(fdh) + logging.debug("Boto debug level is %s and sending debug info to /var/log/fence_aws_boto3.log", options["--boto3_debug"]) + + region = options.get("--region") + access_key = options.get("--access-key") + secret_key = options.get("--secret-key") + try: + conn = boto3.resource('ec2', region_name=region, + aws_access_key_id=access_key, + aws_secret_access_key=secret_key) + except Exception as e: + fail_usage("Failed: Unable to connect to AWS: " + str(e)) + + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/azure_arm/fence_azure_arm.py b/agents/azure_arm/fence_azure_arm.py new file mode 100755 index 0000000..6908169 --- /dev/null +++ b/agents/azure_arm/fence_azure_arm.py @@ -0,0 +1,260 @@ +#!@PYTHON@ -tt + +import sys, re, pexpect +import logging +import atexit +import xml.etree.ElementTree as ET +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, run_command, run_delay +import azure_fence + +def get_nodes_list(clients, options): + result = {} + + if clients: + compute_client = clients[0] + rgName = options["--resourceGroup"] + vms = compute_client.virtual_machines.list(rgName) + try: + for vm in vms: + result[vm.name] = ("", None) + except Exception as e: + fail_usage("Failed: %s" % e) + + return result + +def check_unfence(clients, options): + if clients: + compute_client = clients[0] + network_client = clients[1] + rgName = options["--resourceGroup"] + + try: + vms = compute_client.virtual_machines.list(rgName) + except Exception as e: + fail_usage("Failed: %s" % e) + + for vm in vms: + vmName = vm.name + if azure_fence.get_network_state(compute_client, network_client, rgName, vmName) == "off": + logging.info("Found fenced node " + vmName) + # dont return "off" based on network-fencing status + options.pop("--network-fencing", None) + options["--plug"] = vmName + if get_power_status(clients, options) == "off": + logging.info("Unfencing " + vmName) + options["--network-fencing"] = "" + options["--action"] = "on" + set_power_status(clients, options) + options["--action"] = "monitor" + +def get_power_status(clients, options): + vmstate = { "running": "on", + "deallocated": "off", + "stopped": "off" } + logging.info("getting power status for VM " + options["--plug"]) + + if clients: + compute_client = clients[0] + rgName = options["--resourceGroup"] + vmName = options["--plug"] + + if "--network-fencing" in options: + network_client = clients[1] + netState = azure_fence.get_network_state(compute_client, network_client, rgName, vmName) + logging.info("Found network state of VM: " + netState) + + # return off quickly once network is fenced instead of waiting for vm state to change + if options["--action"] == "off" and netState == "off": + logging.info("Network fenced for " + vmName) + return netState + + powerState = "unknown" + try: + vmStatus = compute_client.virtual_machines.get(rgName, vmName, "instanceView") + except Exception as e: + fail_usage("Failed: %s" % e) + + for status in vmStatus.instance_view.statuses: + if status.code.startswith("PowerState"): + powerState = status.code.split("/")[1] + break + + vmState = vmstate.get(powerState, "unknown") + logging.info("Found power state of VM: %s (%s)" % (vmState, powerState)) + + if "--network-fencing" in options and netState == "off": + return "off" + + if options["--action"] != "on" and vmState != "off": + return "on" + + if vmState == "on": + return "on" + + return "off" + +def set_power_status(clients, options): + logging.info("setting power status for VM " + options["--plug"] + " to " + options["--action"]) + + if clients: + compute_client = clients[0] + rgName = options["--resourceGroup"] + vmName = options["--plug"] + + if "--network-fencing" in options: + network_client = clients[1] + + if (options["--action"]=="off"): + logging.info("Fencing network for " + vmName) + azure_fence.set_network_state(compute_client, network_client, rgName, vmName, "block") + elif (options["--action"]=="on"): + logging.info("Unfencing network for " + vmName) + azure_fence.set_network_state(compute_client, network_client, rgName, vmName, "unblock") + + if (options["--action"]=="off"): + logging.info("Poweroff " + vmName + " in resource group " + rgName) + try: + # try new API version first + compute_client.virtual_machines.begin_power_off(rgName, vmName, skip_shutdown=True) + except AttributeError: + # use older API verson if it fails + logging.debug("Poweroff " + vmName + " did not work via 'virtual_machines.begin_power_off. Trying virtual_machines.power_off'.") + compute_client.virtual_machines.power_off(rgName, vmName, skip_shutdown=True) + elif (options["--action"]=="on"): + logging.info("Starting " + vmName + " in resource group " + rgName) + try: + # try new API version first + compute_client.virtual_machines.begin_start(rgName, vmName) + except AttributeError: + # use older API verson if it fails + logging.debug("Starting " + vmName + " did not work via 'virtual_machines.begin_start. Trying virtual_machines.start'.") + compute_client.virtual_machines.start(rgName, vmName) + + +def define_new_opts(): + all_opt["resourceGroup"] = { + "getopt" : ":", + "longopt" : "resourceGroup", + "help" : "--resourceGroup=[name] Name of the resource group", + "shortdesc" : "Name of resource group. Metadata service is used if the value is not provided.", + "required" : "0", + "order" : 2 + } + all_opt["tenantId"] = { + "getopt" : ":", + "longopt" : "tenantId", + "help" : "--tenantId=[name] Id of the Azure Active Directory tenant", + "shortdesc" : "Id of Azure Active Directory tenant.", + "required" : "0", + "order" : 3 + } + all_opt["subscriptionId"] = { + "getopt" : ":", + "longopt" : "subscriptionId", + "help" : "--subscriptionId=[name] Id of the Azure subscription", + "shortdesc" : "Id of the Azure subscription. Metadata service is used if the value is not provided.", + "required" : "0", + "order" : 4 + } + all_opt["network-fencing"] = { + "getopt" : "", + "longopt" : "network-fencing", + "help" : "--network-fencing Use network fencing. See NOTE-section of\n\ + metadata for required Subnet/Network Security\n\ + Group configuration.", + "shortdesc" : "Use network fencing. See NOTE-section for configuration.", + "required" : "0", + "order" : 5 + } + all_opt["msi"] = { + "getopt" : "", + "longopt" : "msi", + "help" : "--msi Use Managed Service Identity instead of\n\ + username and password. If specified,\n\ + parameters tenantId, login and passwd are not\n\ + allowed.", + "shortdesc" : "Determines if Managed Service Identity should be used.", + "required" : "0", + "order" : 6 + } + all_opt["cloud"] = { + "getopt" : ":", + "longopt" : "cloud", + "help" : "--cloud=[name] Name of the cloud you want to use. Supported\n\ + values are china, germany or usgov. Do not use\n\ + this parameter if you want to use public\n\ + Azure.", + "shortdesc" : "Name of the cloud you want to use.", + "required" : "0", + "order" : 7 + } + +# Main agent method +def main(): + compute_client = None + network_client = None + + device_opt = ["login", "no_login", "no_password", "passwd", "port", "resourceGroup", "tenantId", "subscriptionId", "network-fencing", "msi", "cloud"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["power_timeout"]["default"] = "150" + + all_opt["login"]["help"] = "-l, --username=[appid] Application ID" + all_opt["passwd"]["help"] = "-p, --password=[authkey] Authentication key" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Azure Resource Manager" + docs["longdesc"] = "fence_azure_arm is an I/O Fencing agent for Azure Resource Manager. It uses Azure SDK for Python to connect to Azure.\ +\n.P\n\ +For instructions to setup credentials see: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal\ +\n.P\n\ +Username and password are application ID and authentication key from \"App registrations\".\ +\n.P\n\ +NOTE: NETWORK FENCING\n.br\n\ +Network fencing requires an additional Subnet named \"fence-subnet\" for the Virtual Network using a Network Security Group with the following rules:\n.br\n\ ++-----------+-----+-------------------------+------+------+-----+-----+--------+\n.br\n\ +| DIRECTION | PRI | NAME | PORT | PROT | SRC | DST | ACTION |\n.br\n\ ++-----------+-----+-------------------------+------+------+-----+-----+--------+\n.br\n\ +| Inbound | 100 | FENCE_DENY_ALL_INBOUND | Any | Any | Any | Any | Deny |\n.br\n\ +| Outbound | 100 | FENCE_DENY_ALL_OUTBOUND | Any | Any | Any | Any | Deny |\n.br\n\ ++-----------+-----+-------------------------+------+------+-----+-----+--------+\ +\n.P\n\ +When using network fencing the reboot-action will cause a quick-return once the network has been fenced (instead of waiting for the off-action to succeed). It will check the status during the monitor-action, and request power-on when the shutdown operation is complete." + docs["vendorurl"] = "http://www.microsoft.com" + show_docs(options, docs) + + run_delay(options) + + try: + config = azure_fence.get_azure_config(options) + options["--resourceGroup"] = config.RGName + compute_client = azure_fence.get_azure_compute_client(config) + if "--network-fencing" in options: + network_client = azure_fence.get_azure_network_client(config) + except ImportError: + fail_usage("Azure Resource Manager Python SDK not found or not accessible") + except Exception as e: + fail_usage("Failed: %s" % re.sub("^, ", "", str(e))) + + if "--network-fencing" in options: + # use off-action to quickly return off once network is fenced instead of + # waiting for vm state to change + if options["--action"] == "reboot": + options["--action"] = "off" + # check for devices to unfence in monitor-action + elif options["--action"] == "monitor": + check_unfence([compute_client, network_client], options) + + # Operate the fencing device + result = fence_action([compute_client, network_client], options, set_power_status, get_power_status, get_nodes_list) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/bladecenter/fence_bladecenter.py b/agents/bladecenter/fence_bladecenter.py new file mode 100644 index 0000000..d670367 --- /dev/null +++ b/agents/bladecenter/fence_bladecenter.py @@ -0,0 +1,105 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## Model Firmware +## +--------------------+---------------------------+ +## (1) Main application BRET85K, rev 16 +## Boot ROM BRBR67D, rev 16 +## Remote Control BRRG67D, rev 16 +## +##### + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS, EC_GENERIC_ERROR + +def get_power_status(conn, options): + node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" + + conn.send_eol("env -T system:blade[" + options["--plug"] + "]") + i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) + if i == 1: + ## Given blade number does not exist + if "--missing-as-off" in options: + return "off" + else: + fail(EC_STATUS) + conn.send_eol("power -state") + conn.log_expect(node_cmd, int(options["--shell-timeout"])) + status = conn.before.splitlines()[-1] + conn.send_eol("env -T system") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + return status.lower().strip() + +def set_power_status(conn, options): + node_cmd = r"system:blade\[" + options["--plug"] + r"\]>" + + conn.send_eol("env -T system:blade[" + options["--plug"] + "]") + i = conn.log_expect([node_cmd, "system>"], int(options["--shell-timeout"])) + if i == 1: + ## Given blade number does not exist + if "--missing-as-off" in options: + return + else: + fail(EC_GENERIC_ERROR) + + conn.send_eol("power -"+options["--action"]) + conn.log_expect(node_cmd, int(options["--shell-timeout"])) + conn.send_eol("env -T system") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def get_blades_list(conn, options): + outlets = {} + + node_cmd = "system>" + + conn.send_eol("env -T system") + conn.log_expect(node_cmd, int(options["--shell-timeout"])) + conn.send_eol("list -l 2") + conn.log_expect(node_cmd, int(options["--shell-timeout"])) + + lines = conn.before.split("\r\n") + filter_re = re.compile(r"^\s*blade\[(\d+)\]\s+(.*?)\s*$") + for blade_line in lines: + res = filter_re.search(blade_line) + if res != None: + outlets[res.group(1)] = (res.group(2), "") + + return outlets + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "port", "missing_as_off", "telnet"] + + atexit.register(atexit_handler) + + all_opt["power_wait"]["default"] = "10" + all_opt["cmd_prompt"]["default"] = ["system>"] + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for IBM BladeCenter" + docs["longdesc"] = "fence_bladecenter is an I/O Fencing agent \ +which can be used with IBM Bladecenters with recent enough firmware that \ +includes telnet support. It logs into a Brocade chasis via telnet or ssh \ +and uses the command line interface to power on and off blades." + docs["vendorurl"] = "http://www.ibm.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + ###### + conn = fence_login(options, "(username\s*:\s*)") + result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/brocade/fence_brocade.py b/agents/brocade/fence_brocade.py new file mode 100644 index 0000000..9f413db --- /dev/null +++ b/agents/brocade/fence_brocade.py @@ -0,0 +1,72 @@ +#!@PYTHON@ -tt + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS + +def set_power_status(conn, options): + action = { + 'on' : "portCfgPersistentEnable", + 'off': "portCfgPersistentDisable" + }[options["--action"]] + + conn.send_eol(action + " " + options["--plug"]) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +def get_power_status(conn, options): + line_re = re.compile(r'=========', re.IGNORECASE) + outlets = {} + in_index = False + + conn.send_eol("switchshow") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + for line in str(conn.before).split("\n"): + if line_re.search(line): + in_index = True + elif in_index and line.lstrip()[0].isdigit(): + tokens = line.lstrip().split() + status = "off" if len(tokens) > 7 and tokens[7] == "Disabled" else "on" + outlets[tokens[0]] = ("", status) + + if ["list", "monitor"].count(options["--action"]) == 0: + (_, status) = outlets[options["--plug"]] + return status + else: + return outlets + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "port", "fabric_fencing", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["> "] + + options = check_input(device_opt, process_input(device_opt)) + options["eol"] = "\n" + + docs = {} + docs["shortdesc"] = "Fence agent for HP Brocade over telnet/ssh" + docs["longdesc"] = "fence_brocade is an I/O Fencing agent which can be used with Brocade FC switches. \ +It logs into a Brocade switch via telnet and disables a specified port. Disabling the port which a machine is \ +connected to effectively fences that machine. Lengthy telnet connections to the switch should be avoided while \ +a GFS cluster is running because the connection will block any necessary fencing actions. \ +\ +After a fence operation has taken place the fenced machine can no longer connect to the Brocade FC switch. \ +When the fenced machine is ready to be brought back into the GFS cluster (after reboot) the port on the Brocade \ +FC switch needs to be enabled. This can be done by running fence_brocade and specifying the enable action" + docs["vendorurl"] = "http://www.brocade.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/cdu/fence_cdu.py b/agents/cdu/fence_cdu.py new file mode 100644 index 0000000..483ac51 --- /dev/null +++ b/agents/cdu/fence_cdu.py @@ -0,0 +1,176 @@ +#!@PYTHON@ -tt +# fence_cdu - fence agent for a Sentry Switch CDU. +# +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2021 SUSE Linux GmbH <trenn@suse.de> +# +# Authors: Andres Rodriguez <andres.rodriguez@canonical.com> +# Thomas Renninger <trenn@suse.de> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +##### +## +## The Following Agent Has Been Tested On: +## +## Model Firmware +## +---------------------------------------------+ +## Sentry Switched CDU 6a +## Sentry Switched CDU 7.1c <trenn@suse.de> +## Sentry Switched CDU 7.1f <trenn@suse.de> +## Sentry Switched PDU 8.0i <trenn@suse.de> +## +## +##### + +import sys, re, pexpect, atexit, logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_TIMED_OUT, run_command, frun, EC_STATUS + +def get_power_status(conn, options): + exp_result = 0 + outlets = {} + try: + if options["api-version"] == "8": + conn.send("STATUS ALL\r\n") + else: + conn.send("STATUS\r\n") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + lines = conn.before.split("\n") + if options["api-version"] == "8": + # AA13 Arm-Console3 Wake On On Normal + # AA14 Master_Outlet_14 Wake On On Normal + show_re = re.compile('(\w+)\s+(\S+)\s+(On|Idle On|Off|Wake On)\s+(On|Off)') + else: + # .A12 TowerA_Outlet12 On Idle On + # .A12 test-01 On Idle On + show_re = re.compile('(\.\w+)\s+(\w+|\w+\W\w+)\s+(On|Off)\s+(On|Idle On|Off|Wake On)') + for line in lines: + res = show_re.search(line) + if res != None: + plug_id = res.group(1) + plug_name = res.group(2) + print(plug_name) + plug_state = res.group(3) + if options["api-version"] == "8": + plug_state = res.group(4) + outlets[plug_name] = (plug_id, plug_state) + except pexpect.EOF: + fail(EC_CONNECTION_LOST) + except pexpect.TIMEOUT: + fail(EC_TIMED_OUT) + try: + (_, status) = outlets[options["--plug"]] + return status.lower().strip() + except KeyError: + fail(EC_STATUS) + +def set_power_status(conn, options): + outlets = {} + action = { 'on' : "on", 'off': "off" }[options["--action"]] + try: + conn.send("LIST OUTLETS\r\n") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + lines = conn.before.split("\n") + # if options["api-version"] == "8": + # AA13 Arm-Console3 + # AA14 Master_Outlet_14 + # else: + # .A12 TowerA_Outlet12 + # .A12 test-01 + show_re = re.compile('(\S+)\s+(\w+|\w+\W\w+)\s+') + for line in lines: + res = show_re.search(line) + if res != None: + outlets[res.group(2)] = (res.group(1)) + conn.send(action + " " + outlets[options["--plug"]] + "\r\n") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + except pexpect.EOF: + fail(EC_CONNECTION_LOST) + except pexpect.TIMEOUT: + fail(EC_TIMED_OUT) + +def disconnect(conn): + conn.sendline("LOGOUT") + conn.close() + +def get_version(conn, options): + api_ver = "6" + sub = "a" + minor = "" + conn.send("VERSION\r\n") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + lines = conn.before.split("\n") + show_re = re.compile('Sentry Switched [PC]DU Version (\d)(.\d|)(\w)\r') + for line in lines: + res = show_re.search(line) + if res != None: + api_ver = res.group(1) + if res.group(2): + sub = res.group(2).lstrip(".") + minor = res.group(3) + return (api_ver, sub, minor) + +def main(): + device_opt = [ "ipaddr", "login", "port", "switch", "passwd", "telnet" ] + + atexit.register(atexit_handler) + + options = check_input(device_opt, process_input(device_opt)) + + ## + ## Fence agent specific defaults + ##### + options["--command-prompt"] = "Switched [PC]DU: " + + docs = { } + docs["shortdesc"] = "Fence agent for a Sentry Switch CDU over telnet" + docs["longdesc"] = "fence_cdu is an I/O Fencing agent \ +which can be used with the Sentry Switch CDU. It logs into the device \ +via telnet and power's on/off an outlet." + docs["vendorurl"] = "http://www.servertech.com" + show_docs(options, docs) + + ## Support for --plug [switch]:[plug] notation that was used before + opt_n = options.get("--plug") + if opt_n and (-1 != opt_n.find(":")): + (switch, plug) = opt_n.split(":", 1) + options["--switch"] = switch; + options["--plug"] = plug; + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + (api_ver, sub, minor) = get_version(conn, options) + options["api-version"] = api_ver + logging.debug("Using API version: %s" % api_ver) + if api_ver == "7": + # disable output paging + conn.sendline("set option more disabled") + conn.log_expect(options["--command-prompt"], int(options["--login-timeout"])) + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + ## + ## Logout from system + ## + ## In some special unspecified cases it is possible that + ## connection will be closed before we run close(). This is not + ## a problem because everything is checked before. + ###### + atexit.register(disconnect, conn) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/cisco_mds/fence_cisco_mds.py b/agents/cisco_mds/fence_cisco_mds.py new file mode 100644 index 0000000..fbb876a --- /dev/null +++ b/agents/cisco_mds/fence_cisco_mds.py @@ -0,0 +1,94 @@ +#!@PYTHON@ -tt + +# The Following agent has been tested on: +# - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2 +# with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) +# - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500 +# with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, array_to_dict +from fencing_snmp import FencingSnmp + +### CONSTANTS ### +# Cisco admin status +PORT_ADMIN_STATUS_OID = ".1.3.6.1.2.1.75.1.2.2.1.1" + +# IF-MIB trees for alias, status and port +ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18" +PORTS_OID = ".1.3.6.1.2.1.2.2.1.2" + +### GLOBAL VARIABLES ### +# OID converted from fc port name (fc(x)/(y)) +PORT_OID = "" + +### FUNCTIONS ### + +# Convert cisco port name (fc(x)/(y)) to OID +def cisco_port2oid(port): + port = port.lower() + + nums = re.match(r'^fc(\d+)/(\d+)$', port) + + if nums and len(nums.groups()) == 2: + return "%s.%d.%d"% (PORT_ADMIN_STATUS_OID, int(nums.group(1))+21, int(nums.group(2))-1) + else: + fail_usage("Mangled port number: %s"%(port)) + +def get_power_status(conn, options): + (_, status) = conn.get(PORT_OID) + return status == "1" and "on" or "off" + +def set_power_status(conn, options): + conn.set(PORT_OID, (options["--action"] == "on" and 1 or 2)) + +def get_outlets_status(conn, options): + result = {} + + res_fc = conn.walk(PORTS_OID, 30) + res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30)) + + fc_re = re.compile(r'^"fc\d+/\d+"$') + + for x in res_fc: + if fc_re.match(x[1]): + port_num = x[0].split('.')[-1] + + port_name = x[1].strip('"') + port_alias = (port_num in res_aliases and res_aliases[port_num].strip('"') or "") + port_status = "" + result[port_name] = (port_alias, port_status) + + return result + +# Main agent method +def main(): + global PORT_OID + + device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \ + "port", "snmp_version", "snmp"] + + atexit.register(atexit_handler) + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Cisco MDS" + docs["longdesc"] = "fence_cisco_mds is an I/O Fencing agent \ +which can be used with any Cisco MDS 9000 series with SNMP enabled device." + docs["vendorurl"] = "http://www.cisco.com" + show_docs(options, docs) + + if not options["--action"] in ["list", "monitor"]: + PORT_OID = cisco_port2oid(options["--plug"]) + + # Operate the fencing device + result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/cisco_ucs/fence_cisco_ucs.py b/agents/cisco_ucs/fence_cisco_ucs.py new file mode 100644 index 0000000..b85379a --- /dev/null +++ b/agents/cisco_ucs/fence_cisco_ucs.py @@ -0,0 +1,198 @@ +#!@PYTHON@ -tt + +import sys, re +import pycurl, io +import logging +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS, EC_LOGIN_DENIED, run_delay + +RE_COOKIE = re.compile("<aaaLogin .* outCookie=\"(.*?)\"", re.IGNORECASE) +RE_STATUS = re.compile("<lsPower .*? state=\"(.*?)\"", re.IGNORECASE) +RE_GET_DN = re.compile(" dn=\"(.*?)\"", re.IGNORECASE) +RE_GET_PNDN = re.compile(" pndn=\"(.*?)\"", re.IGNORECASE) +RE_GET_DESC = re.compile(" descr=\"(.*?)\"", re.IGNORECASE) +RE_GET_OPERPOWER = re.compile(" operPower=\"(.*?)\"", re.IGNORECASE) +RE_GET_PRESENCE = re.compile(" presence=\"(.*?)\"", re.IGNORECASE) + +options_global = None + +def get_power_status(conn, options): + del conn + + res = send_command(options, "<configResolveDn cookie=\"" + options["cookie"] + + "\" inHierarchical=\"false\" dn=\"org-root" + options["--suborg"] + "/ls-" + + options["--plug"] + "\"/>", int(options["--shell-timeout"])) + + result = RE_GET_PNDN.search(res) + if result == None: + pndn = "" + else: + pndn = result.group(1) + + if pndn.strip() == "": + if "--missing-as-off" in options: + return "off" + else: + fail(EC_STATUS) + + res = send_command(options, "<configResolveDn cookie=\"" + options["cookie"] + + "\" inHierarchical=\"false\" dn=\"" + pndn + + "\"/>", int(options["--shell-timeout"])) + + result = RE_GET_PRESENCE.search(res) + if result == None: + fail(EC_STATUS) + else: + presence_status = result.group(1) + + if presence_status in ["missing", "mismatch"]: + return "off" + else: + result = RE_GET_OPERPOWER.search(res) + if result == None: + fail(EC_STATUS) + else: + power_status = result.group(1) + + if power_status == "on": + return "on" + else: + return "off" + +def set_power_status(conn, options): + del conn + + action = { + 'on' : "admin-up", + 'off' : "admin-down" + }[options["--action"]] + + send_command(options, "<configConfMos cookie=\"" + options["cookie"] + "\" inHierarchical=\"no\">" + + "<inConfigs><pair key=\"org-root" + options["--suborg"] + "/ls-" + options["--plug"] + + "/power\">" + "<lsPower dn=\"org-root/ls-" + options["--plug"] + "/power\" state=\"" + + action + "\" status=\"modified\" />" + "</pair></inConfigs></configConfMos>", + int(options["--shell-timeout"])) + + return + +def get_list(conn, options): + del conn + outlets = {} + + try: + res = send_command(options, "<configResolveClass cookie=\"" + options["cookie"] + + "\" inHierarchical=\"false\" classId=\"lsServer\"/>", int(options["--shell-timeout"])) + + lines = res.split("<lsServer ") + for i in range(1, len(lines)): + node_name = RE_GET_DN.search(lines[i]).group(1) + desc = RE_GET_DESC.search(lines[i]).group(1) + outlets[node_name] = (desc, None) + except AttributeError: + return {} + except IndexError: + return {} + + return outlets + +def send_command(opt, command, timeout): + ## setup correct URL + if "--ssl-secure" in opt or "--ssl-insecure" in opt: + url = "https:" + else: + url = "http:" + + url += "//" + opt["--ip"] + ":" + str(opt["--ipport"]) + "/nuova" + + ## send command through pycurl + conn = pycurl.Curl() + web_buffer = io.BytesIO() + conn.setopt(pycurl.URL, url.encode("ascii")) + conn.setopt(pycurl.HTTPHEADER, ["Content-type: text/xml"]) + conn.setopt(pycurl.POSTFIELDS, command.encode("ascii")) + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + conn.setopt(pycurl.TIMEOUT, timeout) + + if "--ssl-secure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + elif "--ssl-insecure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + + conn.perform() + result = web_buffer.getvalue().decode() + + logging.debug("%s\n", command) + logging.debug("%s\n", result) + + return result + +def define_new_opts(): + all_opt["suborg"] = { + "getopt" : ":", + "longopt" : "suborg", + "help" : "--suborg=[path] Additional path needed to access suborganization", + "required" : "0", + "shortdesc" : "Additional path needed to access suborganization", + "default" : "", + "order" : 1} + +def logout(): + ### Logout; we do not care about result as we will end in any case + try: + send_command(options_global, "<aaaLogout inCookie=\"" + options_global["cookie"] + "\" />", + int(options_global["--shell-timeout"])) + except Exception: + pass + +def main(): + global options_global + device_opt = ["ipaddr", "login", "passwd", "ssl", "notls", "port", "web", "suborg", "missing_as_off"] + + atexit.register(atexit_handler) + atexit.register(logout) + + define_new_opts() + + options_global = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Cisco UCS" + docs["longdesc"] = "fence_cisco_ucs is an I/O Fencing agent which can be \ +used with Cisco UCS to fence machines." + docs["vendorurl"] = "http://www.cisco.com" + show_docs(options_global, docs) + + run_delay(options_global) + ### Login + try: + res = send_command(options_global, "<aaaLogin inName=\"" + options_global["--username"] + + "\" inPassword=\"" + options_global["--password"] + "\" />", int(options_global["--login-timeout"])) + result = RE_COOKIE.search(res) + if result == None: + ## Cookie is absenting in response + fail(EC_LOGIN_DENIED) + except Exception as e: + logging.error("Failed: {}".format(str(e))) + fail(EC_LOGIN_DENIED) + + options_global["cookie"] = result.group(1) + + ## + ## Modify suborg to format /suborg + if options_global["--suborg"] != "": + options_global["--suborg"] = "/" + options_global["--suborg"].lstrip("/").rstrip("/") + + ## + ## Fence operations + #### + result = fence_action(None, options_global, set_power_status, get_power_status, get_list) + + ## Logout is done every time at atexit phase + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py new file mode 100644 index 0000000..f53b97d --- /dev/null +++ b/agents/compute/fence_compute.py @@ -0,0 +1,516 @@ +#!@PYTHON@ -tt + +import sys +import time +import atexit +import logging +import inspect +import requests.exceptions + +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, is_executable, run_command, run_delay + +override_status = "" + +EVACUABLE_TAG = "evacuable" +TRUE_TAGS = ['true'] + +def get_power_status(connection, options): + + if len(override_status): + logging.debug("Pretending we're " + override_status) + return override_status + + status = "unknown" + logging.debug("get action: " + options["--action"]) + + if connection: + try: + services = connection.services.list(host=options["--plug"], binary="nova-compute") + for service in services: + logging.debug("Status of %s on %s is %s, %s" % (service.binary, options["--plug"], service.state, service.status)) + if service.state == "up" and service.status == "enabled": + # Up and operational + status = "on" + + elif service.state == "down" and service.status == "disabled": + # Down and fenced + status = "off" + + elif service.state == "down": + # Down and requires fencing + status = "failed" + + elif service.state == "up": + # Up and requires unfencing + status = "running" + else: + logging.warning("Unknown status detected from nova for %s: %s, %s" % (options["--plug"], service.state, service.status)) + status = "%s %s" % (service.state, service.status) + break + except requests.exception.ConnectionError as err: + logging.warning("Nova connection failed: " + str(err)) + logging.debug("Final status of %s is %s" % (options["--plug"], status)) + return status + +def get_power_status_simple(connection, options): + status = get_power_status(connection, options) + if status in [ "off" ]: + return status + return "on" + +def set_attrd_status(host, status, options): + logging.debug("Setting fencing status for %s to %s" % (host, status)) + run_command(options, "attrd_updater -p -n evacuate -Q -N %s -U %s" % (host, status)) + +def get_attrd_status(host, options): + (status, pipe_stdout, pipe_stderr) = run_command(options, "attrd_updater -p -n evacuate -Q -N %s" % (host)) + fields = pipe_stdout.split('"') + if len(fields) > 6: + return fields[5] + logging.debug("Got %s: o:%s e:%s n:%d" % (status, pipe_stdout, pipe_stderr, len(fields))) + return "" + +def set_power_status_on(connection, options): + # Wait for any evacuations to complete + while True: + current = get_attrd_status(options["--plug"], options) + if current in ["no", ""]: + logging.info("Evacuation complete for: %s '%s'" % (options["--plug"], current)) + break + else: + logging.info("Waiting for %s to complete evacuations: %s" % (options["--plug"], current)) + time.sleep(2) + + status = get_power_status(connection, options) + # Should we do it for 'failed' too? + if status in [ "off", "running", "failed" ]: + try: + # Forcing the host back up + logging.info("Forcing nova-compute back up on "+options["--plug"]) + connection.services.force_down(options["--plug"], "nova-compute", force_down=False) + logging.info("Forced nova-compute back up on "+options["--plug"]) + except Exception as e: + # In theory, if force_down=False fails, that's for the exact + # same possible reasons that below with force_down=True + # eg. either an incompatible version or an old client. + # Since it's about forcing back to a default value, there is + # no real worries to just consider it's still okay even if the + # command failed + logging.warn("Exception from attempt to force " + "host back up via nova API: " + "%s: %s" % (e.__class__.__name__, e)) + + # Forcing the service back up in case it was disabled + logging.info("Enabling nova-compute on "+options["--plug"]) + connection.services.enable(options["--plug"], 'nova-compute') + + # Pretend we're 'on' so that the fencing library doesn't loop forever waiting for the node to boot + override_status = "on" + elif status not in ["on"]: + # Not safe to unfence, don't waste time looping to see if the status changes to "on" + options["--power-timeout"] = "0" + +def set_power_status_off(connection, options): + status = get_power_status(connection, options) + if status in [ "off" ]: + return + + try: + # Until 2.53 + connection.services.force_down( + options["--plug"], "nova-compute", force_down=True) + connection.services.disable(options["--plug"], 'nova-compute') + except Exception as e: + # Something went wrong when we tried to force the host down. + # That could come from either an incompatible API version + # eg. UnsupportedVersion or VersionNotFoundForAPIMethod + # or because novaclient is old and doesn't include force_down yet + # eg. AttributeError + # In that case, fallbacking to wait for Nova to catch the right state. + + logging.error("Exception from attempt to force host down via nova API: " + "%s: %s" % (e.__class__.__name__, e)) + # need to wait for nova to update its internal status or we + # cannot call host-evacuate + while get_power_status(connection, options) not in ["off"]: + # Loop forever if need be. + # + # Some callers (such as Pacemaker) will have a timer + # running and kill us if necessary + logging.debug("Waiting for nova to update its internal state for %s" % options["--plug"]) + time.sleep(1) + + set_attrd_status(options["--plug"], "yes", options) + +def set_power_status(connection, options): + global override_status + + override_status = "" + logging.debug("set action: " + options["--action"]) + + if not connection: + return + + if options["--action"] in ["off", "reboot"]: + set_power_status_off(connection, options) + else: + set_power_status_on(connection, options) + logging.debug("set action passed: " + options["--action"]) + sys.exit(0) + +def fix_domain(connection, options): + domains = {} + last_domain = None + + if connection: + # Find it in nova + + services = connection.services.list(binary="nova-compute") + for service in services: + shorthost = service.host.split('.')[0] + + if shorthost == service.host: + # Nova is not using FQDN + calculated = "" + else: + # Compute nodes are named as FQDN, strip off the hostname + calculated = service.host.replace(shorthost+".", "") + + if calculated == last_domain: + # Avoid complaining for each compute node with the same name + # One hopes they don't appear interleaved as A.com B.com A.com B.com + logging.debug("Calculated the same domain from: %s" % service.host) + continue + + domains[calculated] = service.host + last_domain = calculated + + if "--domain" in options and options["--domain"] != calculated: + # Warn in case nova isn't available at some point + logging.warning("Supplied domain '%s' does not match the one calculated from: %s" + % (options["--domain"], service.host)) + + if len(domains) == 0 and "--domain" not in options: + logging.error("Could not calculate the domain names used by compute nodes in nova") + + elif len(domains) == 1 and "--domain" not in options: + options["--domain"] = last_domain + + elif len(domains) == 1 and options["--domain"] != last_domain: + logging.error("Overriding supplied domain '%s' as it does not match the one calculated from: %s" + % (options["--domain"], domains[last_domain])) + options["--domain"] = last_domain + + elif len(domains) > 1: + logging.error("The supplied domain '%s' did not match any used inside nova: %s" + % (options["--domain"], repr(domains))) + sys.exit(1) + + return last_domain + +def fix_plug_name(connection, options): + if options["--action"] == "list": + return + + if "--plug" not in options: + return + + calculated = fix_domain(connection, options) + if calculated is None or "--domain" not in options: + # Nothing supplied and nova not available... what to do... nothing + return + + short_plug = options["--plug"].split('.')[0] + logging.debug("Checking target '%s' against calculated domain '%s'"% (options["--plug"], calculated)) + + if options["--domain"] == "": + # Ensure any domain is stripped off since nova isn't using FQDN + options["--plug"] = short_plug + + elif options["--plug"].endswith(options["--domain"]): + # Plug already uses the domain, don't re-add + return + + else: + # Add the domain to the plug + options["--plug"] = short_plug + "." + options["--domain"] + +def get_plugs_list(connection, options): + result = {} + + if connection: + services = connection.services.list(binary="nova-compute") + for service in services: + longhost = service.host + shorthost = longhost.split('.')[0] + result[longhost] = ("", None) + result[shorthost] = ("", None) + return result + +def create_nova_connection(options): + nova = None + + try: + from novaclient import client + from novaclient.exceptions import NotAcceptable + except ImportError: + fail_usage("Nova not found or not accessible") + + from keystoneauth1 import loading + from keystoneauth1 import session + from keystoneclient import discover + + # Prefer the oldest and strip the leading 'v' + keystone_versions = discover.available_versions(options["--auth-url"]) + keystone_version = keystone_versions[0]['id'][1:] + kwargs = dict( + auth_url=options["--auth-url"], + username=options["--username"], + password=options["--password"] + ) + + if discover.version_match("2", keystone_version): + kwargs["tenant_name"] = options["--tenant-name"] + + elif discover.version_match("3", keystone_version): + kwargs["project_name"] = options["--tenant-name"] + kwargs["user_domain_name"] = options["--user-domain"] + kwargs["project_domain_name"] = options["--project-domain"] + + loader = loading.get_plugin_loader('password') + keystone_auth = loader.load_from_options(**kwargs) + keystone_session = session.Session(auth=keystone_auth, verify=not "--insecure" in options) + + nova_versions = [ "2.11", "2" ] + for version in nova_versions: + clientargs = inspect.getargspec(client.Client).varargs + # Some versions of Openstack prior to Ocata only + # supported positional arguments for username, + # password, and tenant. + # + # Versions since Ocata only support named arguments. + # + # So we need to use introspection to figure out how to + # create a Nova client. + # + # Happy days + # + if clientargs: + # OSP < 11 + # ArgSpec(args=['version', 'username', 'password', 'project_id', 'auth_url'], + # varargs=None, + # keywords='kwargs', defaults=(None, None, None, None)) + nova = client.Client(version, + None, # User + None, # Password + None, # Tenant + None, # Auth URL + insecure="--insecure" in options, + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, + http_log_debug="--verbose" in options) + else: + # OSP >= 11 + # ArgSpec(args=['version'], varargs='args', keywords='kwargs', defaults=None) + nova = client.Client(version, + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, + http_log_debug="--verbose" in options) + + try: + nova.hypervisors.list() + return nova + + except NotAcceptable as e: + logging.warning(e) + + except Exception as e: + logging.warning("Nova connection failed. %s: %s" % (e.__class__.__name__, e)) + + logging.warning("Couldn't obtain a supported connection to nova, tried: %s\n" % repr(nova_versions)) + return None + +def define_new_opts(): + all_opt["endpoint_type"] = { + "getopt" : "e:", + "longopt" : "endpoint-type", + "help" : "-e, --endpoint-type=[endpoint] Nova Endpoint type (publicURL, internalURL, adminURL)", + "required" : "0", + "shortdesc" : "Nova Endpoint type", + "default" : "internalURL", + "order": 1, + } + all_opt["tenant_name"] = { + "getopt" : "t:", + "longopt" : "tenant-name", + "help" : "-t, --tenant-name=[name] Keystone v2 Tenant or v3 Project Name", + "required" : "0", + "shortdesc" : "Keystone Admin Tenant or v3 Project", + "default" : "", + "order": 1, + } + all_opt["user-domain"] = { + "getopt" : "u:", + "longopt" : "user-domain", + "help" : "-u, --user-domain=[name] Keystone v3 User Domain", + "required" : "0", + "shortdesc" : "Keystone v3 User Domain", + "default" : "Default", + "order": 2, + } + all_opt["project-domain"] = { + "getopt" : "P:", + "longopt" : "project-domain", + "help" : "-P, --project-domain=[name] Keystone v3 Project Domain", + "required" : "0", + "shortdesc" : "Keystone v3 Project Domain", + "default" : "Default", + "order": 2, + } + all_opt["auth_url"] = { + "getopt" : "k:", + "longopt" : "auth-url", + "help" : "-k, --auth-url=[url] Keystone Admin Auth URL", + "required" : "0", + "shortdesc" : "Keystone Admin Auth URL", + "default" : "", + "order": 1, + } + all_opt["region_name"] = { + "getopt" : ":", + "longopt" : "region-name", + "help" : "--region-name=[region] Region Name", + "required" : "0", + "shortdesc" : "Region Name", + "default" : "", + "order": 1, + } + all_opt["insecure"] = { + "getopt" : "", + "longopt" : "insecure", + "help" : "--insecure Explicitly allow agent to perform \"insecure\" TLS (https) requests", + "required" : "0", + "shortdesc" : "Allow Insecure TLS Requests", + "order": 2, + } + all_opt["domain"] = { + "getopt" : "d:", + "longopt" : "domain", + "help" : "-d, --domain=[string] DNS domain in which hosts live, useful when the cluster uses short names and nova uses FQDN", + "required" : "0", + "shortdesc" : "DNS domain in which hosts live", + "order": 5, + } + all_opt["record_only"] = { + "getopt" : "r:", + "longopt" : "record-only", + "help" : "--record-only Record the target as needing evacuation but as yet do not intiate it", + "required" : "0", + "shortdesc" : "Only record the target as needing evacuation", + "default" : "False", + "order": 5, + } + all_opt["instance_filtering"] = { + "getopt" : "", + "longopt" : "instance-filtering", + "help" : "--instance-filtering Allow instances created from images and flavors with evacuable=true to be evacuated (or all if no images/flavors have been tagged)", + "required" : "0", + "shortdesc" : "Allow instances to be evacuated", + "default" : "True", + "order": 5, + } + all_opt["no_shared_storage"] = { + "getopt" : "", + "longopt" : "no-shared-storage", + "help" : "--no-shared-storage Disable functionality for shared storage", + "required" : "0", + "shortdesc" : "Disable functionality for dealing with shared storage", + "default" : "False", + "order": 5, + } + all_opt["compute-domain"] = { + "getopt" : ":", + "longopt" : "compute-domain", + "help" : "--compute-domain=[string] Replaced by --domain", + "required" : "0", + "shortdesc" : "Replaced by domain", + "order": 6, + } + +def set_multi_power_fn(connection, options, set_power_fn, get_power_fn, retry_attempts=1): + for _ in range(retry_attempts): + set_power_fn(connection, options) + time.sleep(int(options["--power-wait"])) + + for _ in range(int(options["--power-timeout"])): + if get_power_fn(connection, options) != options["--action"]: + time.sleep(1) + else: + return True + return False + +def main(): + global override_status + atexit.register(atexit_handler) + + device_opt = ["login", "passwd", "tenant_name", "auth_url", "fabric_fencing", "no_login", + "no_password", "port", "domain", "compute-domain", "project-domain", + "user-domain", "no_shared_storage", "endpoint_type", "record_only", + "instance_filtering", "insecure", "region_name"] + define_new_opts() + all_opt["shell_timeout"]["default"] = "180" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for the automatic resurrection of OpenStack compute instances" + docs["longdesc"] = "Used to tell Nova that compute nodes are down and to reschedule flagged instances" + docs["vendorurl"] = "" + + show_docs(options, docs) + + if options["--record-only"] in [ "2", "Disabled", "disabled" ]: + sys.exit(0) + + run_delay(options) + + # workaround to avoid regressions + if "--compute-domain" in options and options["--compute-domain"]: + options["--domain"] = options["--compute-domain"] + del options["--domain"] + + # Disable insecure-certificate-warning message + if "--insecure" in options: + import urllib3 + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + logging.debug("Running "+options["--action"]) + connection = create_nova_connection(options) + + if options["--action"] in ["off", "on", "reboot", "status"]: + fix_plug_name(connection, options) + + + if options["--action"] in ["reboot"]: + options["--action"]="off" + + if options["--action"] in ["off", "on"]: + # No status first, call our own version + result = not set_multi_power_fn(connection, options, set_power_status, get_power_status_simple, + 1 + int(options["--retry-on"])) + elif options["--action"] in ["monitor"]: + result = 0 + else: + result = fence_action(connection, options, set_power_status, get_power_status_simple, get_plugs_list, None) + + logging.debug("Result for "+options["--action"]+": "+repr(result)) + if result == None: + result = 0 + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/crosslink/README.md b/agents/crosslink/README.md new file mode 100644 index 0000000..990b790 --- /dev/null +++ b/agents/crosslink/README.md @@ -0,0 +1,44 @@ +# Two node cross-link fence agent + +The problem that this fence agents tries to solve is the following: + +Given a two-node cluster with a direct crosslink ethernet cable +between the two nodes (in addition to the normal networking setup), we want to +be able to maintain quorum on node (A) when node (B) lost power. +The loss of power on node (B) in this case implies its BMC/IPMI is also +not available which would be normally used in fencing in this case. + +Note: An external PDU would be preferrable and would solve this +situation more elegantly. The assumption here is that something +like that won't be available in this environment. + +This works by creating a stonith level composed of a BMC/IPMI +fencing at level 1 and then the fence_crosslink agent at level 2. + +In case node (A) has lost power, then node (B) will do the following: +1. Try to fence node (B) via IPMI, which will fail since the node has no +power and the BMC is unavailable +2. Check via fence_crosslink the cross-cable interconnect. If the cross cable +IP is not reachable, then we know for "sure" (this is a potentially broad +assumption) that the node is really down and fence_crosslink tells pacemaker +that the fencing was successful, so pacemaker can work with that new +information. + +Here are some example configuration commands: +~~~ +pcs stonith create crosslink-controller-1 fence_crosslink crosscableip=1.1.1.2 pcmk_host_list=controller-1 pcmk_reboot_action=off +pcs stonith create crosslink-controller-0 fence_crosslink crosscableip=1.1.1.1 pcmk_host_list=controller-0 pcmk_reboot_action=off +# We make sure the stonith resource do not run on the same node as the fencing target +pcs constraint location crosslink-controller-1 avoids controller-1 +pcs constraint location crosslink-controller-0 avoids controller-0 +pcs stonith level add 2 controller-0 crosslink-controller-0 +pcs stonith level add 2 controller-1 crosslink-controller-1 +~~~ + +Testing done: +- Simulate power outage by turning off the controller-1 VM and its IPMI interface and leaving the crosslink intact. + + * Expected Outcome: + We should retain quorum on controller-0 and all services should be running on controller-0. No UNCLEAN resources should be observed on controller-0. + * Actual Outcome: + Matched the expected outcome. diff --git a/agents/crosslink/fence_crosslink.py b/agents/crosslink/fence_crosslink.py new file mode 100755 index 0000000..7cfc90c --- /dev/null +++ b/agents/crosslink/fence_crosslink.py @@ -0,0 +1,113 @@ +#!@PYTHON@ -tt + +# Copyright (c) 2020 Red Hat +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see +# <http://www.gnu.org/licenses/>. + +import atexit +import logging +import sys +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import (all_opt, atexit_handler, check_input, # noqa: E402 + fence_action, process_input, run_command, run_delay, + show_docs) + +logger = logging.getLogger(__name__) +logger.setLevel("WARNING") + + +def get_power_status(conn, options): + logger.debug("get_power_status(): %s" % options) + ip = options['--crosscableip'] + timeout = options['--timeout'] + # This returns 'off' if not a single ICMP packet gets answered during the + # whole timeout window. (the ping executable will return 1 in such case and + # 0 if even a single packet gets replied to) + (status, stdout, stderr) = run_command(options, "ping -w%s -n %s" % + (timeout, ip)) + logger.debug("get_power_status(): %s - Stdout: %s - Stderr: %s" % + (status, stdout, stderr)) + if status == 0: + return "on" + else: + return "off" + + +def set_power_status(conn, options): + logger.debug("set_power_status(): %s" % options) + # If we got here it means the previous call to get_power_status() returned + # on At this point we've been invoked but the node is still reachable over + # the cross connect, so we can just error out. + ip = options['--crosscableip'] + if options['--action'] == 'off': + logger.error("We've been asked to turn off the node at %s but the " + "cross-cable link is up so erroring out" % ip) + sys.exit(1) + elif options['--action'] == 'on': + logger.error("We've been asked to turn on the node at %s but the " + "cross-cable link is off so erroring out" % ip) + sys.exit(1) + else: + logger.error("set_power_status() was called with action %s which " + "is not supported" % options['--action']) + sys.exit(1) + + +def define_new_opts(): + all_opt["crosscableip"] = { + "getopt": "a:", + "longopt": "crosscableip", + "help": "-a, --crosscableip=[IP] IP over the cross-cable link", + "required": "1", + "shortdesc": "Cross-cable IP", + "order": 1 + } + all_opt["timeout"] = { + "getopt": "T:", + "longopt": "timeout", + "help": "-T, --timeout=[seconds] timeout in seconds", + "required": "0", + "shortdesc": "No ICMP reply in 5 seconds -> Node is considered dead", + "default": "5", + "order": 1 + } + + +def main(): + atexit.register(atexit_handler) + + device_opt = ["crosscableip", "timeout", "no_password", "no_login", "port"] + define_new_opts() + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for cross-link two-node clusters" + docs["longdesc"] = "This agent helps two-node clusters to tackle the " \ + "situation where one node lost power, cannot be " \ + "fenced by telling pacemaker that if the node is not " \ + "reachable over the crosslink cable, we can assume " \ + "it is dead" + docs["vendorurl"] = "" + show_docs(options, docs) + + run_delay(options) + + result = fence_action(None, options, set_power_status, get_power_status) + sys.exit(result) + + +if __name__ == "__main__": + main() diff --git a/agents/cyberpower_ssh/fence_cyberpower_ssh.py b/agents/cyberpower_ssh/fence_cyberpower_ssh.py new file mode 100755 index 0000000..f0695d6 --- /dev/null +++ b/agents/cyberpower_ssh/fence_cyberpower_ssh.py @@ -0,0 +1,70 @@ +#!@PYTHON@ -tt + +##### +## +## Fence agent for CyberPower based SSH-capable power strip +## Tested with CyberPower model PDU41001, ePDU Firmware version 1.2.0 +## +##### + +import sys, re, time +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS + +def set_power_status(conn, options): + conn.send_eol("oltctrl index " + options["--plug"] + " act delay" + options["--action"]) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def get_power_status(conn, options): + outlets = {} + conn.send_eol("oltsta show") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + lines = conn.before.split("\n") + show_re = re.compile(r'(\s*)(\d)\s*(.*)\s*(On|Off)\s*') + for line in lines: + res = show_re.search(line) + if res != None: + outlets[res.group(2)] = (res.group(3), res.group(4)) + if ["list", "monitor"].count(options["--action"]) == 1: + return outlets + else: + try: + (_,status) = outlets[options["--plug"]] + return status.lower().strip() + except KeyError: + fail(EC_STATUS) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "port"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["\n>", "\nCyberPower >"] + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for CyberPower over ssh" + docs["longdesc"] = "fence_cyberpower_ssh is an I/O Fencing agent \ +which can be used with the CyberPower network power switch. It logs into \ +device via ssh and reboots a specified outlet. Lengthy ssh connections \ +should be avoided while a GFS cluster is running because the connection \ +will block any necessary fencing actions." + docs["vendorurl"] = "http://www.cyberpower.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/docker/fence_docker.py b/agents/docker/fence_docker.py new file mode 100644 index 0000000..0044025 --- /dev/null +++ b/agents/docker/fence_docker.py @@ -0,0 +1,161 @@ +#!@PYTHON@ -tt + +import atexit +import sys +import io +import logging +import pycurl +import json + +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import fail_usage, all_opt, fence_action, atexit_handler, check_input, process_input, show_docs, run_delay + +def get_power_status(conn, options): + del conn + status = send_cmd(options, "containers/%s/json" % options["--plug"]) + if status is None: + return None + return "on" if status["State"]["Running"] else "off" + + +def set_power_status(conn, options): + del conn + if options["--action"] == "on": + send_cmd(options, "containers/%s/start" % options["--plug"], True) + else: + send_cmd(options, "containers/%s/kill" % options["--plug"], True) + return + + +def reboot_cycle(conn, options): + del conn + send_cmd(options, "containers/%s/restart" % options["--plug"], True) + return get_power_status(conn, options) + + +def get_list(conn, options): + del conn + output = send_cmd(options, "containers/json?all=1") + containers = {} + for container in output: + containers[container["Id"]] = ({True:container["Names"][0][1:], False: container["Names"][0]}[container["Names"][0][0:1] == '/'], {True:"off", False: "on"}[container["Status"][:4].lower() == "exit"]) + return containers + + +def send_cmd(options, cmd, post = False): + url = "http%s://%s:%s/v%s/%s" % ("s" if "--ssl-secure" in options or "--ssl-insecure" in options else "", options["--ip"], options["--ipport"], options["--api-version"], cmd) + conn = pycurl.Curl() + output_buffer = io.BytesIO() + if logging.getLogger().getEffectiveLevel() < logging.WARNING: + conn.setopt(pycurl.VERBOSE, True) + conn.setopt(pycurl.HTTPGET, 1) + conn.setopt(pycurl.URL, url.encode("ascii")) + if post: + conn.setopt(pycurl.POST, 1) + conn.setopt(pycurl.POSTFIELDSIZE, 0) + conn.setopt(pycurl.WRITEFUNCTION, output_buffer.write) + conn.setopt(pycurl.TIMEOUT, int(options["--shell-timeout"])) + + if "--ssl-secure" in options: + if not (set(("--tlscert", "--tlskey", "--tlscacert")) <= set(options)): + fail_usage("Failed. If --ssl option is used, You have to also \ +specify: --tlscert, --tlskey and --tlscacert") + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSLCERT, options["--tlscert"]) + conn.setopt(pycurl.SSLKEY, options["--tlskey"]) + conn.setopt(pycurl.CAINFO, options["--tlscacert"]) + elif "--ssl-insecure" in options: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + + logging.debug("URL: " + url) + + try: + conn.perform() + result = output_buffer.getvalue().decode() + return_code = conn.getinfo(pycurl.RESPONSE_CODE) + + logging.debug("RESULT [" + str(return_code) + \ + "]: " + result) + conn.close() + if return_code == 200: + return json.loads(result) + except pycurl.error: + logging.error("Connection failed") + except: + if result is not None: + logging.error(result) + logging.error("Cannot parse json") + return None + + +def main(): + atexit.register(atexit_handler) + + all_opt["tlscert"] = { + "getopt" : ":", + "longopt" : "tlscert", + "help" : "--tlscert " + "Path to client certificate for TLS authentication", + "required" : "0", + "shortdesc" : "Path to client certificate (PEM format) \ +for TLS authentication. Required if --ssl option is used.", + "order": 2 + } + + all_opt["tlskey"] = { + "getopt" : ":", + "longopt" : "tlskey", + "help" : "--tlskey " + "Path to client key for TLS authentication", + "required" : "0", + "shortdesc" : "Path to client key (PEM format) for TLS \ +authentication. Required if --ssl option is used.", + "order": 2 + } + + all_opt["tlscacert"] = { + "getopt" : ":", + "longopt" : "tlscacert", + "help" : "--tlscacert " + "Path to CA certificate for TLS authentication", + "required" : "0", + "shortdesc" : "Path to CA certificate (PEM format) for \ +TLS authentication. Required if --ssl option is used.", + "order": 2 + } + + all_opt["api_version"] = { + "getopt" : ":", + "longopt" : "api-version", + "help" : "--api-version " + "Version of Docker Remote API (default: 1.11)", + "required" : "0", + "order" : 2, + "default" : "1.11", + } + + device_opt = ["ipaddr", "no_password", "no_login", "port", "method", "web", "tlscert", "tlskey", "tlscacert", "ssl", "api_version"] + + all_opt["ssl"]["default"] = "1" + + options = check_input(device_opt, process_input(device_opt)) + + docs = { } + docs["shortdesc"] = "Fence agent for Docker" + docs["longdesc"] = "fence_docker is I/O fencing agent which \ +can be used with the Docker Engine containers. You can use this \ +fence-agent without any authentication, or you can use TLS authentication \ +(use --ssl option, more info about TLS authentication in docker: \ +http://docs.docker.com/examples/https/)." + docs["vendorurl"] = "www.docker.io" + show_docs(options, docs) + + run_delay(options) + + result = fence_action(None, options, set_power_status, get_power_status, get_list, reboot_cycle) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/drac/fence_drac.py b/agents/drac/fence_drac.py new file mode 100644 index 0000000..be3e9a5 --- /dev/null +++ b/agents/drac/fence_drac.py @@ -0,0 +1,62 @@ +#!@PYTHON@ -tt + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * + +def get_power_status(conn, options): + conn.send_eol("getmodinfo") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + status = re.compile(r"\s+(on|off)\s+", re.IGNORECASE).search(conn.before).group(1) + return status.lower().strip() + +def set_power_status(conn, options): + action = { + 'on' : "powerup", + 'off': "powerdown" + }[options["--action"]] + + conn.send_eol("serveraction -d 0 " + action) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "telnet"] + + atexit.register(atexit_handler) + + opt = process_input(device_opt) + if "--username" in opt: + all_opt["cmd_prompt"]["default"] = ["\\[" + opt["--username"] + "\\]# "] + else: + all_opt["cmd_prompt"]["default"] = ["\\[" "username" + "\\]# "] + + options = check_input(device_opt, opt) + + docs = {} + docs["shortdesc"] = "I/O Fencing agent for Dell DRAC IV" + docs["longdesc"] = "fence_drac is an I/O Fencing agent which can be used with \ +the Dell Remote Access Card (DRAC). This card provides remote access to controlling \ +power to a server. It logs into the DRAC through the telnet interface of the card. By \ +default, the telnet interface is not enabled. To enable the interface, you will need \ +to use the racadm command in the racser-devel rpm available from Dell. \ +\ +To enable telnet on the DRAC: \ +\ +[root]# racadm config -g cfgSerial -o cfgSerialTelnetEnable 1 \ +\ +[root]# racadm racreset \ +" + docs["vendorurl"] = "http://www.dell.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, None) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/drac5/fence_drac5.py b/agents/drac5/fence_drac5.py new file mode 100644 index 0000000..648ecd9 --- /dev/null +++ b/agents/drac5/fence_drac5.py @@ -0,0 +1,147 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## DRAC Version Firmware +## +-----------------+---------------------------+ +## DRAC 5 1.0 (Build 06.05.12) +## DRAC 5 1.21 (Build 07.05.04) +## +## @note: drac_version was removed +##### + +import sys, re, time +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage + +def get_power_status(conn, options): + if options["--drac-version"] == "DRAC MC": + (_, status) = get_list_devices(conn, options)[options["--plug"]] + else: + if options["--drac-version"] == "DRAC CMC": + conn.send_eol("racadm serveraction powerstatus -m " + options["--plug"]) + elif options["--drac-version"] == "DRAC 5": + conn.send_eol("racadm serveraction powerstatus") + + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + status = re.compile(r"(^|: )(ON|OFF|Powering ON|Powering OFF)\s*$", + re.IGNORECASE | re.MULTILINE).search(conn.before).group(2) + + if status.lower().strip() in ["on", "powering on", "powering off"]: + return "on" + else: + return "off" + +def set_power_status(conn, options): + action = { + 'on' : "powerup", + 'off': "powerdown" + }[options["--action"]] + + if options["--drac-version"] == "DRAC CMC": + conn.send_eol("racadm serveraction " + action + " -m " + options["--plug"]) + elif options["--drac-version"] == "DRAC 5": + conn.send_eol("racadm serveraction " + action) + elif options["--drac-version"] == "DRAC MC": + conn.send_eol("racadm serveraction -s " + options["--plug"] + " " + action) + + ## Fix issue with double-enter [CR/LF] + ## We need to read two additional command prompts (one from get + one from set command) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + if len(conn.before.strip()) == 0: + options["eol"] = options["eol"][:-1] + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +def get_list_devices(conn, options): + outlets = {} + + if options["--drac-version"] == "DRAC CMC": + conn.send_eol("getmodinfo") + + list_re = re.compile(r"^([^\s]*?)\s+Present\s*(ON|OFF)\s*.*$") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + for line in conn.before.splitlines(): + if list_re.search(line): + outlets[list_re.search(line).group(1)] = ("", list_re.search(line).group(2)) + elif options["--drac-version"] == "DRAC MC": + conn.send_eol("getmodinfo") + + list_re = re.compile(r"^\s*([^\s]*)\s*---->\s*(.*?)\s+Present\s*(ON|OFF)\s*.*$") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + for line in conn.before.splitlines(): + if list_re.search(line): + outlets[list_re.search(line).group(2)] = ("", list_re.search(line).group(3)) + elif options["--drac-version"] == "DRAC 5": + ## DRAC 5 can be used only for one computer + ## standard fence library can't handle correctly situation + ## when some fence devices supported by fence agent + ## works with 'list' and other should returns 'N/A' + print("N/A") + + return outlets + +def define_new_opts(): + all_opt["drac_version"] = { + "getopt" : "d:", + "longopt" : "drac-version", + "help" : "-d, --drac-version=[version] Force DRAC version to use (DRAC 5|DRAC CMC|DRAC MC)", + "required" : "0", + "shortdesc" : "Force DRAC version to use", + "choices" : ["DRAC CMC", "DRAC MC", "DRAC 5"], + "order" : 1} + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "drac_version", "port", "no_port", "telnet"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["cmd_prompt"]["default"] = [r"\$", r"DRAC\/MC:"] + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Dell DRAC CMC/5" + docs["longdesc"] = "fence_drac5 is an I/O Fencing agent \ +which can be used with the Dell Remote Access Card v5 or CMC (DRAC). \ +This device provides remote access to controlling power to a server. \ +It logs into the DRAC through the telnet/ssh interface of the card. \ +By default, the telnet interface is not enabled." + docs["vendorurl"] = "http://www.dell.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + ###### + conn = fence_login(options) + + if "--drac-version" not in options: + ## autodetect from text issued by fence device + if conn.before.find("CMC") >= 0: + options["--drac-version"] = "DRAC CMC" + elif conn.before.find("DRAC 5") >= 0: + options["--drac-version"] = "DRAC 5" + elif conn.after.find("DRAC/MC") >= 0: + options["--drac-version"] = "DRAC MC" + else: + ## Assume this is DRAC 5 by default as we don't want to break anything + options["--drac-version"] = "DRAC 5" + + if options["--drac-version"] in ["DRAC MC", "DRAC CMC"]: + if "--plug" not in options and 0 == ["monitor", "list"].count(options["--action"]): + fail_usage("Failed: You have to enter module name (-n)") + + result = fence_action(conn, options, set_power_status, get_power_status, get_list_devices) + fence_logout(conn, "exit", 1) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/dummy/fence_dummy.py b/agents/dummy/fence_dummy.py new file mode 100644 index 0000000..8fa2d9a --- /dev/null +++ b/agents/dummy/fence_dummy.py @@ -0,0 +1,133 @@ +#!@PYTHON@ -tt + +import sys, random +import logging +import time +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, run_delay + +plug_status = "on" + +def get_power_status_file(conn, options): + del conn + + try: + status_file = open(options["--status-file"], 'r') + except Exception: + return "off" + + status = status_file.read() + status_file.close() + + return status.lower() + +def set_power_status_file(conn, options): + del conn + + if not (options["--action"] in ["on", "off"]): + return + + status_file = open(options["--status-file"], 'w') + status_file.write(options["--action"]) + status_file.close() + +def get_power_status_fail(conn, options): + outlets = get_outlets_fail(conn, options) + + if len(outlets) == 0 or "--plug" not in options: + fail_usage("Failed: You have to enter existing machine!") + else: + return outlets[options["--plug"]][0] + +def set_power_status_fail(conn, options): + global plug_status + del conn + + plug_status = "unknown" + if options["--action"] == "on": + plug_status = "off" + +def get_outlets_fail(conn, options): + del conn + + result = {} + global plug_status + + if options["--action"] == "on": + plug_status = "off" + + # This fake agent has no port data to list, so we have to make + # something up for the list action. + if options.get("--action", None) == "list": + result["fake_port_1"] = [plug_status, "fake"] + result["fake_port_2"] = [plug_status, "fake"] + elif "--plug" not in options: + fail_usage("Failed: You have to enter existing machine!") + else: + port = options["--plug"] + result[port] = [plug_status, "fake"] + + return result + +def main(): + device_opt = ["no_password", "status_file", "random_sleep_range", "type", "no_port"] + + atexit.register(atexit_handler) + + all_opt["status_file"] = { + "getopt" : ":", + "longopt" : "status-file", + "help":"--status-file=[file] Name of file that holds current status", + "required" : "0", + "shortdesc" : "File with status", + "default" : "/tmp/fence_dummy.status", + "order": 1 + } + + all_opt["random_sleep_range"] = { + "getopt" : ":", + "longopt" : "random_sleep_range", + "help":"--random_sleep_range=[seconds] Issue a sleep between 1 and [seconds]", + "required" : "0", + "shortdesc" : "Issue a sleep between 1 and X seconds. Used for testing.", + "order": 1 + } + + all_opt["type"] = { + "getopt" : ":", + "longopt" : "type", + "help":"--type=[type] Possible types are: file and fail", + "required" : "0", + "shortdesc" : "Type of the dummy fence agent", + "default" : "file", + "order": 1 + } + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Dummy fence agent" + docs["longdesc"] = "fence_dummy" + docs["vendorurl"] = "http://www.example.com" + show_docs(options, docs) + + run_delay(options) + + # random sleep for testing + if "--random_sleep_range" in options: + val = int(options["--random_sleep_range"]) + ran = random.randint(1, val) + logging.info("Random sleep for %d seconds\n", ran) + time.sleep(ran) + + if options["--type"] == "fail": + result = fence_action(None, options, set_power_status_fail, get_power_status_fail, get_outlets_fail) + else: + result = fence_action(None, options, set_power_status_file, get_power_status_file, None) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/eaton_snmp/README b/agents/eaton_snmp/README new file mode 100644 index 0000000..82619d7 --- /dev/null +++ b/agents/eaton_snmp/README @@ -0,0 +1,20 @@ +This is an snmp based fence agent for Eaton power distribution units to be used +with RHEL4 Red Hat Cluster Suite. + +In order to use this agent, you will need to have net-snmp-utils installed +on every node in your cluster. net-snmp-utils is scheduled for inclusion +in the base RHEL distribution for Update 4, and is yummable in FC5. + +To use the agent, cp the agent to the /sbin directory on every +cluster node. + +Then define a <fencedevice> in the cluster.conf file with +agent="fence_eaton_snmp" as an attribute, and use it that way. +Note, please, that the GUI does not support this agent yet, and you will have +to edit your cluster.conf by hand and then propagate it yourself. If you need +help with this, email me at the address below. + +The interface for the fence_eaton_snmp agent is identical to the existing +fence_apc_snmp agent, upon which it has been derived. + +--Arnaud Quette - ArnaudQuette@Eaton.com diff --git a/agents/eaton_snmp/fence_eaton_snmp.py b/agents/eaton_snmp/fence_eaton_snmp.py new file mode 100644 index 0000000..9fbc056 --- /dev/null +++ b/agents/eaton_snmp/fence_eaton_snmp.py @@ -0,0 +1,229 @@ +#!@PYTHON@ -tt + +# The Following agent has been tested on: +# - Eaton ePDU Managed - SNMP v1 +# EATON | Powerware ePDU model: Managed ePDU (PW104MA0UB99), firmware: 01.01.01 +# - Eaton ePDU Switched - SNMP v1 +# EATON | Powerware ePDU model: Switched ePDU (IPV3600), firmware: 2.0.K + +import sys +import atexit +import logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage +from fencing_snmp import FencingSnmp + +### CONSTANTS ### +# oid defining fence device +OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' + +### GLOBAL VARIABLES ### +# Device - see EatonManagedePDU, EatonSwitchedePDU +device = None + +# Port ID +port_id = None +# Switch ID +switch_id = None + +# Did we issue a set before get (to adjust OID with Switched ePDU) +after_set = False + +# Classes describing Device params +# Managed ePDU +class EatonManagedePDU(object): + status_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.3.%d' + control_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.3.%d' + outlet_table_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.1' + ident_str = "Eaton Managed ePDU" + state_off = 0 + state_on = 1 + state_cycling = 2 # FIXME: not usable with fence-agents + turn_off = 0 + turn_on = 1 + turn_cycle = 2 # FIXME: not usable with fence-agents + has_switches = False + +# Switched ePDU (Pulizzi 2) +# NOTE: sysOID reports "20677.1", while data are actually at "20677.2" +class EatonSwitchedePDU(object): + status_oid = '.1.3.6.1.4.1.20677.2.6.3.%d.0' + control_oid = '.1.3.6.1.4.1.20677.2.6.2.%d.0' + outlet_table_oid = '.1.3.6.1.4.1.20677.2.6.3' + ident_str = "Eaton Switched ePDU" + state_off = 2 + state_on = 1 + state_cycling = 0 # Note: this status doesn't exist on this device + turn_off = 2 + turn_on = 1 + turn_cycle = 3 # FIXME: not usable with fence-agents + has_switches = False + +### FUNCTIONS ### +def eaton_set_device(conn): + global device + + agents_dir = {'.1.3.6.1.4.1.534.6.6.6':EatonManagedePDU, + '.1.3.6.1.4.1.20677.1':EatonSwitchedePDU, + '.1.3.6.1.4.1.20677.2':EatonSwitchedePDU} + + # First resolve type of Eaton + eaton_type = conn.walk(OID_SYS_OBJECT_ID) + + if not ((len(eaton_type) == 1) and (eaton_type[0][1] in agents_dir)): + eaton_type = [[None, None]] + + device = agents_dir[eaton_type[0][1]] + + logging.debug("Trying %s"%(device.ident_str)) + +def eaton_resolv_port_id(conn, options): + global port_id, switch_id + + if device == None: + eaton_set_device(conn) + + # Restore the increment, that was removed in main for ePDU Managed + if device.ident_str == "Eaton Switched ePDU": + options["--plug"] = str(int(options["--plug"]) + 1) + + # Now we resolv port_id/switch_id + if options["--plug"].isdigit() and ((not device.has_switches) or (options["--switch"].isdigit())): + port_id = int(options["--plug"]) + + if device.has_switches: + switch_id = int(options["--switch"]) + else: + table = conn.walk(device.outlet_table_oid, 30) + + for x in table: + if x[1].strip('"') == options["--plug"]: + t = x[0].split('.') + if device.has_switches: + port_id = int(t[len(t)-1]) + switch_id = int(t[len(t)-3]) + else: + if device.ident_str == "Eaton Switched ePDU": + port_id = int(t[len(t)-3]) + else: + port_id = int(t[len(t)-1]) + + if port_id == None: + # Restore index offset, to provide a valid error output on Managed ePDU + if device.ident_str != "Eaton Switched ePDU": + options["--plug"] = str(int(options["--plug"]) + 1) + fail_usage("Can't find port with name %s!"%(options["--plug"])) + +def get_power_status(conn, options): + global port_id, after_set + + if port_id == None: + eaton_resolv_port_id(conn, options) + + # Ajust OID for Switched ePDU when the get is after a set + if after_set and device.ident_str == "Eaton Switched ePDU": + port_id -= 1 + after_set = False + + oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id)) + + try: + (oid, status) = conn.get(oid) + if status == str(device.state_on): + return "on" + elif status == str(device.state_off): + return "off" + else: + return None + except Exception: + return None + +def set_power_status(conn, options): + global port_id, after_set + + after_set = True + + if port_id == None: + eaton_resolv_port_id(conn, options) + + # Controls start at #2 on Switched ePDU, since #1 is the global command + if device.ident_str == "Eaton Switched ePDU": + port_id = int(port_id)+1 + + oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id)) + + conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off)) + + +def get_outlets_status(conn, options): + outletCount = 0 + result = {} + + if device == None: + eaton_set_device(conn) + + res_ports = conn.walk(device.outlet_table_oid, 30) + + for x in res_ports: + outletCount += 1 + status = x[1] + t = x[0].split('.') + + # Plug indexing start from zero, so we substract '1' from the + # user's given plug number + if device.ident_str == "Eaton Managed ePDU": + port_num = str(int(((device.has_switches) and + "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1]))) + 1) + + # Plug indexing start from zero, so we add '1' + # for the user's exposed plug number + port_name = str(int(x[1].strip('"')) + 1) + port_status = "" + result[port_num] = (port_name, port_status) + else: + # Switched ePDU do not propose an outletCount OID! + # Invalid status (ie value == '0'), retrieved via the walk, + # means the outlet is absent + port_num = str(outletCount) + port_name = str(outletCount) + port_status = "" + if status != '0': + result[port_num] = (port_name, port_status) + + return result + +# Main agent method +def main(): + device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ + "port", "snmp_version", "snmp"] + + atexit.register(atexit_handler) + + all_opt["switch"]["default"] = 1 + all_opt["power_wait"]["default"] = 2 + all_opt["snmp_version"]["default"] = "1" + all_opt["community"]["default"] = "private" + options = check_input(device_opt, process_input(device_opt)) + + # Plug indexing start from zero on ePDU Managed, so we substract '1' from + # the user's given plug number. + # For Switched ePDU, we will add this back again later. + if "--plug" in options and options["--plug"].isdigit(): + options["--plug"] = str(int(options["--plug"]) - 1) + + docs = {} + docs["shortdesc"] = "Fence agent for Eaton over SNMP" + docs["longdesc"] = "fence_eaton_snmp is an I/O Fencing agent \ +which can be used with the Eaton network power switch. It logs \ +into a device via SNMP and reboots a specified outlet. It supports \ +SNMP v1 and v3 with all combinations of authenticity/privacy settings." + docs["vendorurl"] = "http://powerquality.eaton.com" + show_docs(options, docs) + + # Operate the fencing device + result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) +if __name__ == "__main__": + main() diff --git a/agents/ecloud/fence_ecloud.py b/agents/ecloud/fence_ecloud.py new file mode 100644 index 0000000..0707e10 --- /dev/null +++ b/agents/ecloud/fence_ecloud.py @@ -0,0 +1,169 @@ +#!@PYTHON@ -tt +# +# Fence agent for eCloud and eCloud VPC +# https://www.ans.co.uk/cloud-and-infrastructure/ecloud/ +# +# Copyright (c) 2022 ANS Group Limited +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see +# <http://www.gnu.org/licenses/>. + +import sys +import time +import atexit +import logging +import requests +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import run_delay, fail_usage, fail, EC_TIMED_OUT + +API_BASE = "https://api.ukfast.io/ecloud" +API_MONITOR = API_BASE + "/ping" +API_VPC_INSTANCE_DATA = API_BASE + "/v2/instances/:ID" +API_VPC_POWER_ON = API_BASE + "/v2/instances/:ID/power-on" +API_VPC_POWER_OFF = API_BASE + "/v2/instances/:ID/power-off" +API_V1_INSTANCE_DATA = API_BASE + "/v1/vms/:ID" +API_V1_POWER_ON = API_BASE + "/v1/vms/:ID/power-on" +API_V1_POWER_OFF = API_BASE + "/v1/vms/:ID/power-off" + + +def set_power_fn(conn, options): + logging.debug("setting power {}".format(options['--action'])) + del conn + + action = options['--action'] + vpc = options['--ecloud-vpc'] + plug = options['--plug'] + + url = fence_url(vpc, action, plug) + hdrs = headers(options['--apikey']) + + logging.info("executing '{}' action on '{}'".format(action, plug)) + + retries = 0 + while True: + resp = requests.put(url, headers=hdrs) + if resp.status_code == 409: + # If we attempt to power the instance back on too soon after powering it off, + # e.g. during a reboot, the API will return a 409 because while the power status + # has changed, the task is still executing. Retry the action until we exceed + # retries or get a different status code. + if retries >= 6: + logging.error("timed out trying to execute '{}' action after repeated 409 codes from API", action) + fail(EC_TIMED_OUT) + + time.sleep(2) + retries += 1 + continue + + if resp.status_code != 202: + logging.error("unexpected status code '{}' from endpoint '{}': {}".format( + resp.status_code, url, resp.text + )) + + break + + +def get_power_fn(conn, options): + logging.debug("getting power state") + del conn + + vpc = options['--ecloud-vpc'] + plug = options['--plug'] + + url = instance_data_url(vpc, plug) + hdrs = headers(options['--apikey']) + + resp = requests.get(url, headers=hdrs) + if resp.status_code != 200: + logging.error("unexpected status code ('{}') from endpoint '{}': {}".format( + resp.status_code, url, resp.text + )) + return "bad status {}".format(resp.status_code) + + instance = resp.json()['data'] + if vpc: + logging.debug("power state return value: {}".format(instance['online'])) + return "on" if instance['online'] else "off" + else: + if instance['power_status'] == "Online": + return "on" + elif instance['power_status'] == "Offline": + return "off" + else: + # Could be 'Unknown' or other value + return instance['power_status'] + + +def headers(apikey): + return { + "Authorization": apikey, + "User-Agent": "fence_ecloud" + } + + +def itp(url, plug): + return url.replace(':ID', plug) + + +def fence_url(vpc, action, plug): + if action == "on": + return itp(API_VPC_POWER_ON, plug) if vpc else itp(API_V1_POWER_ON, plug) + if action == "off": + return itp(API_VPC_POWER_OFF, plug) if vpc else itp(API_V1_POWER_OFF, plug) + + fail_usage("no available API configured for action '{}'".format(action)) + + +def instance_data_url(vpc, plug): + return itp(API_VPC_INSTANCE_DATA, plug) if vpc else itp(API_V1_INSTANCE_DATA, plug) + + +def main(): + device_opt = ["apikey", "port", "no_login", "no_password"] + + all_opt["apikey"] = { + "getopt": ":", + "longopt": "apikey", + "help": "--apikey=[key] eCloud API Key", + "required": "1", + "shortdesc": "API Key", + "order": 0, + } + all_opt["port"]["help"] = "-n, --plug=[instance] Instance ID (VPC) or server ID (v1)" + + atexit.register(atexit_handler) + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence Agent for ANS eCloud" + docs["longdesc"] = "fence_ecloud is a fence agent for use with the ANS \ +eCloud platform which is compatible with eCloud VPC and eCloud v1." + docs["vendorurl"] = "https://www.ans.co.uk" + show_docs(options, docs) + + if options['--action'] in ['on', 'off', 'reboot', 'status']: + plug = options['--plug'] + + options['--ecloud-vpc'] = True + if not plug.startswith("i-"): + options['--ecloud-vpc'] = False + + run_delay(options) + fence_action(None, options, set_power_fn, get_power_fn) + + +if __name__ == '__main__': + main() diff --git a/agents/emerson/fence_emerson.py b/agents/emerson/fence_emerson.py new file mode 100644 index 0000000..2e65cda --- /dev/null +++ b/agents/emerson/fence_emerson.py @@ -0,0 +1,62 @@ +#!@PYTHON@ -tt + +import sys +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing_snmp import FencingSnmp + +### CONSTANTS ### +STATUSES_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.95" +CONTROL_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.100" +NAMES_OID = ".1.3.6.1.4.1.476.1.42.3.8.50.20.1.10" + +# Status constants returned as value from SNMP +STATUS_DOWN = 1 +STATUS_UP = 2 + +# Status constants to set as value to SNMP +STATUS_SET_OFF = 0 +STATUS_SET_ON = 1 + +def get_power_status(conn, options): + (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) + return status == str(STATUS_UP) and "on" or "off" + +def set_power_status(conn, options): + conn.set("%s.%s" % (CONTROL_OID, options["--plug"]), + (options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF)) + +def get_outlets_status(conn, _): + result = {} + res_outlet = conn.walk(STATUSES_OID, 30) + + for outlet_info in res_outlet: + port_num = ".".join(outlet_info[0].split('.')[-3:]) + port_alias = conn.get("%s.%s"% (NAMES_OID, port_num))[1] + port_status = (outlet_info[1] == str(STATUS_UP) and "on" or "off") + result[port_num] = (port_alias, port_status) + return result + +def main(): + device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ + "port", "snmp_version", "snmp"] + + atexit.register(atexit_handler) + + all_opt["power_wait"]["default"] = "5" + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Emerson over SNMP" + docs["longdesc"] = "fence_emerson is an I/O Fencing agent \ + which can be used with MPX and MPH2 managed rack PDU." + docs["vendorurl"] = "http://www.emersonnetworkpower.com" + show_docs(options, docs) + + # Operate the fencing device + result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) +if __name__ == "__main__": + main() diff --git a/agents/eps/fence_eps.py b/agents/eps/fence_eps.py new file mode 100644 index 0000000..f0df862 --- /dev/null +++ b/agents/eps/fence_eps.py @@ -0,0 +1,129 @@ +#!@PYTHON@ -tt + +# The Following Agent Has Been Tested On: +# ePowerSwitch 8M+ version 1.0.0.4 + +import sys, re +import base64, string, socket +import logging +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, EC_LOGIN_DENIED, EC_TIMED_OUT, run_delay + +if sys.version_info[0] > 2: + import http.client as httplib +else: + import httplib + +# Run command on EPS device. +# @param options Device options +# @param params HTTP GET parameters (without ?) +def eps_run_command(options, params): + try: + # New http connection + conn = httplib.HTTPConnection(options["--ip"]) + + request_str = "/"+options["--page"] + + if params != "": + request_str += "?"+params + + logging.debug("GET %s\n", request_str) + conn.putrequest('GET', request_str) + + if "--username" in options: + if "--password" not in options: + options["--password"] = "" # Default is empty password + + # String for Authorization header + auth_str = 'Basic ' + string.strip(base64.encodestring(options["--username"]+':'+options["--password"])) + logging.debug("Authorization: %s\n", auth_str) + conn.putheader('Authorization', auth_str) + + conn.endheaders() + + response = conn.getresponse() + + logging.debug("%d %s\n", response.status, response.reason) + + #Response != OK -> couldn't login + if response.status != 200: + fail(EC_LOGIN_DENIED) + + result = response.read() + logging.debug("%s \n", result) + conn.close() + except socket.timeout: + fail(EC_TIMED_OUT) + except socket.error as e: + logging.error("Failed: {}".format(str(e))) + fail(EC_LOGIN_DENIED) + + return result + +def get_power_status(conn, options): + del conn + ret_val = eps_run_command(options, "") + + result = {} + status = re.findall(r"p(\d{2})=(0|1)\s*\<br\>", ret_val.lower()) + for out_num, out_stat in status: + result[out_num] = ("", (out_stat == "1" and "on" or "off")) + + if not options["--action"] in ['monitor', 'list']: + if not options["--plug"] in result: + fail_usage("Failed: You have to enter existing physical plug!") + else: + return result[options["--plug"]][1] + else: + return result + +def set_power_status(conn, options): + del conn + eps_run_command(options, "P%s=%s"%(options["--plug"], (options["--action"] == "on" and "1" or "0"))) + +# Define new option +def eps_define_new_opts(): + all_opt["hidden_page"] = { + "getopt" : "c:", + "longopt" : "page", + "help":"-c, --page=[page] Name of hidden page (default: hidden.htm)", + "required" : "0", + "shortdesc" : "Name of hidden page", + "default" : "hidden.htm", + "order": 1 + } + +# Starting point of fence agent +def main(): + device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ + "port", "hidden_page", "web"] + + atexit.register(atexit_handler) + + eps_define_new_opts() + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for ePowerSwitch" + docs["longdesc"] = "fence_eps is an I/O Fencing agent \ +which can be used with the ePowerSwitch 8M+ power switch to fence \ +connected machines. Fence agent works ONLY on 8M+ device, because \ +this is only one, which has support for hidden page feature. \ +\n.TP\n\ +Agent basically works by connecting to hidden page and pass \ +appropriate arguments to GET request. This means, that hidden \ +page feature must be enabled and properly configured." + docs["vendorurl"] = "http://www.epowerswitch.com" + show_docs(options, docs) + + run_delay(options) + #Run fence action. Conn is None, beacause we always need open new http connection + result = fence_action(None, options, set_power_status, get_power_status, get_power_status) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py new file mode 100644 index 0000000..53d6fd1 --- /dev/null +++ b/agents/evacuate/fence_evacuate.py @@ -0,0 +1,428 @@ +#!@PYTHON@ -tt + +import sys +import time +import atexit +import logging +import inspect +import requests.exceptions + +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, is_executable, run_command, run_delay + +EVACUABLE_TAG = "evacuable" +TRUE_TAGS = ['true'] + +def get_power_status(connection, options): + + status = "unknown" + logging.debug("get action: " + options["--action"]) + + if connection: + try: + services = connection.services.list(host=options["--plug"], binary="nova-compute") + for service in services: + logging.debug("Status of %s is %s, %s" % (service.binary, service.state, service.status)) + if service.state == "up" and service.status == "enabled": + # Up and operational + status = "on" + + elif service.state == "down" and service.status == "disabled": + # Down and fenced + status = "off" + + elif service.state == "down": + # Down and requires fencing + status = "failed" + + elif service.state == "up": + # Up and requires unfencing + status = "running" + else: + logging.warning("Unknown status detected from nova for %s: %s, %s" % (options["--plug"], service.state, service.status)) + status = "%s %s" % (service.state, service.status) + break + except requests.exception.ConnectionError as err: + logging.warning("Nova connection failed: " + str(err)) + return status + +# NOTE(sbauza); We mimic the host-evacuate module since it's only a contrib +# module which is not stable +def _server_evacuate(connection, server, on_shared_storage): + success = False + error_message = "" + try: + logging.debug("Resurrecting instance: %s" % server) + (response, dictionary) = connection.servers.evacuate(server=server, on_shared_storage=on_shared_storage) + + if response == None: + error_message = "No response while evacuating instance" + elif response.status_code == 200: + success = True + error_message = response.reason + else: + error_message = response.reason + + except Exception as e: + error_message = "Error while evacuating instance: %s" % e + + return { + "uuid": server, + "accepted": success, + "reason": error_message, + } + +def _is_server_evacuable(server, evac_flavors, evac_images): + reason = "flavor "+server.flavor.get('id') + if server.flavor.get('id') in evac_flavors: + return True + if hasattr(server.image, 'get'): + if server.image.get('id') in evac_images: + return True + reason = reason +" and image "+server.image.get('id') + + logging.debug("Instance is not evacuable: no match for %s" % reason) + return False + +def _get_evacuable_flavors(connection): + result = [] + flavors = connection.flavors.list(is_public=None) + # Since the detailed view for all flavors doesn't provide the extra specs, + # we need to call each of the flavor to get them. + for flavor in flavors: + tag = flavor.get_keys().get(EVACUABLE_TAG) + if tag and tag.strip().lower() in TRUE_TAGS: + result.append(flavor.id) + return result + +def _get_evacuable_images(connection): + result = [] + images = [] + if hasattr(connection, "images"): + images = connection.images.list(detailed=True) + elif hasattr(connection, "glance"): + # OSP12+ + images = connection.glance.list() + + for image in images: + if hasattr(image, 'metadata'): + tag = image.metadata.get(EVACUABLE_TAG) + if tag and tag.strip().lower() in TRUE_TAGS: + result.append(image.id) + elif hasattr(image, 'tags'): + # OSP12+ + if EVACUABLE_TAG in image.tags: + result.append(image.id) + return result + +def _host_evacuate(connection, options): + result = True + images = _get_evacuable_images(connection) + flavors = _get_evacuable_flavors(connection) + servers = connection.servers.list(search_opts={'host': options["--plug"], 'all_tenants': 1 }) + + if options["--instance-filtering"] == "False": + logging.debug("Not evacuating anything") + evacuables = [] + elif len(flavors) or len(images): + logging.debug("Filtering images and flavors: %s %s" % (repr(flavors), repr(images))) + # Identify all evacuable servers + logging.debug("Checking %s" % repr(servers)) + evacuables = [server for server in servers + if _is_server_evacuable(server, flavors, images)] + logging.debug("Evacuating %s" % repr(evacuables)) + else: + logging.debug("Evacuating all images and flavors") + evacuables = servers + + if options["--no-shared-storage"] != "False": + on_shared_storage = False + else: + on_shared_storage = True + + for server in evacuables: + logging.debug("Processing %s" % server) + if hasattr(server, 'id'): + response = _server_evacuate(connection, server.id, on_shared_storage) + if response["accepted"]: + logging.debug("Evacuated %s from %s: %s" % + (response["uuid"], options["--plug"], response["reason"])) + else: + logging.error("Evacuation of %s on %s failed: %s" % + (response["uuid"], options["--plug"], response["reason"])) + result = False + else: + logging.error("Could not evacuate instance: %s" % server.to_dict()) + # Should a malformed instance result in a failed evacuation? + # result = False + return result + +def set_attrd_status(host, status, options): + logging.debug("Setting fencing status for %s to %s" % (host, status)) + run_command(options, "attrd_updater -p -n evacuate -Q -N %s -U %s" % (host, status)) + +def set_power_status(connection, options): + logging.debug("set action: " + options["--action"]) + + if not connection: + return + + if options["--action"] == "off" and not _host_evacuate(options): + sys.exit(1) + + sys.exit(0) + +def get_plugs_list(connection, options): + result = {} + + if connection: + services = connection.services.list(binary="nova-compute") + for service in services: + longhost = service.host + shorthost = longhost.split('.')[0] + result[longhost] = ("", None) + result[shorthost] = ("", None) + return result + +def create_nova_connection(options): + nova = None + + try: + from novaclient import client + from novaclient.exceptions import NotAcceptable + except ImportError: + fail_usage("Nova not found or not accessible") + + from keystoneauth1 import loading + from keystoneauth1 import session + from keystoneclient import discover + + # Prefer the oldest and strip the leading 'v' + keystone_versions = discover.available_versions(options["--auth-url"]) + keystone_version = keystone_versions[0]['id'][1:] + kwargs = dict( + auth_url=options["--auth-url"], + username=options["--username"], + password=options["--password"] + ) + + if discover.version_match("2", keystone_version): + kwargs["tenant_name"] = options["--tenant-name"] + + elif discover.version_match("3", keystone_version): + kwargs["project_name"] = options["--tenant-name"] + kwargs["user_domain_name"] = options["--user-domain"] + kwargs["project_domain_name"] = options["--project-domain"] + + loader = loading.get_plugin_loader('password') + keystone_auth = loader.load_from_options(**kwargs) + keystone_session = session.Session(auth=keystone_auth, verify=not "--insecure" in options) + + versions = [ "2.11", "2" ] + for version in versions: + clientargs = inspect.getargspec(client.Client).varargs + + # Some versions of Openstack prior to Ocata only + # supported positional arguments for username, + # password, and tenant. + # + # Versions since Ocata only support named arguments. + # + # So we need to use introspection to figure out how to + # create a Nova client. + # + # Happy days + # + if clientargs: + # OSP < 11 + # ArgSpec(args=['version', 'username', 'password', 'project_id', 'auth_url'], + # varargs=None, + # keywords='kwargs', defaults=(None, None, None, None)) + nova = client.Client(version, + None, # User + None, # Password + None, # Tenant + None, # Auth URL + insecure="--insecure" in options, + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, + http_log_debug="--verbose" in options) + else: + # OSP >= 11 + # ArgSpec(args=['version'], varargs='args', keywords='kwargs', defaults=None) + nova = client.Client(version, + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, + http_log_debug="--verbose" in options) + + try: + nova.hypervisors.list() + return nova + + except NotAcceptable as e: + logging.warning(e) + + except Exception as e: + logging.warning("Nova connection failed. %s: %s" % (e.__class__.__name__, e)) + + logging.warning("Couldn't obtain a supported connection to nova, tried: %s\n" % repr(versions)) + return None + +def define_new_opts(): + all_opt["endpoint_type"] = { + "getopt" : "e:", + "longopt" : "endpoint-type", + "help" : "-e, --endpoint-type=[endpoint] Nova Endpoint type (publicURL, internalURL, adminURL)", + "required" : "0", + "shortdesc" : "Nova Endpoint type", + "default" : "internalURL", + "order": 1, + } + all_opt["tenant_name"] = { + "getopt" : "t:", + "longopt" : "tenant-name", + "help" : "-t, --tenant-name=[name] Keystone v2 Tenant or v3 Project Name", + "required" : "0", + "shortdesc" : "Keystone Admin Tenant or v3 Project", + "default" : "", + "order": 1, + } + all_opt["user-domain"] = { + "getopt" : "u:", + "longopt" : "user-domain", + "help" : "-u, --user-domain=[name] Keystone v3 User Domain", + "required" : "0", + "shortdesc" : "Keystone v3 User Domain", + "default" : "Default", + "order": 2, + } + all_opt["project-domain"] = { + "getopt" : "P:", + "longopt" : "project-domain", + "help" : "-P, --project-domain=[name] Keystone v3 Project Domain", + "required" : "0", + "shortdesc" : "Keystone v3 Project Domain", + "default" : "Default", + "order": 2, + } + all_opt["auth_url"] = { + "getopt" : "k:", + "longopt" : "auth-url", + "help" : "-k, --auth-url=[url] Keystone Admin Auth URL", + "required" : "0", + "shortdesc" : "Keystone Admin Auth URL", + "default" : "", + "order": 1, + } + all_opt["region_name"] = { + "getopt" : ":", + "longopt" : "region-name", + "help" : "--region-name=[region] Region Name", + "required" : "0", + "shortdesc" : "Region Name", + "default" : "", + "order": 1, + } + all_opt["insecure"] = { + "getopt" : "", + "longopt" : "insecure", + "help" : "--insecure Explicitly allow agent to perform \"insecure\" TLS (https) requests", + "required" : "0", + "shortdesc" : "Allow Insecure TLS Requests", + "order": 2, + } + all_opt["domain"] = { + "getopt" : "d:", + "longopt" : "domain", + "help" : "-d, --domain=[string] DNS domain in which hosts live, useful when the cluster uses short names and nova uses FQDN", + "required" : "0", + "shortdesc" : "DNS domain in which hosts live", + "order": 5, + } + all_opt["instance_filtering"] = { + "getopt" : "", + "longopt" : "instance-filtering", + "help" : "--instance-filtering Allow instances created from images and flavors with evacuable=true to be evacuated (or all if no images/flavors have been tagged)", + "required" : "0", + "shortdesc" : "Allow instances to be evacuated", + "default" : "True", + "order": 5, + } + all_opt["no_shared_storage"] = { + "getopt" : "", + "longopt" : "no-shared-storage", + "help" : "--no-shared-storage Disable functionality for shared storage", + "required" : "0", + "shortdesc" : "Disable functionality for dealing with shared storage", + "default" : "False", + "order": 5, + } + all_opt["compute-domain"] = { + "getopt" : ":", + "longopt" : "compute-domain", + "help" : "--compute-domain=[string] Replaced by --domain", + "required" : "0", + "shortdesc" : "Replaced by domain", + "order": 6, + } + +def main(): + atexit.register(atexit_handler) + + device_opt = ["login", "passwd", "tenant_name", "auth_url", + "no_login", "no_password", "port", "domain", "compute-domain", + "project-domain", "user-domain", "no_shared_storage", + "endpoint_type", "instance_filtering", "insecure", "region_name"] + define_new_opts() + all_opt["shell_timeout"]["default"] = "180" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for the automatic resurrection of OpenStack compute instances" + docs["longdesc"] = "Used to reschedule flagged instances" + docs["vendorurl"] = "" + + show_docs(options, docs) + + run_delay(options) + + # workaround to avoid regressions + if "--compute-domain" in options and options["--compute-domain"]: + options["--domain"] = options["--compute-domain"] + del options["--domain"] + + + # Disable insecure-certificate-warning message + if "--insecure" in options: + import urllib3 + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + connection = create_nova_connection(options) + + # Un-evacuating a server doesn't make sense + if options["--action"] in ["on"]: + logging.error("Action %s is not supported by this agent" % (options["--action"])) + sys.exit(1) + + if options["--action"] in ["off", "reboot"]: + status = get_power_status(connection, options) + if status != "off": + logging.error("Cannot resurrect instances from %s in state '%s'" % (options["--plug"], status)) + sys.exit(1) + + elif not _host_evacuate(connection, options): + logging.error("Resurrection of instances from %s failed" % (options["--plug"])) + sys.exit(1) + + logging.info("Resurrection of instances from %s complete" % (options["--plug"])) + sys.exit(0) + + result = fence_action(connection, options, set_power_status, get_power_status, get_plugs_list, None) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py new file mode 100644 index 0000000..2c815b8 --- /dev/null +++ b/agents/gce/fence_gce.py @@ -0,0 +1,632 @@ +#!@PYTHON@ -tt + +# +# Requires the googleapiclient and oauth2client +# RHEL 7.x: google-api-python-client==1.6.7 python-gflags==2.0 pyasn1==0.4.8 rsa==3.4.2 pysocks==1.7.1 httplib2==0.19.0 +# RHEL 8.x: pysocks==1.7.1 httplib2==0.19.0 +# SLES 12.x: python-google-api-python-client python-oauth2client python-oauth2client-gce pysocks==1.7.1 httplib2==0.19.0 +# SLES 15.x: python3-google-api-python-client python3-oauth2client pysocks==1.7.1 httplib2==0.19.0 +# + +import atexit +import logging +import json +import re +import os +import socket +import sys +import time + +from ssl import SSLError + +if sys.version_info >= (3, 0): + # Python 3 imports. + import urllib.parse as urlparse + import urllib.request as urlrequest +else: + # Python 2 imports. + import urllib as urlparse + import urllib2 as urlrequest +sys.path.append("@FENCEAGENTSLIBDIR@") + +from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action, run_command +try: + import httplib2 + import googleapiclient.discovery + import socks + try: + from google.oauth2.credentials import Credentials as GoogleCredentials + except: + from oauth2client.client import GoogleCredentials +except: + pass + +VERSION = '1.0.5' +ACTION_IDS = { + 'on': 1, 'off': 2, 'reboot': 3, 'status': 4, 'list': 5, 'list-status': 6, + 'monitor': 7, 'metadata': 8, 'manpage': 9, 'validate-all': 10 +} +USER_AGENT = 'sap-core-eng/fencegce/%s/%s/ACTION/%s' +METADATA_SERVER = 'http://metadata.google.internal/computeMetadata/v1/' +METADATA_HEADERS = {'Metadata-Flavor': 'Google'} +INSTANCE_LINK = 'https://www.googleapis.com/compute/v1/projects/{}/zones/{}/instances/{}' + +def run_on_fail(options): + if "--runonfail" in options: + run_command(options, options["--runonfail"]) + +def fail_fence_agent(options, message): + run_on_fail(options) + fail_usage(message) + +def raise_fence_agent(options, message): + run_on_fail(options) + raise Exception(message) + +# +# Will use baremetalsolution setting or the environment variable +# FENCE_GCE_URI_REPLACEMENTS to replace the uri for calls to *.googleapis.com. +# +def replace_api_uri(options, http_request): + uri_replacements = [] + # put any env var replacements first, then baremetalsolution if in options + if "FENCE_GCE_URI_REPLACEMENTS" in os.environ: + logging.debug("FENCE_GCE_URI_REPLACEMENTS environment variable exists") + env_uri_replacements = os.environ["FENCE_GCE_URI_REPLACEMENTS"] + try: + uri_replacements_json = json.loads(env_uri_replacements) + if isinstance(uri_replacements_json, list): + uri_replacements = uri_replacements_json + else: + logging.warning("FENCE_GCE_URI_REPLACEMENTS exists, but is not a JSON List") + except ValueError as e: + logging.warning("FENCE_GCE_URI_REPLACEMENTS exists but is not valid JSON") + if "--baremetalsolution" in options: + uri_replacements.append( + { + "matchlength": 4, + "match": "https://compute.googleapis.com/compute/v1/projects/(.*)/zones/(.*)/instances/(.*)/reset(.*)", + "replace": "https://baremetalsolution.googleapis.com/v1/projects/\\1/locations/\\2/instances/\\3:resetInstance\\4" + }) + for uri_replacement in uri_replacements: + # each uri_replacement should have matchlength, match, and replace + if "matchlength" not in uri_replacement or "match" not in uri_replacement or "replace" not in uri_replacement: + logging.warning("FENCE_GCE_URI_REPLACEMENTS missing matchlength, match, or replace in %s" % uri_replacement) + continue + match = re.match(uri_replacement["match"], http_request.uri) + if match is None or len(match.groups()) != uri_replacement["matchlength"]: + continue + replaced_uri = re.sub(uri_replacement["match"], uri_replacement["replace"], http_request.uri) + match = re.match("https:\/\/.*.googleapis.com", replaced_uri) + if match is None or match.start() != 0: + logging.warning("FENCE_GCE_URI_REPLACEMENTS replace is not " + "targeting googleapis.com, ignoring it: %s" % replaced_uri) + continue + logging.debug("Replacing googleapis uri %s with %s" % (http_request.uri, replaced_uri)) + http_request.uri = replaced_uri + break + return http_request + +def retry_api_execute(options, http_request): + replaced_http_request = replace_api_uri(options, http_request) + action = ACTION_IDS[options["--action"]] if options["--action"] in ACTION_IDS else 0 + try: + user_agent_header = USER_AGENT % (VERSION, options["image"], action) + except ValueError: + user_agent_header = USER_AGENT % (VERSION, options["image"], 0) + replaced_http_request.headers["User-Agent"] = user_agent_header + logging.debug("User agent set as %s" % (user_agent_header)) + retries = 3 + if options.get("--retries"): + retries = int(options.get("--retries")) + retry_sleep = 5 + if options.get("--retrysleep"): + retry_sleep = int(options.get("--retrysleep")) + retry = 0 + current_err = None + while retry <= retries: + if retry > 0: + time.sleep(retry_sleep) + try: + return replaced_http_request.execute() + except Exception as err: + current_err = err + logging.warning("Could not execute api call to: %s, retry: %s, " + "err: %s" % (replaced_http_request.uri, retry, str(err))) + retry += 1 + raise current_err + + +def translate_status(instance_status): + "Returns on | off | unknown." + if instance_status == "RUNNING": + return "on" + elif instance_status == "TERMINATED": + return "off" + return "unknown" + + +def get_nodes_list(conn, options): + result = {} + plug = options["--plug"] if "--plug" in options else "" + zones = options["--zone"] if "--zone" in options else "" + if not zones: + zones = get_zone(conn, options, plug) if "--plugzonemap" not in options else options["--plugzonemap"][plug] + try: + for zone in zones.split(","): + instanceList = retry_api_execute(options, conn.instances().list( + project=options["--project"], + zone=zone)) + for instance in instanceList["items"]: + result[instance["id"]] = (instance["name"], translate_status(instance["status"])) + except Exception as err: + fail_fence_agent(options, "Failed: get_nodes_list: {}".format(str(err))) + + return result + + +def get_power_status(conn, options): + logging.debug("get_power_status") + # if this is bare metal we need to just send back the opposite of the + # requested action: if on send off, if off send on + if "--baremetalsolution" in options: + if options.get("--action") == "on": + return "off" + else: + return "on" + # If zone is not listed for an entry we attempt to get it automatically + instance = options["--plug"] + zone = get_zone(conn, options, instance) if "--plugzonemap" not in options else options["--plugzonemap"][instance] + instance_status = get_instance_power_status(conn, options, instance, zone) + # If any of the instances do not match the intended status we return the + # the opposite status so that the fence agent can change it. + if instance_status != options.get("--action"): + return instance_status + + return options.get("--action") + + +def get_instance_power_status(conn, options, instance, zone): + try: + instance = retry_api_execute( + options, + conn.instances().get(project=options["--project"], zone=zone, instance=instance)) + return translate_status(instance["status"]) + except Exception as err: + fail_fence_agent(options, "Failed: get_instance_power_status: {}".format(str(err))) + + +def check_for_existing_operation(conn, options, instance, zone, operation_type): + logging.debug("check_for_existing_operation") + if "--baremetalsolution" in options: + # There is no API for checking in progress operations + return False + + project = options["--project"] + target_link = INSTANCE_LINK.format(project, zone, instance) + query_filter = '(targetLink = "{}") AND (operationType = "{}") AND (status = "RUNNING")'.format(target_link, operation_type) + result = retry_api_execute( + options, + conn.zoneOperations().list(project=project, zone=zone, filter=query_filter, maxResults=1)) + + if "items" in result and result["items"]: + logging.info("Existing %s operation found", operation_type) + return result["items"][0] + + +def wait_for_operation(conn, options, zone, operation): + if 'name' not in operation: + logging.warning('Cannot wait for operation to complete, the' + ' requested operation will continue asynchronously') + return False + + wait_time = 0 + project = options["--project"] + while True: + result = retry_api_execute(options, conn.zoneOperations().get( + project=project, + zone=zone, + operation=operation['name'])) + if result['status'] == 'DONE': + if 'error' in result: + raise_fence_agent(options, result['error']) + return True + + if "--errortimeout" in options and wait_time > int(options["--errortimeout"]): + raise_fence_agent(options, "Operation did not complete before the timeout.") + + if "--warntimeout" in options and wait_time > int(options["--warntimeout"]): + logging.warning("Operation did not complete before the timeout.") + if "--runonwarn" in options: + run_command(options, options["--runonwarn"]) + return False + + wait_time = wait_time + 1 + time.sleep(1) + + +def set_power_status(conn, options): + logging.debug("set_power_status") + instance = options["--plug"] + # If zone is not listed for an entry we attempt to get it automatically + zone = get_zone(conn, options, instance) if "--plugzonemap" not in options else options["--plugzonemap"][instance] + set_instance_power_status(conn, options, instance, zone, options["--action"]) + + +def set_instance_power_status(conn, options, instance, zone, action): + logging.info("Setting power status of %s in zone %s", instance, zone) + project = options["--project"] + + try: + if action == "off": + logging.info("Issuing poweroff of %s in zone %s", instance, zone) + operation = check_for_existing_operation(conn, options, instance, zone, "stop") + if operation and "--earlyexit" in options: + return + if not operation: + operation = retry_api_execute( + options, + conn.instances().stop(project=project, zone=zone, instance=instance)) + logging.info("Poweroff command completed, waiting for the operation to complete") + if wait_for_operation(conn, options, zone, operation): + logging.info("Poweroff of %s in zone %s complete", instance, zone) + elif action == "on": + logging.info("Issuing poweron of %s in zone %s", instance, zone) + operation = check_for_existing_operation(conn, options, instance, zone, "start") + if operation and "--earlyexit" in options: + return + if not operation: + operation = retry_api_execute( + options, + conn.instances().start(project=project, zone=zone, instance=instance)) + if wait_for_operation(conn, options, zone, operation): + logging.info("Poweron of %s in zone %s complete", instance, zone) + except Exception as err: + fail_fence_agent(options, "Failed: set_instance_power_status: {}".format(str(err))) + +def power_cycle(conn, options): + logging.debug("power_cycle") + instance = options["--plug"] + # If zone is not listed for an entry we attempt to get it automatically + zone = get_zone(conn, options, instance) if "--plugzonemap" not in options else options["--plugzonemap"][instance] + return power_cycle_instance(conn, options, instance, zone) + + +def power_cycle_instance(conn, options, instance, zone): + logging.info("Issuing reset of %s in zone %s", instance, zone) + project = options["--project"] + + try: + operation = check_for_existing_operation(conn, options, instance, zone, "reset") + if operation and "--earlyexit" in options: + return True + if not operation: + operation = retry_api_execute( + options, + conn.instances().reset(project=project, zone=zone, instance=instance)) + logging.info("Reset command sent, waiting for the operation to complete") + if wait_for_operation(conn, options, zone, operation): + logging.info("Reset of %s in zone %s complete", instance, zone) + return True + except Exception as err: + logging.exception("Failed: power_cycle") + raise err + + +def get_zone(conn, options, instance): + logging.debug("get_zone"); + project = options['--project'] + fl = 'name="%s"' % instance + request = replace_api_uri(options, conn.instances().aggregatedList(project=project, filter=fl)) + while request is not None: + response = request.execute() + zones = response.get('items', {}) + for zone in zones.values(): + for inst in zone.get('instances', []): + if inst['name'] == instance: + return inst['zone'].split("/")[-1] + request = replace_api_uri(options, conn.instances().aggregatedList_next( + previous_request=request, previous_response=response)) + raise_fence_agent(options, "Unable to find instance %s" % (instance)) + + +def get_metadata(metadata_key, params=None, timeout=None): + """Performs a GET request with the metadata headers. + + Args: + metadata_key: string, the metadata to perform a GET request on. + params: dictionary, the query parameters in the GET request. + timeout: int, timeout in seconds for metadata requests. + + Returns: + HTTP response from the GET request. + + Raises: + urlerror.HTTPError: raises when the GET request fails. + """ + logging.debug("get_metadata"); + timeout = timeout or 60 + metadata_url = os.path.join(METADATA_SERVER, metadata_key) + params = urlparse.urlencode(params or {}) + url = '%s?%s' % (metadata_url, params) + request = urlrequest.Request(url, headers=METADATA_HEADERS) + request_opener = urlrequest.build_opener(urlrequest.ProxyHandler({})) + return request_opener.open(request, timeout=timeout * 1.1).read().decode("utf-8") + + +def define_new_opts(): + all_opt["zone"] = { + "getopt" : ":", + "longopt" : "zone", + "help" : "--zone=[name] Zone, e.g. us-central1-b", + "shortdesc" : "Zone.", + "required" : "0", + "order" : 2 + } + all_opt["project"] = { + "getopt" : ":", + "longopt" : "project", + "help" : "--project=[name] Project ID", + "shortdesc" : "Project ID.", + "required" : "0", + "order" : 3 + } + all_opt["stackdriver-logging"] = { + "getopt" : "", + "longopt" : "stackdriver-logging", + "help" : "--stackdriver-logging Enable Logging to Stackdriver", + "shortdesc" : "Stackdriver-logging support.", + "longdesc" : "If enabled IP failover logs will be posted to stackdriver logging.", + "required" : "0", + "order" : 4 + } + all_opt["baremetalsolution"] = { + "getopt" : "", + "longopt" : "baremetalsolution", + "help" : "--baremetalsolution Enable on bare metal", + "shortdesc" : "If enabled this is a bare metal offering from google.", + "required" : "0", + "order" : 5 + } + all_opt["apitimeout"] = { + "getopt" : ":", + "type" : "second", + "longopt" : "apitimeout", + "help" : "--apitimeout=[seconds] Timeout to use for API calls", + "shortdesc" : "Timeout in seconds to use for API calls, default is 60.", + "required" : "0", + "default" : 60, + "order" : 6 + } + all_opt["retries"] = { + "getopt" : ":", + "type" : "integer", + "longopt" : "retries", + "help" : "--retries=[retries] Number of retries on failure for API calls", + "shortdesc" : "Number of retries on failure for API calls, default is 3.", + "required" : "0", + "default" : 3, + "order" : 7 + } + all_opt["retrysleep"] = { + "getopt" : ":", + "type" : "second", + "longopt" : "retrysleep", + "help" : "--retrysleep=[seconds] Time to sleep between API retries", + "shortdesc" : "Time to sleep in seconds between API retries, default is 5.", + "required" : "0", + "default" : 5, + "order" : 8 + } + all_opt["serviceaccount"] = { + "getopt" : ":", + "longopt" : "serviceaccount", + "help" : "--serviceaccount=[filename] Service account json file location e.g. serviceaccount=/somedir/service_account.json", + "shortdesc" : "Service Account to use for authentication to the google cloud APIs.", + "required" : "0", + "order" : 9 + } + all_opt["plugzonemap"] = { + "getopt" : ":", + "longopt" : "plugzonemap", + "help" : "--plugzonemap=[plugzonemap] Comma separated zone map when fencing multiple plugs", + "shortdesc" : "Comma separated zone map when fencing multiple plugs.", + "required" : "0", + "order" : 10 + } + all_opt["proxyhost"] = { + "getopt" : ":", + "longopt" : "proxyhost", + "help" : "--proxyhost=[proxy_host] The proxy host to use, if one is needed to access the internet (Example: 10.122.0.33)", + "shortdesc" : "If a proxy is used for internet access, the proxy host should be specified.", + "required" : "0", + "order" : 11 + } + all_opt["proxyport"] = { + "getopt" : ":", + "type" : "integer", + "longopt" : "proxyport", + "help" : "--proxyport=[proxy_port] The proxy port to use, if one is needed to access the internet (Example: 3127)", + "shortdesc" : "If a proxy is used for internet access, the proxy port should be specified.", + "required" : "0", + "order" : 12 + } + all_opt["earlyexit"] = { + "getopt" : "", + "longopt" : "earlyexit", + "help" : "--earlyexit Return early if reset is already in progress", + "shortdesc" : "If an existing reset operation is detected, the fence agent will return before the operation completes with a 0 return code.", + "required" : "0", + "order" : 13 + } + all_opt["warntimeout"] = { + "getopt" : ":", + "type" : "second", + "longopt" : "warntimeout", + "help" : "--warntimeout=[warn_timeout] Timeout seconds before logging a warning and returning a 0 status code", + "shortdesc" : "If the operation is not completed within the timeout, the cluster operations are allowed to continue.", + "required" : "0", + "order" : 14 + } + all_opt["errortimeout"] = { + "getopt" : ":", + "type" : "second", + "longopt" : "errortimeout", + "help" : "--errortimeout=[error_timeout] Timeout seconds before failing and returning a non-zero status code", + "shortdesc" : "If the operation is not completed within the timeout, cluster is notified of the operation failure.", + "required" : "0", + "order" : 15 + } + all_opt["runonwarn"] = { + "getopt" : ":", + "longopt" : "runonwarn", + "help" : "--runonwarn=[run_on_warn] If a timeout occurs and warning is generated, run the supplied command", + "shortdesc" : "If a timeout would occur while running the agent, then the supplied command is run.", + "required" : "0", + "order" : 16 + } + all_opt["runonfail"] = { + "getopt" : ":", + "longopt" : "runonfail", + "help" : "--runonfail=[run_on_fail] If a failure occurs, run the supplied command", + "shortdesc" : "If a failure would occur while running the agent, then the supplied command is run.", + "required" : "0", + "order" : 17 + } + + +def main(): + conn = None + + device_opt = ["port", "no_password", "zone", "project", "stackdriver-logging", + "method", "baremetalsolution", "apitimeout", "retries", "retrysleep", + "serviceaccount", "plugzonemap", "proxyhost", "proxyport", "earlyexit", + "warntimeout", "errortimeout", "runonwarn", "runonfail"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["power_timeout"]["default"] = "60" + all_opt["method"]["default"] = "cycle" + all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for GCE (Google Cloud Engine)" + docs["longdesc"] = "fence_gce is an I/O Fencing agent for GCE (Google Cloud " \ + "Engine). It uses the googleapiclient library to connect to GCE.\n" \ + "googleapiclient can be configured with Google SDK CLI or by " \ + "executing 'gcloud auth application-default login'.\n" \ + "For instructions see: https://cloud.google.com/compute/docs/tutorials/python-guide" + docs["vendorurl"] = "http://cloud.google.com" + show_docs(options, docs) + + run_delay(options) + + # Prepare logging + if options.get('--verbose') is None: + logging.getLogger('googleapiclient').setLevel(logging.ERROR) + logging.getLogger('oauth2client').setLevel(logging.ERROR) + if options.get('--stackdriver-logging') is not None and options.get('--plug'): + try: + import google.cloud.logging.handlers + client = google.cloud.logging.Client() + handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=options['--plug']) + handler.setLevel(logging.INFO) + formatter = logging.Formatter('gcp:stonith "%(message)s"') + handler.setFormatter(formatter) + root_logger = logging.getLogger() + if options.get('--verbose') is None: + root_logger.setLevel(logging.INFO) + root_logger.addHandler(handler) + except ImportError: + logging.error('Couldn\'t import google.cloud.logging, ' + 'disabling Stackdriver-logging support') + + # if apitimeout is defined we set the socket timeout, if not we keep the + # socket default which is 60s + if options.get("--apitimeout"): + socket.setdefaulttimeout(options["--apitimeout"]) + + # Prepare cli + try: + serviceaccount = options.get("--serviceaccount") + if serviceaccount: + scope = ['https://www.googleapis.com/auth/cloud-platform'] + logging.debug("using credentials from service account") + try: + from google.oauth2.service_account import Credentials as ServiceAccountCredentials + credentials = ServiceAccountCredentials.from_service_account_file(filename=serviceaccount, scopes=scope) + except ImportError: + from oauth2client.service_account import ServiceAccountCredentials + credentials = ServiceAccountCredentials.from_json_keyfile_name(serviceaccount, scope) + else: + try: + from googleapiclient import _auth + credentials = _auth.default_credentials(); + except: + credentials = GoogleCredentials.get_application_default() + logging.debug("using application default credentials") + + if options.get("--proxyhost") and options.get("--proxyport"): + proxy_info = httplib2.ProxyInfo( + proxy_type=socks.PROXY_TYPE_HTTP, + proxy_host=options.get("--proxyhost"), + proxy_port=int(options.get("--proxyport"))) + http = credentials.authorize(httplib2.Http(proxy_info=proxy_info)) + conn = googleapiclient.discovery.build( + 'compute', 'v1', http=http, cache_discovery=False) + else: + conn = googleapiclient.discovery.build( + 'compute', 'v1', credentials=credentials, cache_discovery=False) + except SSLError as err: + fail_fence_agent(options, "Failed: Create GCE compute v1 connection: {}\n\nThis might be caused by old versions of httplib2.".format(str(err))) + except Exception as err: + fail_fence_agent(options, "Failed: Create GCE compute v1 connection: {}".format(str(err))) + + # Get project and zone + if not options.get("--project"): + try: + options["--project"] = get_metadata('project/project-id') + except Exception as err: + fail_fence_agent(options, "Failed retrieving GCE project. Please provide --project option: {}".format(str(err))) + + try: + image = get_metadata('instance/image') + options["image"] = image[image.rindex('/')+1:] + except Exception as err: + options["image"] = "unknown" + + if "--baremetalsolution" in options: + options["--zone"] = "none" + + # Populates zone automatically if missing from the command + zones = [] if not "--zone" in options else options["--zone"].split(",") + options["--plugzonemap"] = {} + if "--plug" in options: + for i, instance in enumerate(options["--plug"].split(",")): + if len(zones) == 1: + # If only one zone is specified, use it across all plugs + options["--plugzonemap"][instance] = zones[0] + continue + + if len(zones) - 1 >= i: + # If we have enough zones specified with the --zone flag use the zone at + # the same index as the plug + options["--plugzonemap"][instance] = zones[i] + continue + + try: + # In this case we do not have a zone specified so we attempt to detect it + options["--plugzonemap"][instance] = get_zone(conn, options, instance) + except Exception as err: + fail_fence_agent(options, "Failed retrieving GCE zone. Please provide --zone option: {}".format(str(err))) + + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list, power_cycle) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/hds_cb/fence_hds_cb.py b/agents/hds_cb/fence_hds_cb.py new file mode 100755 index 0000000..375054c --- /dev/null +++ b/agents/hds_cb/fence_hds_cb.py @@ -0,0 +1,132 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## Model Modle/Firmware +## +--------------------+---------------------------+ +## (1) Main application CB2000/A0300-E-6617 +## +##### + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * + +RE_STATUS_LINE = r"^([0-9]+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+).*$" + +def get_power_status(conn, options): + #### Maybe should put a conn.log_expect here to make sure + #### we have properly entered into the main menu + conn.sendline("S") # Enter System Command Mode + conn.log_expect("SVP>", int(options["--shell-timeout"])) + conn.sendline("PC") # Enter partition control + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + result = {} + # Status can now be obtained from the output of the PC + # command. Line looks like the following: + # "P Power Condition LID lamp Mode Auto power on" + # "0 On Normal Off Basic Synchronized" + # "1 On Normal Off Basic Synchronized" + for line in conn.before.splitlines(): + # populate the relevant fields based on regex + partition = re.search(RE_STATUS_LINE, line) + if partition != None: + # find the blade number defined in args + if partition.group(1) == options["--plug"]: + result = partition.group(2).lower() + # We must make sure we go back to the main menu as the + # status is checked before any fencing operations are + # executed. We could in theory save some time by staying in + # the partition control, but the logic is a little cleaner + # this way. + conn.sendline("Q") # Back to system command mode + conn.log_expect("SVP>", int(options["--shell-timeout"])) + conn.sendline("EX") # Back to system console main menu + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + return result + +def set_power_status(conn, options): + action = { + 'on' : "P", + 'off': "F", + 'reboot' : "H", + }[options["--action"]] + + conn.sendline("S") # Enter System Command Mode + conn.log_expect("SVP>", int(options["--shell-timeout"])) + conn.sendline("PC") # Enter partition control + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.sendline("P") # Enter power control menu + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.sendline(action) # Execute action from array above + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.sendline(options["--plug"]) # Select blade number from args + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.sendline("Y") # Confirm action + conn.log_expect("Hit enter key.", int(options["--shell-timeout"])) + conn.sendline("") # Press the any key + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.sendline("Q") # Quit back to partition control + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.sendline("Q") # Quit back to system command mode + conn.log_expect("SVP>", int(options["--shell-timeout"])) + conn.sendline("EX") # Quit back to system console menu + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def get_blades_list(conn, options): + outlets = {} + + conn.sendline("S") # Enter System Command Mode + conn.log_expect("SVP>", int(options["--shell-timeout"])) + conn.sendline("PC") # Enter partition control + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + # Status can now be obtained from the output of the PC + # command. Line looks like the following: + # "P Power Condition LID lamp Mode Auto power on" + # "0 On Normal Off Basic Synchronized" + # "1 On Normal Off Basic Synchronized" + for line in conn.before.splitlines(): + partition = re.search(RE_STATUS_LINE, line) + if partition != None: + outlets[partition.group(1)] = (partition.group(2), "") + conn.sendline("Q") # Quit back to system command mode + conn.log_expect("SVP>", int(options["--shell-timeout"])) + conn.sendline("EX") # Quit back to system console menu + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + return outlets + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "port", "missing_as_off", "telnet"] + + atexit.register(atexit_handler) + + all_opt["power_wait"]["default"] = "5" + all_opt["cmd_prompt"]["default"] = [r"\) :"] + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Hitachi Compute Blade systems" + docs["longdesc"] = "fence_hds_cb is an I/O Fencing agent \ +which can be used with Hitachi Compute Blades with recent enough firmware that \ +includes telnet support." + docs["vendorurl"] = "http://www.hds.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + ###### + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list) + + fence_logout(conn, "X") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/heuristics_ping/fence_heuristics_ping.py b/agents/heuristics_ping/fence_heuristics_ping.py new file mode 100644 index 0000000..5b2c61d --- /dev/null +++ b/agents/heuristics_ping/fence_heuristics_ping.py @@ -0,0 +1,198 @@ +#!@PYTHON@ -tt + +# The Following Agent Has Been Tested On: +# +# RHEL 7.4 +# + +import io +import re +import subprocess +import shlex +import sys, stat +import logging +import os +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import fail_usage, run_command, fence_action, all_opt +from fencing import atexit_handler, check_input, process_input, show_docs +from fencing import run_delay + +def ping_test(con, options): + # Send pings to the targets + + if options["--action"] == "on": + # we want unfencing to always succeed + return True + + if not "--ping-targets" in options or options["--ping-targets"] == "": + # "off" was requested so fake "on" to provoke failure + logging.error("ping target required") + return False + + timeout = int(options["--ping-timeout"]) + count = int(options["--ping-count"]) + interval = int(options["--ping-interval"]) + good_required = int(options["--ping-good-count"]) + maxfail = int(options["--ping-maxfail"]) + targets = options["--ping-targets"].split(",") + exitcode = True + p = {} + failcount = 0 + # search string for parsing the results of the ping-executable + packet_count = re.compile(r".*transmitted, ([0-9]*)( packets)? received.*") + + # start a ping-process per target + for target in targets: + ping_path = '@PING_CMD@' + target_mangled = target + if target.startswith('inet6:'): + if '@PING6_CMD@' == '': + p[target] = None + continue + ping_path = '@PING6_CMD@' + target_mangled = target.split(':',2)[1] + elif target.startswith('inet:'): + ping_path = '@PING4_CMD@' + target_mangled = target.split(':',2)[1] + + ping_cmd = "%s -n -q -W %d -c %d -i %d %s" % ( + ping_path, timeout, count, interval, target_mangled) + logging.info("Running command: %s", ping_cmd) + try: + p[target] = subprocess.Popen(shlex.split(ping_cmd), + stdout=subprocess.PIPE); + except OSError: + p[target] = None + + # collect the results of the ping-processes + for target in targets: + good = 0 + if p[target] != None: + p[target].wait() + if p[target].returncode == 0: + for line in p[target].stdout: + searchres = packet_count.search(line.decode()) + if searchres: + good = int(searchres.group(1)) + break + if good >= good_required: + logging.info("ping target %s received %d of %d" \ + % (target, good, count)) + continue + failcount += 1 + logging.info("ping target %s received %d of %d and thus failed" + % (target, good, count)) + else: + failcount += 1 + logging.error("ping target %s failed on OS level" % target) + + if failcount > maxfail: + exitcode = False + + return exitcode + + +def define_new_opts(): + all_opt["ping_count"] = { + "getopt" : ":", + "longopt" : "ping-count", + "required" : "0", + "help" : "--ping-count=[number] Number of ping-probes to send", + "shortdesc" : "The number of ping-probes that is being sent per target", + "default" : "10", + "order" : 1 + } + + all_opt["ping_good_count"] = { + "getopt" : ":", + "longopt" : "ping-good-count", + "required" : "0", + "help" : "--ping-good-count=[number] Number of positive ping-probes required", + "shortdesc" : "The number of positive ping-probes required to account a target as available", + "default" : "8", + "order" : 1 + } + + all_opt["ping_interval"] = { + "getopt" : ":", + "longopt" : "ping-interval", + "required" : "0", + "help" : "--ping-interval=[seconds] Seconds between ping-probes", + "shortdesc" : "The interval in seconds between ping-probes", + "default" : "1", + "order" : 1 + } + + all_opt["ping_timeout"] = { + "getopt" : ":", + "longopt" : "ping-timeout", + "required" : "0", + "help" : "--ping-timeout=[seconds] Timeout for individual ping-probes", + "shortdesc" : "The timeout in seconds till an individual ping-probe is accounted as lost", + "default" : "2", + "order" : 1 + } + + all_opt["ping_maxfail"] = { + "getopt" : ":", + "longopt" : "ping-maxfail", + "required" : "0", + "help" : "--ping-maxfail=[number] Number of failed ping-targets allowed", + "shortdesc" : "The number of failed ping-targets to still account as overall success", + "default" : "0", + "order" : 1 + } + + all_opt["ping_targets"] = { + "getopt" : ":", + "longopt" : "ping-targets", + "required" : "1", + "help" : "--ping-targets=tgt1,[inet6:]tgt2 Comma separated list of ping-targets", + "shortdesc" : "A comma separated list of ping-targets (optionally prepended by 'inet:' or 'inet6:') to be probed", + "default" : "", + "order" : 1 + } + + +def main(): + device_opt = ["no_status", "no_password", "ping_count", "ping_good_count", + "ping_interval", "ping_timeout", "ping_maxfail", "ping_targets", "method"] + define_new_opts() + atexit.register(atexit_handler) + + all_opt["method"]["default"] = "cycle" + all_opt["method"]["help"] = "-m, --method=[method] Method to fence (cycle|onoff) (Default: cycle)" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for ping-heuristic based fencing" + docs["longdesc"] = "fence_heuristics_ping uses ping-heuristics to control execution of another fence agent on the same fencing level.\ +\n.P\n\ +This is not a fence agent by itself! \ +Its only purpose is to enable/disable another fence agent that lives on the same fencing level but after fence_heuristics_ping." + docs["vendorurl"] = "" + show_docs(options, docs) + + # move ping-test to the end of the time-window set via --delay + # as to give the network time to settle after the incident that has + # caused fencing and have the results as current as possible + max_pingcheck = (int(options["--ping-count"]) - 1) * \ + int(options["--ping-interval"]) + int(options["--ping-timeout"]) + run_delay(options, reserve=max_pingcheck) + + result = fence_action(\ + None, \ + options, \ + None, \ + None, \ + reboot_cycle_fn = ping_test, + sync_set_power_fn = ping_test) + + # execute the remaining delay + run_delay(options, result=result) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/hpblade/fence_hpblade.py b/agents/hpblade/fence_hpblade.py new file mode 100644 index 0000000..fbc89f6 --- /dev/null +++ b/agents/hpblade/fence_hpblade.py @@ -0,0 +1,134 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## * HP BladeSystem c7000 Enclosure +## * HP Integrity Superdome X (BL920s) +##### + +import sys, re +import pexpect +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS + +def get_enclosure_type(conn, options): + conn.send_eol("show enclosure info") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + type_re=re.compile(r"^\s*Enclosure Type: (\w+)(.*?)\s*$") + enclosure="unknown" + for line in conn.before.splitlines(): + res = type_re.search(line) + if res != None: + enclosure=res.group(1) + + if enclosure == "unknown": + fail(EC_GENERIC_ERROR) + + return enclosure.lower().strip() + +def get_power_status(conn, options): + if options["enc_type"] == "superdome": + cmd_send = "parstatus -M -p " + options["--plug"] + powrestr = "^partition:\\d\\s+:\\w+\\s+/(\\w+)\\s.*$" + else: + cmd_send = "show server status " + options["--plug"] + powrestr = "^\\s*Power: (.*?)\\s*$" + + conn.send_eol(cmd_send) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + power_re = re.compile(powrestr) + status = "unknown" + for line in conn.before.splitlines(): + res = power_re.search(line) + if res != None: + if options["enc_type"] == "superdome": + if res.group(1) == "DOWN": + status = "off" + else: + status = "on" + else: + status = res.group(1) + + if status == "unknown": + if "--missing-as-off" in options: + return "off" + else: + fail(EC_STATUS) + + return status.lower().strip() + +def set_power_status(conn, options): + if options["enc_type"] == "superdome": + dev="partition " + else: + dev="server " + + if options["--action"] == "on": + conn.send_eol("poweron " + dev + options["--plug"]) + elif options["--action"] == "off": + conn.send_eol("poweroff " + dev + options["--plug"] + " force") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def get_instances_list(conn, options): + outlets = {} + if options["enc_type"] == "superdome": + cmd_send = "parstatus -P -M" + listrestr = "^partition:(\\d+)\\s+:\\w+\\s+/(\\w+)\\s+:OK.*?:(\\w+)\\s*$" + else: + cmd_send = "show server list" + listrestr = "^\\s*(\\d+)\\s+(.*?)\\s+(.*?)\\s+OK\\s+(.*?)\\s+(.*?)\\s*$" + + conn.send_eol(cmd_send) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + list_re = re.compile(listrestr) + for line in conn.before.splitlines(): + res = list_re.search(line) + if res != None: + if options["enc_type"] == "superdome": + outlets[res.group(1)] = (res.group(3), res.group(2).lower()) + else: + outlets[res.group(1)] = (res.group(2), res.group(4).lower()) + + return outlets + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ + "port", "missing_as_off", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["c7000oa>"] + all_opt["login_timeout"]["default"] = "10" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for HP BladeSystem" + docs["longdesc"] = "fence_hpblade is an I/O Fencing agent \ +which can be used with HP BladeSystem and HP Integrity Superdome X. \ +It logs into the onboard administrator of an enclosure via telnet or \ +ssh and uses the command line interface to power blades or partitions \ +on or off." + docs["vendorurl"] = "http://www.hp.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + ###### + options["eol"] = "\n" + conn = fence_login(options) + + options["enc_type"] = get_enclosure_type(conn, options) + + result = fence_action(conn, options, set_power_status, get_power_status, get_instances_list) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ibm_powervs/fence_ibm_powervs.py b/agents/ibm_powervs/fence_ibm_powervs.py new file mode 100755 index 0000000..1838936 --- /dev/null +++ b/agents/ibm_powervs/fence_ibm_powervs.py @@ -0,0 +1,267 @@ +#!@PYTHON@ -tt + +import sys +import pycurl, io, json +import logging +import atexit +import time +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS + +state = { + "ACTIVE": "on", + "SHUTOFF": "off", + "ERROR": "unknown" +} + +def get_token(conn, options): + try: + command = "identity/token" + action = "grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey={}".format(options["--token"]) + res = send_command(conn, command, "POST", action, printResult=False) + except Exception as e: + logging.debug("Failed: {}".format(e)) + return "TOKEN_IS_MISSING_OR_WRONG" + + return res["access_token"] + +def get_list(conn, options): + outlets = {} + + try: + command = "cloud-instances/{}/pvm-instances".format(options["--instance"]) + res = send_command(conn, command) + except Exception as e: + logging.debug("Failed: {}".format(e)) + return outlets + + for r in res["pvmInstances"]: + if "--verbose" in options: + logging.debug(json.dumps(r, indent=2)) + outlets[r["pvmInstanceID"]] = (r["serverName"], state[r["status"]]) + + return outlets + +def get_power_status(conn, options): + try: + command = "cloud-instances/{}/pvm-instances/{}".format( + options["--instance"], options["--plug"]) + res = send_command(conn, command) + result = get_list(conn, options)[options["--plug"]][1] + except KeyError as e: + logging.debug("Failed: Unable to get status for {}".format(e)) + fail(EC_STATUS) + + return result + +def set_power_status(conn, options): + action = { + "on" : '{"action" : "start"}', + "off" : '{"action" : "immediate-shutdown"}', + }[options["--action"]] + + try: + send_command(conn, "cloud-instances/{}/pvm-instances/{}/action".format( + options["--instance"], options["--plug"]), "POST", action) + except Exception as e: + logging.debug("Failed: Unable to set power to {} for {}".format(options["--action"], e)) + fail(EC_STATUS) + +def connect(opt, token): + conn = pycurl.Curl() + + ## setup correct URL + conn.base_url = "https://" + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" + if opt["--api-type"] == "private": + conn.base_url = "https://private." + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" + + if opt["--verbose-level"] < 3: + conn.setopt(pycurl.VERBOSE, 0) + + conn.setopt(pycurl.CONNECTTIMEOUT,int(opt["--shell-timeout"])) + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + conn.setopt(pycurl.PROXY, "{}".format(opt["--proxy"])) + + # set auth token for later requests + conn.setopt(pycurl.HTTPHEADER, [ + "Content-Type: application/json", + "Authorization: Bearer {}".format(token), + "CRN: {}".format(opt["--crn"]), + "User-Agent: curl", + ]) + + return conn + +def auth_connect(opt): + conn = pycurl.Curl() + + # setup correct URL + conn.base_url = "https://iam.cloud.ibm.com/" + + if opt["--verbose-level"] > 1: + conn.setopt(pycurl.VERBOSE, 1) + + conn.setopt(pycurl.CONNECTTIMEOUT,int(opt["--shell-timeout"])) + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + conn.setopt(pycurl.PROXY, "{}".format(opt["--proxy"])) + + # set auth token for later requests + conn.setopt(pycurl.HTTPHEADER, [ + "Content-type: application/x-www-form-urlencoded", + "Accept: application/json", + "User-Agent: curl", + ]) + + return conn + +def disconnect(conn): + conn.close() + +def send_command(conn, command, method="GET", action=None, printResult=True): + url = conn.base_url + command + + conn.setopt(pycurl.URL, url.encode("ascii")) + + web_buffer = io.BytesIO() + + if method == "GET": + conn.setopt(pycurl.POST, 0) + if method == "POST": + conn.setopt(pycurl.POSTFIELDS, action) + if method == "DELETE": + conn.setopt(pycurl.CUSTOMREQUEST, "DELETE") + + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + + try: + conn.perform() + except Exception as e: + logging.error("send_command(): {}".format(e)) + raise(e) + + rc = conn.getinfo(pycurl.HTTP_CODE) + result = web_buffer.getvalue().decode("UTF-8") + + web_buffer.close() + + if rc != 200: + if len(result) > 0: + raise Exception("{}: {}".format(rc,result)) + else: + raise Exception("Remote returned {} for request to {}".format(rc, url)) + + if len(result) > 0: + result = json.loads(result) + + logging.debug("url: {}".format(url)) + logging.debug("method: {}".format(method)) + logging.debug("response code: {}".format(rc)) + if printResult: + logging.debug("result: {}\n".format(result)) + + return result + +def define_new_opts(): + all_opt["token"] = { + "getopt" : ":", + "longopt" : "token", + "help" : "--token=[token] API Token", + "required" : "1", + "shortdesc" : "API Token", + "order" : 0 + } + all_opt["crn"] = { + "getopt" : ":", + "longopt" : "crn", + "help" : "--crn=[crn] CRN", + "required" : "1", + "shortdesc" : "CRN", + "order" : 0 + } + all_opt["instance"] = { + "getopt" : ":", + "longopt" : "instance", + "help" : "--instance=[instance] PowerVS Instance", + "required" : "1", + "shortdesc" : "PowerVS Instance", + "order" : 0 + } + all_opt["region"] = { + "getopt" : ":", + "longopt" : "region", + "help" : "--region=[region] Region", + "required" : "1", + "shortdesc" : "Region", + "order" : 0 + } + all_opt["api-type"] = { + "getopt" : ":", + "longopt" : "api-type", + "help" : "--api-type=[public|private] API-type: 'public' (default) or 'private'", + "required" : "0", + "shortdesc" : "API-type (public|private)", + "order" : 0 + } + all_opt["proxy"] = { + "getopt" : ":", + "longopt" : "proxy", + "help" : "--proxy=[http://<URL>:<PORT>] Proxy: 'http://<URL>:<PORT>'", + "required" : "0", + "shortdesc" : "Network proxy", + "order" : 0 + } + + +def main(): + device_opt = [ + "token", + "crn", + "instance", + "region", + "api-type", + "proxy", + "port", + "no_password", + ] + + atexit.register(atexit_handler) + define_new_opts() + + all_opt["shell_timeout"]["default"] = "500" + all_opt["power_timeout"]["default"] = "30" + all_opt["power_wait"]["default"] = "1" + all_opt["stonith_status_sleep"]["default"] = "2" + all_opt["api-type"]["default"] = "private" + all_opt["proxy"]["default"] = "" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for IBM PowerVS" + docs["longdesc"] = """fence_ibm_powervs is an I/O Fencing agent which can be \ +used with IBM PowerVS to fence virtual machines.""" + docs["vendorurl"] = "https://www.ibm.com" + show_docs(options, docs) + + #### + ## Fence operations + #### + run_delay(options) + + auth_conn = auth_connect(options) + token = get_token(auth_conn, options) + disconnect(auth_conn) + conn = connect(options, token) + atexit.register(disconnect, conn) + + result = fence_action(conn, options, set_power_status, get_power_status, get_list) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ibm_vpc/fence_ibm_vpc.py b/agents/ibm_vpc/fence_ibm_vpc.py new file mode 100755 index 0000000..8470105 --- /dev/null +++ b/agents/ibm_vpc/fence_ibm_vpc.py @@ -0,0 +1,316 @@ +#!@PYTHON@ -tt + +import sys +import pycurl, io, json +import logging +import atexit +import hashlib +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS, EC_GENERIC_ERROR + +state = { + "running": "on", + "stopped": "off", + "starting": "unknown", + "stopping": "unknown", + "restarting": "unknown", + "pending": "unknown", +} + +def get_list(conn, options): + outlets = {} + + try: + command = "instances?version=2021-05-25&generation=2&limit={}".format(options["--limit"]) + res = send_command(conn, options, command) + except Exception as e: + logging.debug("Failed: Unable to get list: {}".format(e)) + return outlets + + for r in res["instances"]: + if options["--verbose-level"] > 1: + logging.debug("Node:\n{}".format(json.dumps(r, indent=2))) + logging.debug("Status: " + state[r["status"]]) + outlets[r["id"]] = (r["name"], state[r["status"]]) + + return outlets + +def get_power_status(conn, options): + try: + command = "instances/{}?version=2021-05-25&generation=2".format(options["--plug"]) + res = send_command(conn, options, command) + result = state[res["status"]] + if options["--verbose-level"] > 1: + logging.debug("Result:\n{}".format(json.dumps(res, indent=2))) + logging.debug("Status: " + result) + except Exception as e: + logging.debug("Failed: Unable to get status for {}: {}".format(options["--plug"], e)) + fail(EC_STATUS) + + return result + +def set_power_status(conn, options): + action = { + "on" : '{"type" : "start"}', + "off" : '{"type" : "stop"}', + }[options["--action"]] + + try: + command = "instances/{}/actions?version=2021-05-25&generation=2".format(options["--plug"]) + send_command(conn, options, command, "POST", action, 201) + except Exception as e: + logging.debug("Failed: Unable to set power to {} for {}".format(options["--action"], e)) + fail(EC_STATUS) + +def get_bearer_token(conn, options): + import os, errno + + try: + # FIPS requires usedforsecurity=False and might not be + # available on all distros: https://bugs.python.org/issue9216 + hash = hashlib.sha256(options["--apikey"].encode("utf-8"), usedforsecurity=False).hexdigest() + except (AttributeError, TypeError): + hash = hashlib.sha256(options["--apikey"].encode("utf-8")).hexdigest() + file_path = options["--token-file"].replace("[hash]", hash) + token = None + + if not os.path.isdir(os.path.dirname(file_path)): + os.makedirs(os.path.dirname(file_path)) + + # For security, remove file with potentially elevated mode + try: + os.remove(file_path) + except OSError: + pass + + try: + oldumask = os.umask(0) + file_handle = os.open(file_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600) + except OSError as e: + if e.errno == errno.EEXIST: # Failed as the file already exists. + logging.error("Failed: File already exists: {}".format(e)) + sys.exit(EC_GENERIC_ERROR) + else: # Something unexpected went wrong + logging.error("Failed: Unable to open file: {}".format(e)) + sys.exit(EC_GENERIC_ERROR) + else: # No exception, so the file must have been created successfully. + with os.fdopen(file_handle, 'w') as file_obj: + try: + conn.setopt(pycurl.HTTPHEADER, [ + "Content-Type: application/x-www-form-urlencoded", + "User-Agent: curl", + ]) + token = send_command(conn, options, "https://iam.cloud.ibm.com/identity/token", "POST", "grant_type=urn:ibm:params:oauth:grant-type:apikey&apikey={}".format(options["--apikey"]))["access_token"] + except Exception as e: + logging.error("Failed: Unable to authenticate: {}".format(e)) + fail(EC_LOGIN_DENIED) + file_obj.write(token) + finally: + os.umask(oldumask) + + return token + +def set_bearer_token(conn, bearer_token): + conn.setopt(pycurl.HTTPHEADER, [ + "Content-Type: application/json", + "Authorization: Bearer {}".format(bearer_token), + "User-Agent: curl", + ]) + + return conn + +def connect(opt): + conn = pycurl.Curl() + bearer_token = "" + + ## setup correct URL + conn.base_url = "https://" + opt["--region"] + ".iaas.cloud.ibm.com/v1/" + + if opt["--verbose-level"] > 1: + conn.setopt(pycurl.VERBOSE, 1) + + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + conn.setopt(pycurl.PROXY, "{}".format(opt["--proxy"])) + + # get bearer token + try: + try: + # FIPS requires usedforsecurity=False and might not be + # available on all distros: https://bugs.python.org/issue9216 + hash = hashlib.sha256(opt["--apikey"].encode("utf-8"), usedforsecurity=False).hexdigest() + except (AttributeError, TypeError): + hash = hashlib.sha256(opt["--apikey"].encode("utf-8")).hexdigest() + f = open(opt["--token-file"].replace("[hash]", hash)) + bearer_token = f.read() + f.close() + except IOError: + bearer_token = get_bearer_token(conn, opt) + + # set auth token for later requests + conn = set_bearer_token(conn, bearer_token) + + return conn + +def disconnect(conn): + conn.close() + +def send_command(conn, options, command, method="GET", action=None, expected_rc=200): + if not command.startswith("https"): + url = conn.base_url + command + else: + url = command + + conn.setopt(pycurl.URL, url.encode("ascii")) + + web_buffer = io.BytesIO() + + if method == "GET": + conn.setopt(pycurl.POST, 0) + if method == "POST": + conn.setopt(pycurl.POSTFIELDS, action) + if method == "DELETE": + conn.setopt(pycurl.CUSTOMREQUEST, "DELETE") + + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + + try: + conn.perform() + except Exception as e: + raise(e) + + rc = conn.getinfo(pycurl.HTTP_CODE) + + # auth if token has expired + if rc in [400, 401, 415]: + tokenconn = pycurl.Curl() + token = get_bearer_token(tokenconn, options) + tokenconn.close() + conn = set_bearer_token(conn, token) + + # flush web_buffer + web_buffer.close() + web_buffer = io.BytesIO() + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + + try: + conn.perform() + except Exception as e: + raise(e) + + rc = conn.getinfo(pycurl.HTTP_CODE) + + result = web_buffer.getvalue().decode("UTF-8") + + web_buffer.close() + + # actions (start/stop/reboot) report 201 when they've been created + if rc != expected_rc: + logging.debug("rc: {}, result: {}".format(rc, result)) + if len(result) > 0: + raise Exception("{}: {}".format(rc, + result["value"]["messages"][0]["default_message"])) + else: + raise Exception("Remote returned {} for request to {}".format(rc, url)) + + if len(result) > 0: + result = json.loads(result) + + logging.debug("url: {}".format(url)) + logging.debug("method: {}".format(method)) + logging.debug("response code: {}".format(rc)) + logging.debug("result: {}\n".format(result)) + + return result + +def define_new_opts(): + all_opt["apikey"] = { + "getopt" : ":", + "longopt" : "apikey", + "help" : "--apikey=[key] API Key", + "required" : "1", + "shortdesc" : "API Key", + "order" : 0 + } + all_opt["region"] = { + "getopt" : ":", + "longopt" : "region", + "help" : "--region=[region] Region", + "required" : "1", + "shortdesc" : "Region", + "order" : 0 + } + all_opt["proxy"] = { + "getopt" : ":", + "longopt" : "proxy", + "help" : "--proxy=[http://<URL>:<PORT>] Proxy: 'http://<URL>:<PORT>'", + "required" : "0", + "default": "", + "shortdesc" : "Network proxy", + "order" : 0 + } + all_opt["limit"] = { + "getopt" : ":", + "longopt" : "limit", + "help" : "--limit=[number] Limit number of nodes returned by API", + "required" : "0", + "default": 50, + "shortdesc" : "Number of nodes returned by API", + "order" : 0 + } + all_opt["token_file"] = { + "getopt" : ":", + "longopt" : "token-file", + "help" : "--token-file=[path] Path to the token cache file\n" + "\t\t\t\t (Default: @FENCETMPDIR@/fence_ibm_vpc/[hash].token)\n" + "\t\t\t\t [hash] will be replaced by a hashed value", + "required" : "0", + "default": "@FENCETMPDIR@/fence_ibm_vpc/[hash].token", + "shortdesc" : "Path to the token cache file", + "order" : 0 + } + + +def main(): + device_opt = [ + "apikey", + "region", + "proxy", + "limit", + "token_file", + "port", + "no_password", + ] + + atexit.register(atexit_handler) + define_new_opts() + + all_opt["shell_timeout"]["default"] = "15" + all_opt["power_timeout"]["default"] = "30" + all_opt["power_wait"]["default"] = "1" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for IBM Cloud VPC" + docs["longdesc"] = """fence_ibm_vpc is an I/O Fencing agent which can be \ +used with IBM Cloud VPC to fence virtual machines.""" + docs["vendorurl"] = "https://www.ibm.com" + show_docs(options, docs) + + #### + ## Fence operations + #### + run_delay(options) + + conn = connect(options) + atexit.register(disconnect, conn) + + result = fence_action(conn, options, set_power_status, get_power_status, get_list) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ibmblade/fence_ibmblade.py b/agents/ibmblade/fence_ibmblade.py new file mode 100644 index 0000000..d623fff --- /dev/null +++ b/agents/ibmblade/fence_ibmblade.py @@ -0,0 +1,72 @@ +#!@PYTHON@ -tt + +import sys +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing_snmp import FencingSnmp + +### CONSTANTS ### +# From fence_ibmblade.pl +STATUSES_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.4" # remoteControlBladePowerState +CONTROL_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7" # powerOnOffBlade + +# Status constants returned as value from SNMP +STATUS_DOWN = 0 +STATUS_UP = 1 + +# Status constants to set as value to SNMP +STATUS_SET_OFF = 0 +STATUS_SET_ON = 1 + +### FUNCTIONS ### + +def get_power_status(conn, options): + (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) + return status == str(STATUS_UP) and "on" or "off" + +def set_power_status(conn, options): + conn.set("%s.%s" % (CONTROL_OID, options["--plug"]), + (options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF)) + +def get_outlets_status(conn, _): + result = {} + + res_blades = conn.walk(STATUSES_OID, 30) + + for blade_info in res_blades: + port_num = blade_info[0].split('.')[-1] + + port_alias = "" + port_status = (blade_info[1] == str(STATUS_UP) and "on" or "off") + + result[port_num] = (port_alias, port_status) + + return result + +# Main agent method +def main(): + device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ + "port", "snmp_version", "snmp"] + + atexit.register(atexit_handler) + + all_opt["snmp_version"]["default"] = "1" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for IBM BladeCenter over SNMP" + docs["longdesc"] = "fence_ibmblade is an I/O Fencing agent \ +which can be used with IBM BladeCenter chassis. It issues SNMP Set \ +request to BladeCenter chassis, rebooting, powering up or down \ +the specified Blade Server." + docs["vendorurl"] = "http://www.ibm.com" + show_docs(options, docs) + + # Operate the fencing device + result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) +if __name__ == "__main__": + main() diff --git a/agents/ibmz/fence_ibmz.py b/agents/ibmz/fence_ibmz.py new file mode 100644 index 0000000..d477ade --- /dev/null +++ b/agents/ibmz/fence_ibmz.py @@ -0,0 +1,566 @@ +#!@PYTHON@ -tt + +# Copyright (c) 2020 IBM Corp. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see +# <http://www.gnu.org/licenses/>. + +import atexit +import logging +import time +import sys + +import requests +from requests.packages import urllib3 + +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, run_delay, EC_GENERIC_ERROR + +DEFAULT_POWER_TIMEOUT = '300' +ERROR_NOT_FOUND = ("{obj_type} {obj_name} not found in this HMC. " + "Attention: names are case-sensitive.") + +class ApiClientError(Exception): + """ + Base exception for all API Client related errors. + """ + +class ApiClientRequestError(ApiClientError): + """ + Raised when an API request ends in error + """ + + def __init__(self, req_method, req_uri, status, reason, message): + self.req_method = req_method + self.req_uri = req_uri + self.status = status + self.reason = reason + self.message = message + super(ApiClientRequestError, self).__init__() + + def __str__(self): + return ( + "API request failed, details:\n" + "HTTP Request : {req_method} {req_uri}\n" + "HTTP Response status: {status}\n" + "Error reason: {reason}\n" + "Error message: {message}\n".format( + req_method=self.req_method, req_uri=self.req_uri, + status=self.status, reason=self.reason, message=self.message) + ) + +class APIClient(object): + DEFAULT_CONFIG = { + # how many connection-related errors to retry on + 'connect_retries': 3, + # how many times to retry on read errors (after request was sent to the + # server) + 'read_retries': 3, + # http methods that should be retried + 'method_whitelist': ['HEAD', 'GET', 'OPTIONS'], + # limit of redirects to perform to avoid loops + 'redirect': 5, + # how long to wait while establishing a connection + 'connect_timeout': 30, + # how long to wait for asynchronous operations (jobs) to complete + 'operation_timeout': 900, + # how long to wait between bytes sent by the remote side + 'read_timeout': 300, + # default API port + 'port': 6794, + # validate ssl certificates + 'ssl_verify': False, + # load on activate is set in the HMC activation profile and therefore + # no additional load is executed by the fence agent + 'load_on_activate': False + } + LABEL_BY_OP_MODE = { + 'classic': { + 'nodes': 'logical-partitions', + 'state-on': 'operating', + 'start': 'load', + 'stop': 'deactivate' + }, + 'dpm': { + 'nodes': 'partitions', + 'state-on': 'active', + 'start': 'start', + 'stop': 'stop' + } + } + def __init__(self, host, user, passwd, config=None): + self.host = host + if not passwd: + raise ValueError('Password cannot be empty') + self.passwd = passwd + if not user: + raise ValueError('Username cannot be empty') + self.user = user + self._cpc_cache = {} + self._session = None + self._config = self.DEFAULT_CONFIG.copy() + # apply user defined values + if config: + self._config.update(config) + + def _create_session(self): + """ + Create a new requests session and apply config values + """ + session = requests.Session() + retry_obj = urllib3.Retry( + # setting a total is necessary to cover SSL related errors + total=max(self._config['connect_retries'], + self._config['read_retries']), + connect=self._config['connect_retries'], + read=self._config['read_retries'], + method_whitelist=self._config['method_whitelist'], + redirect=self._config['redirect'] + ) + session.mount('http://', requests.adapters.HTTPAdapter( + max_retries=retry_obj)) + session.mount('https://', requests.adapters.HTTPAdapter( + max_retries=retry_obj)) + return session + + def _get_mode_labels(self, cpc): + """ + Return the map of labels that corresponds to the cpc operation mode + """ + if self.is_dpm_enabled(cpc): + return self.LABEL_BY_OP_MODE['dpm'] + return self.LABEL_BY_OP_MODE['classic'] + + def _get_partition(self, cpc, partition): + """ + Return the properties of the specified partition. Raises ValueError if + it cannot be found. + """ + # HMC API's documentation says it'll return an empty array when no + # matches are found but for a CPC in classic mode it returns in fact + # 404, so we handle this accordingly. Remove the extra handling below + # once this behavior has been fixed on the API's side. + label_map = self._get_mode_labels(cpc) + resp = self._request('get', '{}/{}?name={}'.format( + self._cpc_cache[cpc]['object-uri'], label_map['nodes'], partition), + valid_codes=[200, 404]) + + if label_map['nodes'] not in resp or not resp[label_map['nodes']]: + raise ValueError(ERROR_NOT_FOUND.format( + obj_type='LPAR/Partition', obj_name=partition)) + return resp[label_map['nodes']][0] + + def _partition_switch_power(self, cpc, partition, action): + """ + Perform the API request to start (power on) or stop (power off) the + target partition and wait for the job to finish. + """ + # retrieve partition's uri + part_uri = self._get_partition(cpc, partition)['object-uri'] + label_map = self._get_mode_labels(cpc) + + # in dpm mode the request must have empty body + if self.is_dpm_enabled(cpc): + body = None + # in classic mode we make sure the operation is executed + # even if the partition is already on + else: + body = {'force': True} + # when powering on the partition must be activated first + if action == 'start': + op_uri = '{}/operations/activate'.format(part_uri) + job_resp = self._request( + 'post', op_uri, body=body, valid_codes=[202]) + # always wait for activate otherwise the load (start) + # operation will fail + if self._config['operation_timeout'] == 0: + timeout = self.DEFAULT_CONFIG['operation_timeout'] + else: + timeout = self._config['operation_timeout'] + logging.debug( + 'waiting for activate (timeout %s secs)', timeout) + self._wait_for_job('post', op_uri, job_resp['job-uri'], + timeout=timeout) + if self._config['load_on_activate']: + return + + # trigger the start job + op_uri = '{}/operations/{}'.format(part_uri, label_map[action]) + job_resp = self._request('post', op_uri, body=body, valid_codes=[202]) + if self._config['operation_timeout'] == 0: + return + logging.debug('waiting for %s (timeout %s secs)', + label_map[action], self._config['operation_timeout']) + self._wait_for_job('post', op_uri, job_resp['job-uri'], + timeout=self._config['operation_timeout']) + + def _request(self, method, uri, body=None, headers=None, valid_codes=None): + """ + Perform a request to the HMC API + """ + assert method in ('delete', 'head', 'get', 'post', 'put') + + url = 'https://{host}:{port}{uri}'.format( + host=self.host, port=self._config['port'], uri=uri) + if not headers: + headers = {} + + if self._session is None: + raise ValueError('You need to log on first') + method = getattr(self._session, method) + timeout = ( + self._config['connect_timeout'], self._config['read_timeout']) + response = method(url, json=body, headers=headers, + verify=self._config['ssl_verify'], timeout=timeout) + + if valid_codes and response.status_code not in valid_codes: + reason = '(no reason)' + message = '(no message)' + if response.headers.get('content-type') == 'application/json': + try: + json_resp = response.json() + except ValueError: + pass + else: + reason = json_resp.get('reason', reason) + message = json_resp.get('message', message) + else: + message = '{}...'.format(response.text[:500]) + raise ApiClientRequestError( + response.request.method, response.request.url, + response.status_code, reason, message) + + if response.status_code == 204: + return dict() + try: + json_resp = response.json() + except ValueError: + raise ApiClientRequestError( + response.request.method, response.request.url, + response.status_code, '(no reason)', + 'Invalid JSON content in response') + + return json_resp + + def _update_cpc_cache(self, cpc_props): + self._cpc_cache[cpc_props['name']] = { + 'object-uri': cpc_props['object-uri'], + 'dpm-enabled': cpc_props.get('dpm-enabled', False) + } + + def _wait_for_job(self, req_method, req_uri, job_uri, timeout): + """ + Perform API requests to check for job status until it has completed + or the specified timeout is reached + """ + op_timeout = time.time() + timeout + while time.time() < op_timeout: + job_resp = self._request("get", job_uri) + if job_resp['status'] == 'complete': + if job_resp['job-status-code'] in (200, 201, 204): + return + raise ApiClientRequestError( + req_method, req_uri, + job_resp.get('job-status-code', '(no status)'), + job_resp.get('job-reason-code', '(no reason)'), + job_resp.get('job-results', {}).get( + 'message', '(no message)') + ) + time.sleep(1) + raise ApiClientError('Timed out while waiting for job completion') + + def cpc_list(self): + """ + Return a list of CPCs in the format {'name': 'cpc-name', 'status': + 'operating'} + """ + list_resp = self._request("get", "/api/cpcs", valid_codes=[200]) + ret = [] + for cpc_props in list_resp['cpcs']: + self._update_cpc_cache(cpc_props) + ret.append({ + 'name': cpc_props['name'], 'status': cpc_props['status']}) + return ret + + def is_dpm_enabled(self, cpc): + """ + Return True if CPC is in DPM mode, False for classic mode + """ + if cpc in self._cpc_cache: + return self._cpc_cache[cpc]['dpm-enabled'] + list_resp = self._request("get", "/api/cpcs?name={}".format(cpc), + valid_codes=[200]) + if not list_resp['cpcs']: + raise ValueError(ERROR_NOT_FOUND.format( + obj_type='CPC', obj_name=cpc)) + self._update_cpc_cache(list_resp['cpcs'][0]) + return self._cpc_cache[cpc]['dpm-enabled'] + + def logon(self): + """ + Open a session with the HMC API and store its ID + """ + self._session = self._create_session() + logon_body = {"userid": self.user, "password": self.passwd} + logon_resp = self._request("post", "/api/sessions", body=logon_body, + valid_codes=[200, 201]) + self._session.headers["X-API-Session"] = logon_resp['api-session'] + + def logoff(self): + """ + Close/delete the HMC API session + """ + if self._session is None: + return + self._request("delete", "/api/sessions/this-session", + valid_codes=[204]) + self._cpc_cache = {} + self._session = None + + def partition_list(self, cpc): + """ + Return a list of partitions in the format {'name': 'part-name', + 'status': 'on'} + """ + label_map = self._get_mode_labels(cpc) + list_resp = self._request( + 'get', '{}/{}'.format( + self._cpc_cache[cpc]['object-uri'], label_map['nodes']), + valid_codes=[200]) + status_map = {label_map['state-on']: 'on'} + return [{'name': part['name'], + 'status': status_map.get(part['status'].lower(), 'off')} + for part in list_resp[label_map['nodes']]] + + def partition_start(self, cpc, partition): + """ + Power on a partition + """ + self._partition_switch_power(cpc, partition, 'start') + + def partition_status(self, cpc, partition): + """ + Return the current status of a partition (on or off) + """ + label_map = self._get_mode_labels(cpc) + + part_props = self._get_partition(cpc, partition) + if part_props['status'].lower() == label_map['state-on']: + return 'on' + return 'off' + + def partition_stop(self, cpc, partition): + """ + Power off a partition + """ + self._partition_switch_power(cpc, partition, 'stop') + +def parse_plug(options): + """ + Extract cpc and partition from specified plug value + """ + try: + cpc, partition = options['--plug'].strip().split('/', 1) + except ValueError: + fail_usage('Please specify nodename in format cpc/partition') + cpc = cpc.strip() + if not cpc or not partition: + fail_usage('Please specify nodename in format cpc/partition') + return cpc, partition + +def get_power_status(conn, options): + logging.debug('executing get_power_status') + status = conn.partition_status(*parse_plug(options)) + return status + +def set_power_status(conn, options): + logging.debug('executing set_power_status') + if options['--action'] == 'on': + conn.partition_start(*parse_plug(options)) + elif options['--action'] == 'off': + conn.partition_stop(*parse_plug(options)) + else: + fail_usage('Invalid action {}'.format(options['--action'])) + +def get_outlet_list(conn, options): + logging.debug('executing get_outlet_list') + result = {} + for cpc in conn.cpc_list(): + for part in conn.partition_list(cpc['name']): + result['{}/{}'.format(cpc['name'], part['name'])] = ( + part['name'], part['status']) + return result + +def disconnect(conn): + """ + Close the API session + """ + try: + conn.logoff() + except Exception as exc: + logging.exception('Logoff failed: ') + sys.exit(str(exc)) + +def set_opts(): + """ + Define the options supported by this agent + """ + device_opt = [ + "ipaddr", + "ipport", + "login", + "passwd", + "port", + "connect_retries", + "connect_timeout", + "operation_timeout", + "read_retries", + "read_timeout", + "ssl_secure", + "load_on_activate", + ] + + all_opt["ipport"]["default"] = APIClient.DEFAULT_CONFIG['port'] + all_opt["power_timeout"]["default"] = DEFAULT_POWER_TIMEOUT + port_desc = ("Physical plug id in the format cpc-name/partition-name " + "(case-sensitive)") + all_opt["port"]["shortdesc"] = port_desc + all_opt["port"]["help"] = ( + "-n, --plug=[id] {}".format(port_desc)) + all_opt["connect_retries"] = { + "getopt" : ":", + "longopt" : "connect-retries", + "help" : "--connect-retries=[number] How many times to " + "retry on connection errors", + "default" : APIClient.DEFAULT_CONFIG['connect_retries'], + "type" : "integer", + "required" : "0", + "shortdesc" : "How many times to retry on connection errors", + "order" : 2 + } + all_opt["read_retries"] = { + "getopt" : ":", + "longopt" : "read-retries", + "help" : "--read-retries=[number] How many times to " + "retry on errors related to reading from server", + "default" : APIClient.DEFAULT_CONFIG['read_retries'], + "type" : "integer", + "required" : "0", + "shortdesc" : "How many times to retry on read errors", + "order" : 2 + } + all_opt["connect_timeout"] = { + "getopt" : ":", + "longopt" : "connect-timeout", + "help" : "--connect-timeout=[seconds] How long to wait to " + "establish a connection", + "default" : APIClient.DEFAULT_CONFIG['connect_timeout'], + "type" : "second", + "required" : "0", + "shortdesc" : "How long to wait to establish a connection", + "order" : 2 + } + all_opt["operation_timeout"] = { + "getopt" : ":", + "longopt" : "operation-timeout", + "help" : "--operation-timeout=[seconds] How long to wait for " + "power operation to complete (0 = do not wait)", + "default" : APIClient.DEFAULT_CONFIG['operation_timeout'], + "type" : "second", + "required" : "0", + "shortdesc" : "How long to wait for power operation to complete", + "order" : 2 + } + all_opt["read_timeout"] = { + "getopt" : ":", + "longopt" : "read-timeout", + "help" : "--read-timeout=[seconds] How long to wait " + "to read data from server", + "default" : APIClient.DEFAULT_CONFIG['read_timeout'], + "type" : "second", + "required" : "0", + "shortdesc" : "How long to wait for server data", + "order" : 2 + } + all_opt["load_on_activate"] = { + "getopt" : "", + "longopt" : "load-on-activate", + "help" : "--load-on-activate Rely on the HMC to perform " + "a load operation on activation", + "required" : "0", + "order" : 3 + } + return device_opt + +def main(): + """ + Agent entry point + """ + # register exit handler used by pacemaker + atexit.register(atexit_handler) + + # prepare accepted options + device_opt = set_opts() + + # parse options provided on input + options = check_input(device_opt, process_input(device_opt)) + + docs = { + "shortdesc": "Fence agent for IBM z LPARs", + "longdesc": ( + "fence_ibmz is a power fencing agent which uses the HMC Web " + "Services API to fence IBM z LPARs."), + "vendorurl": "http://www.ibm.com" + } + show_docs(options, docs) + + run_delay(options) + + # set underlying library's logging and ssl config according to specified + # options + requests_log = logging.getLogger("urllib3") + requests_log.propagate = True + if "--verbose" in options: + requests_log.setLevel(logging.DEBUG) + if "--ssl-insecure" in options: + urllib3.disable_warnings( + category=urllib3.exceptions.InsecureRequestWarning) + + hmc_address = options["--ip"] + hmc_userid = options["--username"] + hmc_password = options["--password"] + config = { + 'connect_retries': int(options['--connect-retries']), + 'read_retries': int(options['--read-retries']), + 'operation_timeout': int(options['--operation-timeout']), + 'connect_timeout': int(options['--connect-timeout']), + 'read_timeout': int(options['--read-timeout']), + 'port': int(options['--ipport']), + 'ssl_verify': bool('--ssl-insecure' not in options), + 'load_on_activate': bool('--load-on-activate' in options), + } + try: + conn = APIClient(hmc_address, hmc_userid, hmc_password, config) + conn.logon() + atexit.register(disconnect, conn) + result = fence_action(conn, options, set_power_status, + get_power_status, get_outlet_list) + except Exception: + logging.exception('Exception occurred: ') + result = EC_GENERIC_ERROR + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ifmib/README b/agents/ifmib/README new file mode 100644 index 0000000..6fe8a2b --- /dev/null +++ b/agents/ifmib/README @@ -0,0 +1,45 @@ +Intro: +------ +This is an SNMP-based fencing agent for RHCS. It was designed with the use-case +of disabling ethernet ports on an iSCSI SAN, but could be used to disable any +port on any SNMP v1/2c/3 device that implementes the IF-MIB. + +The script requires NetSNMP to be installed and working on all nodes +in the cluster. There are no requirements for any MIBs to be setup --- all of +the required OIDs are hard-coded into the script. Since the IF-MIB is an IETF +standard, these identifiers are very widely supported and will not change. + + +Typical usage: +-------------- +To use this agent with the switch used on the iSCSI network, you'll need: + 1) A managed switch running SNMP. + 2) An SNMP community with write privileges. + 3) Permission to send SNMP through any ACLs or firewalls from the nodes. + 4) The ifIndex or ifPort associated with the ports being used by the cluster nodes. + +Consider a three-node cluster composed of A, B, and C. Each node has two +network interfaces - one used for network and cluster communication, the second +used for iSCSI traffic. If A needs to be fenced, B and C will run this script +to administratively disable the switchport for A's connection to the iSCSI +storage. + +If you are using a single interface for cluster and iSCSI traffic, this will +still work, but you will lose network connectivity to the fenced host. + + +cluster.conf: +------------- +There is no GUI support for this fence agent at this time. To use it, you will +need something like this cluster.conf + +<fencedevice agent="fence_ifmib" name="myswitch" comm="fencing" ipaddr="sw1"/> + +In a node's fencing methods, you'll include a line like this: + +<device name="myswitch" port="43" option="off"/> + +This node will be fenced by disabling the port with ifIndex 43 on the host sw1. +In SNMP speak, we set IF-MIB::ifAdminStatus.43 = down(2). + +If you will use port name (like fc1/1), script will try to find ifIndex. diff --git a/agents/ifmib/fence_ifmib.py b/agents/ifmib/fence_ifmib.py new file mode 100644 index 0000000..d119134 --- /dev/null +++ b/agents/ifmib/fence_ifmib.py @@ -0,0 +1,116 @@ +#!@PYTHON@ -tt + +# The Following agent has been tested on: +# - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2 +# with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) +# - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500 +# with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) +# - Partially with APC PDU (Network Management Card AOS v2.7.0, Rack PDU APP v2.7.3) +# Only lance if is visible + +import sys +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, array_to_dict +from fencing_snmp import FencingSnmp + +### CONSTANTS ### +# IF-MIB trees for alias, status and port +ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18" +PORTS_OID = ".1.3.6.1.2.1.2.2.1.2" +STATUSES_OID = ".1.3.6.1.2.1.2.2.1.7" + +# Status constants returned as value from SNMP +STATUS_UP = 1 +STATUS_DOWN = 2 +STATUS_TESTING = 3 + +### GLOBAL VARIABLES ### +# Port number converted from port name or index +port_num = None + +### FUNCTIONS ### + +# Convert port index or name to port index +def port2index(conn, port): + res = None + + if port.isdigit(): + res = int(port) + else: + ports = conn.walk(PORTS_OID, 30) + + for x in ports: + if x[1].strip('"') == port: + res = int(x[0].split('.')[-1]) + break + + if res == None: + fail_usage("Can't find port with name %s!"%(port)) + + return res + +def get_power_status(conn, options): + global port_num + + if port_num == None: + port_num = port2index(conn, options["--plug"]) + + (_, status) = conn.get("%s.%d"%(STATUSES_OID, port_num)) + return status == str(STATUS_UP) and "on" or "off" + +def set_power_status(conn, options): + global port_num + + if port_num == None: + port_num = port2index(conn, options["--plug"]) + + conn.set("%s.%d" % (STATUSES_OID, port_num), (options["--action"] == "on" and STATUS_UP or STATUS_DOWN)) + +def get_outlets_status(conn, options): + result = {} + + res_fc = conn.walk(PORTS_OID, 30) + res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30)) + + for x in res_fc: + port_number = x[0].split('.')[-1] + + port_name = x[1].strip('"') + port_alias = (port_number in res_aliases and res_aliases[port_number].strip('"') or "") + port_status = "" + result[port_name] = (port_alias, port_status) + + return result + +# Main agent method +def main(): + device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \ + "port", "snmp_version", "snmp"] + + atexit.register(atexit_handler) + + all_opt["snmp_version"]["default"] = "2c" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for IF MIB" + docs["longdesc"] = "fence_ifmib is an I/O Fencing agent \ +which can be used with any SNMP IF-MIB capable device. \ +\n.P\n\ +It was written with managed ethernet switches in mind, in order to \ +fence iSCSI SAN connections. However, there are many devices that \ +support the IF-MIB interface. The agent uses IF-MIB::ifAdminStatus \ +to control the state of an interface." + docs["vendorurl"] = "http://www.ietf.org/wg/concluded/ifmib.html" + show_docs(options, docs) + + # Operate the fencing device + result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ilo/fence_ilo.py b/agents/ilo/fence_ilo.py new file mode 100644 index 0000000..6124505 --- /dev/null +++ b/agents/ilo/fence_ilo.py @@ -0,0 +1,143 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## iLO Version +## +---------------------------------------------+ +## iLO / firmware 1.91 / RIBCL 2.22 +## iLO2 / firmware 1.22 / RIBCL 2.22 +## iLO2 / firmware 1.50 / RIBCL 2.22 +##### + +import sys, re, pexpect +import atexit +from xml.sax.saxutils import quoteattr +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_LOGIN_DENIED + +def get_power_status(conn, options): + conn.send("<LOGIN USER_LOGIN = " + quoteattr(options["--username"]) + \ + " PASSWORD = " + quoteattr(options["--password"]) + ">\r\n") + conn.send("<SERVER_INFO MODE = \"read\"><GET_HOST_POWER_STATUS/>\r\n") + conn.send("</SERVER_INFO></LOGIN>\r\n") + conn.log_expect("HOST_POWER=\"(.*?)\"", int(options["--power-timeout"])) + + status = conn.match.group(1) + return status.lower().strip() + +def set_power_status(conn, options): + conn.send("<LOGIN USER_LOGIN = " + quoteattr(options["--username"]) + \ + " PASSWORD = " + quoteattr(options["--password"]) + ">\r\n") + conn.send("<SERVER_INFO MODE = \"write\">") + + if options.get("fw_processor", None) == "iLO2": + if options["fw_version"] > 1.29: + conn.send("<HOLD_PWR_BTN TOGGLE=\"yes\" />\r\n") + else: + conn.send("<HOLD_PWR_BTN />\r\n") + elif options["--ribcl-version"] < 2.21: + conn.send("<SET_HOST_POWER HOST_POWER = \"" + options["--action"] + "\" />\r\n") + else: + if options["--action"] == "off": + conn.send("<HOLD_PWR_BTN/>\r\n") + else: + conn.send("<PRESS_PWR_BTN/>\r\n") + conn.send("</SERVER_INFO></LOGIN>\r\n") + + return + +def define_new_opts(): + all_opt["ribcl"] = { + "getopt" : "r:", + "longopt" : "ribcl-version", + "help" : "-r, --ribcl-version=[version] Force ribcl version to use", + "required" : "0", + "shortdesc" : "Force ribcl version to use", + "order" : 1} + +def main(): + device_opt = ["ipaddr", "login", "passwd", "ssl", "notls", "tls1.0", "ribcl"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["login_timeout"]["default"] = "10" + all_opt["retry_on"]["default"] = "3" + all_opt["ssl"]["default"] = "1" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for HP iLO" + docs["longdesc"] = "fence_ilo is an I/O Fencing agent \ +used for HP servers with the Integrated Light Out (iLO) PCI card.\ +The agent opens an SSL connection to the iLO card. Once the SSL \ +connection is established, the agent is able to communicate with \ +the iLO card through an XML stream." + docs["vendorurl"] = "http://www.hp.com" + docs["symlink"] = [("fence_ilo2", "Fence agent for HP iLO2")] + show_docs(options, docs) + + ## + ## Login and get version number + #### + conn = fence_login(options) + try: + conn.send("<?xml version=\"1.0\"?>\r\n") + conn.log_expect(["</RIBCL>", "<END_RIBCL/>"], int(options["--login-timeout"])) + except pexpect.TIMEOUT: + fail(EC_LOGIN_DENIED) + except pexpect.EOF: + if "--tls1.0" in options: + fail(EC_LOGIN_DENIED) + options["--tls1.0"] = "1" + conn.close() + conn = fence_login(options) + try: + conn.send("<?xml version=\"1.0\"?>\r\n") + conn.log_expect(["</RIBCL>", "<END_RIBCL/>"], int(options["--login-timeout"])) + except pexpect.TIMEOUT: + fail(EC_LOGIN_DENIED) + except pexpect.EOF: + fail(EC_LOGIN_DENIED) + + try: + version = re.compile("<RIBCL VERSION=\"(.*?)\"", re.IGNORECASE).search(conn.before).group(1) + if "--ribcl-version" not in options: + options["--ribcl-version"] = float(version) + + if options["--ribcl-version"] >= 2: + conn.send("<RIBCL VERSION=\"2.0\">\r\n") + else: + conn.send("<RIBCL VERSION=\"1.2\">\r\n") + + conn.send("<LOGIN USER_LOGIN = " + quoteattr(options["--username"]) + \ + " PASSWORD = " + quoteattr(options["--password"]) + ">\r\n") + if options["--ribcl-version"] >= 2: + conn.send("<RIB_INFO MODE=\"read\"><GET_FW_VERSION />\r\n") + conn.send("</RIB_INFO>\r\n") + conn.log_expect(r"<GET_FW_VERSION\s*\n", int(options["--shell-timeout"])) + conn.log_expect("/>", int(options["--shell-timeout"])) + options["fw_version"] = float(re.compile(r"FIRMWARE_VERSION\s*=\s*\"(.*?)\"", + re.IGNORECASE).search(conn.before).group(1)) + options["fw_processor"] = re.compile(r"MANAGEMENT_PROCESSOR\s*=\s*\"(.*?)\"", + re.IGNORECASE).search(conn.before).group(1) + conn.send("</LOGIN>\r\n") + except pexpect.TIMEOUT: + fail(EC_LOGIN_DENIED) + except pexpect.EOF: + fail(EC_LOGIN_DENIED) + + ## + ## Fence operations + #### + result = fence_action(conn, options, set_power_status, get_power_status, None) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ilo_moonshot/fence_ilo_moonshot.py b/agents/ilo_moonshot/fence_ilo_moonshot.py new file mode 100644 index 0000000..1923eeb --- /dev/null +++ b/agents/ilo_moonshot/fence_ilo_moonshot.py @@ -0,0 +1,65 @@ +#!@PYTHON@ -tt + +import sys +import logging +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS + +def get_power_status(conn, options): + conn.send_eol("show node list") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + nodes = {} + for line in conn.before.splitlines(): + if len(line.split()) == 10: + nodes[line.split()[1]] = ("", line.split()[8].lower().strip()) + + if ["list", "monitor"].count(options["--action"]) == 1: + return nodes + else: + try: + (_, status) = nodes[options["--plug"]] + return status.lower() + except KeyError as e: + logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + +def set_power_status(conn, options): + if options["--action"] == "on": + conn.send_eol("set node power on %s" % (options["--plug"])) + else: + conn.send_eol("set node power off force %s" % (options["--plug"])) + + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + return + +def main(): + device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "port"] + + atexit.register(atexit_handler) + + all_opt["secure"]["default"] = "1" + all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for HP Moonshot iLO" + docs["longdesc"] = "" + docs["vendorurl"] = "http://www.hp.com" + show_docs(options, docs) + + conn = fence_login(options) + + ## + ## Fence operations + #### + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ilo_mp/fence_ilo_mp.py b/agents/ilo_mp/fence_ilo_mp.py new file mode 100644 index 0000000..1ae4d3e --- /dev/null +++ b/agents/ilo_mp/fence_ilo_mp.py @@ -0,0 +1,58 @@ +#!@PYTHON@ -tt + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * + +def get_power_status(conn, options): + conn.send_eol("show /system1") + + re_state = re.compile('EnabledState=(.*)', re.IGNORECASE) + conn.log_expect(re_state, int(options["--shell-timeout"])) + + status = conn.match.group(1).lower() + + if status.startswith("enabled"): + return "on" + else: + return "off" + +def set_power_status(conn, options): + if options["--action"] == "on": + conn.send_eol("start /system1") + else: + conn.send_eol("stop -f /system1") + + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + return + +def main(): + device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] + all_opt["power_wait"]["default"] = 5 + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for HP iLO MP" + docs["longdesc"] = "" + docs["vendorurl"] = "http://www.hp.com" + show_docs(options, docs) + + conn = fence_login(options) + conn.send_eol("SMCLP") + + ## + ## Fence operations + #### + result = fence_action(conn, options, set_power_status, get_power_status) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ilo_ssh/fence_ilo_ssh.py b/agents/ilo_ssh/fence_ilo_ssh.py new file mode 100644 index 0000000..a27e341 --- /dev/null +++ b/agents/ilo_ssh/fence_ilo_ssh.py @@ -0,0 +1,77 @@ +#!@PYTHON@ -tt + +import sys, re +import atexit +import logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * + +def get_power_status(conn, options): + conn.send_eol("show /system1") + + re_state = re.compile('EnabledState=(.*)', re.IGNORECASE) + conn.log_expect(re_state, int(options["--shell-timeout"])) + + status = conn.match.group(1).lower() + + if status.startswith("enabled"): + return "on" + else: + return "off" + +def set_power_status(conn, options): + if options["--action"] == "on": + conn.send_eol("start /system1") + else: + conn.send_eol("power off hard") + + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + return + +def reboot_cycle(conn, options): + conn.send_eol("reset /system1 hard") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + if get_power_status(conn, options) == "off": + logging.error("Timed out waiting to power ON\n") + + return True + +def main(): + device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "method", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] + all_opt["power_wait"]["default"] = 5 + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for HP iLO over SSH" + docs["longdesc"] = "fence_ilo_ssh is a fence agent that connects to iLO device. It logs into \ +device via ssh and reboot a specified outlet.\ +\n.P\n\ +WARNING: The monitor-action is prone to timeouts. Use the fence_ilo-equivalent \ +to avoid this issue." + docs["vendorurl"] = "http://www.hp.com" + docs["symlink"] = [("fence_ilo3_ssh", "Fence agent for HP iLO3 over SSH"), + ("fence_ilo4_ssh", "Fence agent for HP iLO4 over SSH"), + ("fence_ilo5_ssh", "Fence agent for HP iLO5 over SSH")] + show_docs(options, docs) + + options["eol"] = "\r" + + conn = fence_login(options) + conn.send_eol("SMCLP") + + ## + ## Fence operations + #### + result = fence_action(conn, options, set_power_status, get_power_status, None, reboot_cycle) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/intelmodular/fence_intelmodular.py b/agents/intelmodular/fence_intelmodular.py new file mode 100644 index 0000000..294ea4d --- /dev/null +++ b/agents/intelmodular/fence_intelmodular.py @@ -0,0 +1,86 @@ +#!@PYTHON@ -tt + +# Tested with an Intel MFSYS25 using firmware package 2.6 Should work with an +# MFSYS35 as well. +# +# Notes: +# +# The manual and firmware release notes says SNMP is read only. This is not +# true, as per the MIBs that ship with the firmware you can write to +# the bladePowerLed oid to control the servers. +# +# Thanks Matthew Kent for original agent and testing. + +import sys +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing_snmp import FencingSnmp + +### CONSTANTS ### +# From INTELCORPORATION-MULTI-FLEX-SERVER-BLADES-MIB.my that ships with +# firmware updates +STATUSES_OID = ".1.3.6.1.4.1.343.2.19.1.2.10.202.1.1.6" + +# Status constants returned as value from SNMP +STATUS_UP = 2 +STATUS_DOWN = 0 + +# Status constants to set as value to SNMP +STATUS_SET_ON = 2 +STATUS_SET_OFF = 3 + +### FUNCTIONS ### + +def get_power_status(conn, options): + (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) + return status == str(STATUS_UP) and "on" or "off" + +def set_power_status(conn, options): + conn.set("%s.%s" % (STATUSES_OID, options["--plug"]), + (options["--action"] == "on" and STATUS_SET_ON or STATUS_SET_OFF)) + +def get_outlets_status(conn, options): + result = {} + + res_blades = conn.walk(STATUSES_OID, 30) + + for x in res_blades: + port_num = x[0].split('.')[-1] + + port_alias = "" + port_status = (x[1] == str(STATUS_UP) and "on" or "off") + + result[port_num] = (port_alias, port_status) + + return result + +# Main agent method +def main(): + device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", + "port", "snmp_version", "snmp"] + + atexit.register(atexit_handler) + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Intel Modular" + docs["longdesc"] = "fence_intelmodular is an I/O Fencing agent \ +which can be used with Intel Modular device (tested on Intel MFSYS25, should \ +work with MFSYS35 as well). \ +\n.P\n\ +Note: Since firmware update version 2.7, SNMP v2 write support is \ +removed, and replaced by SNMP v3 support. So agent now has default \ +SNMP version 3. If you are using older firmware, please supply -d \ +for command line and snmp_version option for your cluster.conf." + docs["vendorurl"] = "http://www.intel.com" + show_docs(options, docs) + + # Operate the fencing device + result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ipdu/fence_ipdu.py b/agents/ipdu/fence_ipdu.py new file mode 100644 index 0000000..da34d2b --- /dev/null +++ b/agents/ipdu/fence_ipdu.py @@ -0,0 +1,153 @@ +#!@PYTHON@ -tt + +# The Following agent has been tested on: +# IBM iPDU model 46M4002 +# Firmware release OPDP_sIBM_v01.2_1 +# + +import sys +import atexit +import logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage +from fencing_snmp import FencingSnmp + +### CONSTANTS ### +# oid defining fence device +OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' + +### GLOBAL VARIABLES ### +# Device - see IBM iPDU +device = None + +# Port ID +port_id = None +# Switch ID +switch_id = None + +# Classes describing Device params +class IBMiPDU(object): + # iPDU + status_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d' + control_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d' + outlet_table_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.2' + ident_str = "IBM iPDU" + state_on = 1 + state_off = 0 + turn_on = 1 + turn_off = 0 + has_switches = False + +### FUNCTIONS ### +def ipdu_set_device(conn, options): + global device + + agents_dir = {'.1.3.6.1.4.1.2.6.223':IBMiPDU, + None:IBMiPDU} + + # First resolve type of PDU device + pdu_type = conn.walk(OID_SYS_OBJECT_ID) + + if not ((len(pdu_type) == 1) and (pdu_type[0][1] in agents_dir)): + pdu_type = [[None, None]] + + device = agents_dir[pdu_type[0][1]] + + logging.debug("Trying %s"%(device.ident_str)) + +def ipdu_resolv_port_id(conn, options): + global port_id, switch_id + + if device == None: + ipdu_set_device(conn, options) + + # Now we resolv port_id/switch_id + if options["--plug"].isdigit() and ((not device.has_switches) or (options["--switch"].isdigit())): + port_id = int(options["--plug"]) + + if device.has_switches: + switch_id = int(options["--switch"]) + else: + table = conn.walk(device.outlet_table_oid, 30) + + for x in table: + if x[1].strip('"') == options["--plug"]: + t = x[0].split('.') + if device.has_switches: + port_id = int(t[len(t)-1]) + switch_id = int(t[len(t)-3]) + else: + port_id = int(t[len(t)-1]) + + if port_id == None: + fail_usage("Can't find port with name %s!"%(options["--plug"])) + +def get_power_status(conn, options): + if port_id == None: + ipdu_resolv_port_id(conn, options) + + oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id)) + + (oid, status) = conn.get(oid) + return status == str(device.state_on) and "on" or "off" + +def set_power_status(conn, options): + if port_id == None: + ipdu_resolv_port_id(conn, options) + + oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id)) + + conn.set(oid, (options["--action"] == "on" and device.turn_on or device.turn_off)) + + +def get_outlets_status(conn, options): + result = {} + + if device == None: + ipdu_set_device(conn, options) + + res_ports = conn.walk(device.outlet_table_oid, 30) + + for x in res_ports: + t = x[0].split('.') + + port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1])) + + port_name = x[1].strip('"') + port_status = "" + result[port_num] = (port_name, port_status) + + return result + +# Main agent method +def main(): + global device + + device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ + "port", "snmp_version", "snmp"] + + atexit.register(atexit_handler) + + all_opt["snmp_version"]["default"] = "3" + all_opt["community"]["default"] = "private" + all_opt["switch"]["default"] = "1" + device = IBMiPDU + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for iPDU over SNMP" + docs["longdesc"] = "fence_ipdu is an I/O Fencing agent \ +which can be used with the IBM iPDU network power switch. It logs \ +into a device via SNMP and reboots a specified outlet. It supports \ +SNMP v3 with all combinations of authenticity/privacy settings." + docs["vendorurl"] = "http://www.ibm.com" + show_docs(options, docs) + + # Operate the fencing device + result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) +if __name__ == "__main__": + main() diff --git a/agents/ipmilan/fence_ipmilan.py b/agents/ipmilan/fence_ipmilan.py new file mode 100644 index 0000000..f751de6 --- /dev/null +++ b/agents/ipmilan/fence_ipmilan.py @@ -0,0 +1,233 @@ +#!@PYTHON@ -tt + +import sys, re, os +import atexit +from pipes import quote +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, is_executable, run_command, run_delay + +def get_power_status(_, options): + output = _run_command(options, "status") + match = re.search('[Cc]hassis [Pp]ower is [\\s]*([a-zA-Z]{2,3})', str(output)) + status = match.group(1) if match else None + return status + +def set_power_status(_, options): + _run_command(options, options["--action"]) + return + +def reboot_cycle(_, options): + output = _run_command(options, "cycle") + return bool(re.search('chassis power control: cycle', str(output).lower())) + +def reboot_diag(_, options): + output = _run_command(options, "diag") + return bool(re.search('chassis power control: diag', str(output).lower())) + +def _run_command(options, action): + cmd, log_cmd = create_command(options, action) + return run_command(options, cmd, log_command=log_cmd) + +def create_command(options, action): + class Cmd: + cmd = "" + log = "" + + @classmethod + def append(cls, cmd, log=None): + cls.cmd += cmd + cls.log += (cmd if log is None else log) + + # --use-sudo / -d + if "--use-sudo" in options: + Cmd.append(options["--sudo-path"] + " ") + + Cmd.append(options["--ipmitool-path"]) + + # --lanplus / -L + if "--lanplus" in options and options["--lanplus"] in ["", "1"]: + Cmd.append(" -I lanplus") + else: + Cmd.append(" -I lan") + + # --ip / -a + Cmd.append(" -H " + options["--ip"]) + + # --port / -n + if "--ipport" in options: + Cmd.append(" -p " + options["--ipport"]) + + # --target + if "--target" in options: + Cmd.append(" -t " + options["--target"]) + + # --username / -l + if "--username" in options and len(options["--username"]) != 0: + Cmd.append(" -U " + quote(options["--username"])) + + # --auth / -A + if "--auth" in options: + Cmd.append(" -A " + options["--auth"]) + + # --password / -p + if "--password" in options: + Cmd.append(" -P " + quote(options["--password"]), " -P [set]") + else: + Cmd.append(" -P ''", " -P [set]") + + # --cipher / -C + if "--cipher" in options: + Cmd.append(" -C " + options["--cipher"]) + + if "--privlvl" in options: + Cmd.append(" -L " + options["--privlvl"]) + + if "--hexadecimal-kg" in options: + Cmd.append(" -y " + options["--hexadecimal-kg"]) + + if "--ipmitool-timeout" in options: + Cmd.append(" -N " + options["--ipmitool-timeout"]) + + # --action / -o + Cmd.append(" chassis power " + action) + + # --verbose-level + if options["--verbose-level"] > 1: + Cmd.append(" -" + "v" * (options["--verbose-level"] - 1)) + + return (Cmd.cmd, Cmd.log) + +def define_new_opts(): + all_opt["lanplus"] = { + "getopt" : "P", + "longopt" : "lanplus", + "help" : "-P, --lanplus Use Lanplus to improve security of connection", + "required" : "0", + "default" : "0", + "shortdesc" : "Use Lanplus to improve security of connection", + "order": 1 + } + all_opt["auth"] = { + "getopt" : "A:", + "longopt" : "auth", + "help" : "-A, --auth=[auth] IPMI Lan Auth type (md5|password|none)", + "required" : "0", + "shortdesc" : "IPMI Lan Auth type.", + "choices" : ["md5", "password", "none"], + "order": 1 + } + all_opt["cipher"] = { + "getopt" : "C:", + "longopt" : "cipher", + "help" : "-C, --cipher=[cipher] Ciphersuite to use (same as ipmitool -C parameter)", + "required" : "0", + "shortdesc" : "Ciphersuite to use (same as ipmitool -C parameter)", + "order": 1 + } + all_opt["privlvl"] = { + "getopt" : "L:", + "longopt" : "privlvl", + "help" : "-L, --privlvl=[level] " + "Privilege level on IPMI device (callback|user|operator|administrator)", + "required" : "0", + "shortdesc" : "Privilege level on IPMI device", + "default" : "administrator", + "choices" : ["callback", "user", "operator", "administrator"], + "order": 1 + } + all_opt["ipmitool_path"] = { + "getopt" : ":", + "longopt" : "ipmitool-path", + "help" : "--ipmitool-path=[path] Path to ipmitool binary", + "required" : "0", + "shortdesc" : "Path to ipmitool binary", + "default" : "@IPMITOOL_PATH@", + "order": 200 + } + all_opt["ipmitool_timeout"] = { + "getopt" : ":", + "longopt" : "ipmitool-timeout", + "help" : "--ipmitool-timeout=[timeout] Timeout (sec) for IPMI operation", + "required" : "0", + "shortdesc" : "Timeout (sec) for IPMI operation", + "default" : "2", + "order": 201 + } + all_opt["target"] = { + "getopt" : ":", + "longopt" : "target", + "help" : "--target=[targetaddress] Bridge IPMI requests to the remote target address", + "required" : "0", + "shortdesc" : "Bridge IPMI requests to the remote target address", + "order": 1 + } + all_opt["hexadecimal_kg"] = { + "getopt" : ":", + "longopt" : "hexadecimal-kg", + "help" : "--hexadecimal-kg=[key] Hexadecimal-encoded Kg key for IPMIv2 authentication", + "required" : "0", + "shortdesc" : "Hexadecimal-encoded Kg key for IPMIv2 authentication", + "order": 1 + } + +def main(): + atexit.register(atexit_handler) + + device_opt = ["ipaddr", "login", "no_login", "no_password", "passwd", + "diag", "lanplus", "auth", "cipher", "privlvl", "sudo", + "ipmitool_path", "ipmitool_timeout", "method", "target", "hexadecimal_kg"] + define_new_opts() + + all_opt["power_wait"]["default"] = 2 + if os.path.basename(sys.argv[0]) == "fence_ilo3": + all_opt["power_wait"]["default"] = "4" + all_opt["lanplus"]["default"] = "1" + elif os.path.basename(sys.argv[0]) == "fence_ilo4": + all_opt["lanplus"]["default"] = "1" + elif os.path.basename(sys.argv[0]) == "fence_ilo5": + all_opt["lanplus"]["default"] = "1" + elif os.path.basename(sys.argv[0]) == "fence_ipmilanplus": + all_opt["lanplus"]["default"] = "1" + + all_opt["ipport"]["default"] = "623" + all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: onoff)\n" \ + "WARNING! This fence agent might report success before the node is powered off. " \ + "You should use -m/method onoff if your fence device works correctly with that option." + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for IPMI" + docs["longdesc"] = "fence_ipmilan is an I/O Fencing agent\ +which can be used with machines controlled by IPMI.\ +This agent calls support software ipmitool (http://ipmitool.sf.net/). \ +WARNING! This fence agent might report success before the node is powered off. \ +You should use -m/method onoff if your fence device works correctly with that option." + docs["vendorurl"] = "" + docs["symlink"] = [("fence_ilo3", "Fence agent for HP iLO3"), + ("fence_ilo4", "Fence agent for HP iLO4"), + ("fence_ilo5", "Fence agent for HP iLO5"), + ("fence_ipmilanplus", "Fence agent for IPMIv2 lanplus"), + ("fence_imm", "Fence agent for IBM Integrated Management Module"), + ("fence_idrac", "Fence agent for Dell iDRAC")] + show_docs(options, docs) + + run_delay(options) + + if not is_executable(options["--ipmitool-path"]): + fail_usage("Ipmitool not found or not accessible") + + reboot_fn = reboot_cycle + if options["--action"] == "diag": + # Diag is a special action that can't be verified so we will reuse reboot functionality + # to minimize impact on generic library + options["--action"] = "reboot" + options["--method"] = "cycle" + reboot_fn = reboot_diag + + result = fence_action(None, options, set_power_status, get_power_status, None, reboot_fn) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ironic/fence_ironic.py b/agents/ironic/fence_ironic.py new file mode 100644 index 0000000..66d84fc --- /dev/null +++ b/agents/ironic/fence_ironic.py @@ -0,0 +1,130 @@ +#!@PYTHON@ -tt + +import atexit +import logging +import os +import re +import sys +from pipes import quote +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, is_executable, run_command, run_delay + +def get_name_or_uuid(options): + return options["--uuid"] if "--uuid" in options else options["--plug"] + +def get_power_status(_, options): + output = ironic_run_command(options, "status") + stdout = output[1] + match = re.search('power[\\s]*([a-zA-Z]{2,3})', str(stdout)) + status = match.group(1) if match else None + return status + +def set_power_status(_, options): + ironic_run_command(options, options["--action"]) + return + +def get_devices_list(_, options): + nodes = {} + output = ironic_run_command(options, "list") + stdout = output[1] + for line in stdout.splitlines(): + uuid = "UUID" + try: + (uuid, name, state) = line.split(',') + except ValueError: + pass + if "UUID" in uuid: + continue # skip line header + match = re.search('power[\\s]*([a-zA-Z]{2,3})', state) + status = match.group(1) if match else None + nodes[uuid] = (name, status) + + return nodes + +def ironic_run_command(options, action, timeout=None): + cmd = options["--openstack-path"] + " baremetal" + env = os.environ.copy() + # --username / -l + if "--username" in options and len(options["--username"]) != 0: + env["OS_USERNAME"] = options["--username"] + + # --password / -p + if "--password" in options: + env["OS_PASSWORD"] = options["--password"] + + # --tenant-name -t + if "--tenant-name" in options: + env["OS_TENANT_NAME"] = options["--tenant-name"] + + # --auth-url + if "--auth-url" in options: + env["OS_AUTH_URL"] = options["--auth-url"] + + # --action / -o + if action == "status": + cmd += " show %s -c power_state --format value" % (get_name_or_uuid(options)) + elif action in ["on", "off"]: + cmd += " power %s %s" % (action, get_name_or_uuid(options)) + elif action == "list": + cmd += " list -c 'Instance UUID' -c Name -c 'Power State' --format csv --quote minimal" + + + logging.debug("cmd -> %s" % cmd) + return run_command(options, cmd, timeout, env) + +def define_new_opts(): + all_opt["auth-url"] = { + "getopt" : ":", + "longopt" : "auth-url", + "help" : "--auth-url=[authurl] Auth URL", + "required" : "1", + "shortdesc" : "Keystone Admin Auth URL", + "order": 1 + } + all_opt["tenant-name"] = { + "getopt" : "t:", + "longopt" : "tenant-name", + "help" : "-t, --tenant-name=[tenant] Tenantname", + "required" : "0", + "shortdesc" : "Keystone Admin Tenant", + "default": "admin", + "order": 1 + } + all_opt["openstack-path"] = { + "getopt" : ":", + "longopt" : "openstack-path", + "help" : "--openstack-path=[path] Path to openstack binary", + "required" : "0", + "shortdesc" : "Path to the OpenStack binary", + "default" : "@OPENSTACK_PATH@", + "order": 200 + } + +def main(): + atexit.register(atexit_handler) + + device_opt = ["login", "passwd", "port", "auth-url", "tenant-name", "openstack-path"] + define_new_opts() + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for OpenStack's Ironic (Bare Metal as a service) service" + docs["longdesc"] = "fence_ironic is a Fencing agent \ +which can be used with machines controlled by the Ironic service. \ +This agent calls the openstack CLI. \ +WARNING! This fence agent is not intended for production use. Relying on a functional ironic service for fencing is not a good design choice." + docs["vendorurl"] = "https://wiki.openstack.org/wiki/Ironic" + show_docs(options, docs) + + run_delay(options) + + if not is_executable(options["--openstack-path"]): + fail_usage("openstack tool not found or not accessible") + + result = fence_action(None, options, set_power_status, get_power_status, get_devices_list) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/kdump/fence_kdump.c b/agents/kdump/fence_kdump.c new file mode 100644 index 0000000..eda1559 --- /dev/null +++ b/agents/kdump/fence_kdump.c @@ -0,0 +1,592 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- + * + * Copyright (c) Ryan O'Hara (rohara@redhat.com) + * Copyright (c) Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <syslog.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include "options.h" +#include "message.h" +#include "version.h" + +static int verbose = 0; + +#define log_debug(lvl, fmt, args...) \ +do { \ + if (lvl <= verbose) { \ + fprintf (stdout, "[debug]: " fmt, ##args); \ + syslog (LOG_INFO, fmt, ##args); \ + } \ +} while (0); + +#define log_error(lvl, fmt, args...) \ +do { \ + if (lvl <= verbose) { \ + fprintf (stderr, "[error]: " fmt, ##args); \ + syslog (LOG_ERR, fmt, ##args); \ + } \ +} while (0); + +static int +trim (char *str) +{ + char *p; + int len; + + if (!str) return (0); + + len = strlen (str); + + while (len--) { + if (isspace (str[len])) { + str[len] = 0; + } else { + break; + } + } + + for (p = str; *p && isspace (*p); p++); + + memmove (str, p, strlen (p) + 1); + + return (strlen (str)); +} + +static int +do_action_monitor (void) +{ + const char cmdline_path[] = "/proc/cmdline"; + FILE *procFile; + size_t sz = 0; + char *lines = NULL; + int result = 1; + + procFile = fopen(cmdline_path, "r"); + + if (procFile == NULL) { + log_error (0, "Unable to open file %s (%s)\n", cmdline_path, strerror (errno)); + return 1; + } + + while (!feof (procFile)) { + ssize_t rv = getline (&lines, &sz, procFile); + if ((rv != -1) && (strstr(lines, "crashkernel=") != NULL)) { + result = 0; + } + } + + free (lines); + fclose (procFile); + + return result; +} + +static int +do_action_off (const fence_kdump_opts_t *opts) +{ + int error; + fd_set rfds; + fence_kdump_msg_t msg; + fence_kdump_node_t *node; + struct timeval timeout; + struct addrinfo hints; + fence_kdump_node_t *check_node; + char addr[NI_MAXHOST]; + char port[NI_MAXSERV]; + struct sockaddr_storage ss; + socklen_t size = sizeof (ss); + + if (list_empty (&opts->nodes)) { + return (1); + } else { + node = list_first_entry (&opts->nodes, fence_kdump_node_t, list); + } + + timeout.tv_sec = opts->timeout; + timeout.tv_usec = 0; + + FD_ZERO (&rfds); + FD_SET (node->socket, &rfds); + + // create listening socket + memset (&hints, 0, sizeof (hints)); + + hints.ai_family = opts->family; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICSERV; + + hints.ai_family = node->info->ai_family; + hints.ai_flags |= AI_PASSIVE; + + freeaddrinfo (node->info); + + node->info = NULL; + error = getaddrinfo (NULL, node->port, &hints, &node->info); + if (error != 0) { + log_error (2, "getaddrinfo (%s)\n", gai_strerror (error)); + free_node (node); + return (1); + } + + error = bind (node->socket, node->info->ai_addr, node->info->ai_addrlen); + if (error != 0) { + log_error (2, "bind (%s)\n", strerror (errno)); + free_node (node); + return (1); + } + + list_for_each_entry (check_node, &opts->nodes, list) { + log_debug (0, "waiting for message from '%s'\n", check_node->addr); + if (node->info->ai_family != check_node->info->ai_family) { + log_error (0, "mixing IPv4 and IPv6 nodes is not supported\n"); + return (1); + } + } + + for (;;) { + error = select (node->socket + 1, &rfds, NULL, NULL, &timeout); + if (error < 0) { + log_error (2, "select (%s)\n", strerror (errno)); + break; + } + if (error == 0) { + log_debug (0, "timeout after %d seconds\n", opts->timeout); + break; + } + + error = recvfrom (node->socket, &msg, sizeof (msg), 0, (struct sockaddr *) &ss, &size); + if (error < 0) { + log_error (2, "recvfrom (%s)\n", strerror (errno)); + continue; + } + + error = getnameinfo ((struct sockaddr *) &ss, size, + addr, sizeof (addr), + port, sizeof (port), + NI_NUMERICHOST | NI_NUMERICSERV); + if (error != 0) { + log_error (2, "getnameinfo (%s)\n", gai_strerror (error)); + continue; + } + + if (msg.magic != FENCE_KDUMP_MAGIC) { + log_debug (1, "invalid magic number '0x%X'\n", msg.magic); + continue; + } + + // check if we have matched messages from any known node + list_for_each_entry (check_node, &opts->nodes, list) { + error = strcasecmp (check_node->addr, addr); + if (error == 0 ) { + switch (msg.version) { + case FENCE_KDUMP_MSGV1: + log_debug (0, "received valid message from '%s'\n", addr); + return (0); + default: + log_debug (1, "invalid message version '0x%X'\n", msg.version); + continue; + } + } + } + log_debug (1, "discard message from '%s'\n", addr); + + } + + return (1); +} + +static int +do_action_metadata (const char *self) +{ + fprintf (stdout, "<?xml version=\"1.0\" ?>\n"); + fprintf (stdout, "<resource-agent name=\"%s\"", basename (self)); + fprintf (stdout, " shortdesc=\"fencing agent for use with kdump crash recovery service\">\n"); + fprintf (stdout, "<longdesc>"); + fprintf (stdout, "fence_kdump is an I/O fencing agent to be used with the kdump\n" + "crash recovery service. When the fence_kdump agent is invoked,\n" + "it will listen for a message from the failed node that acknowledges\n" + "that the failed node is executing the kdump crash kernel.\n" + "Note that fence_kdump is not a replacement for traditional\n" + "fencing methods. The fence_kdump agent can only detect that a\n" + "node has entered the kdump crash recovery service. This allows the\n" + "kdump crash recovery service complete without being preempted by\n" + "traditional power fencing methods.\n\n" + "Note: the \"off\" action listen for message from failed node that\n" + "acknowledges node has entered kdump crash recovery service. If a valid\n" + "message is received from the failed node, the node is considered to be\n" + "fenced and the agent returns success. Failure to receive a valid\n" + "message from the failed node in the given timeout period results in\n" + "fencing failure. When multiple node names/IP addresses are specified\n" + "a single valid message is sufficient for success. This is useful when\n" + "single node can send message via several different IP addresses.\n"); + fprintf (stdout, "</longdesc>\n"); + fprintf (stdout, "<vendor-url>http://www.kernel.org/pub/linux/utils/kernel/kexec/</vendor-url>\n"); + + fprintf (stdout, "<parameters>\n"); + + fprintf (stdout, "\t<parameter name=\"nodename\" unique=\"0\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-n, --nodename=NODE[,NODE...]\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "List of names or IP addresses of node to be fenced. This option is\n" + "required for the \"off\" action. Multiple values separated by commas\n" + "can be specified. All values must be of same IP network family." ); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"ipport\" unique=\"0\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-p, --ipport=PORT\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" default=\"7410\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "IP port number that the fence_kdump agent will use to listen for\n" + "messages."); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"family\" unique=\"0\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-f, --family=FAMILY\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" default=\"auto\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "IP network family. Force the fence_kdump agent to use a specific\n" + "family. The value for FAMILY can be \"auto\", \"ipv4\", or\n" + "\"ipv6\"."); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"action\" unique=\"0\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-o, --action=ACTION\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" default=\"off\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Fencing action to perform. The value for ACTION can be either\n" + "\"off\" or \"metadata\"."); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"timeout\" unique=\"0\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-t, --timeout=TIMEOUT\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" default=\"60\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Number of seconds to wait for message from failed node. If no message\n" + "is received within TIMEOUT seconds, the fence_kdump agent\n" + "returns failure."); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"verbose\" unique=\"0\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-v, --verbose\" />\n"); + fprintf (stdout, "\t\t<content type=\"boolean\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Print verbose output"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"version\" unique=\"0\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-V, --version\" />\n"); + fprintf (stdout, "\t\t<content type=\"boolean\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Print version"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"usage\" unique=\"0\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-h, --help\" />\n"); + fprintf (stdout, "\t\t<content type=\"boolean\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Print usage"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "</parameters>\n"); + + fprintf (stdout, "<actions>\n"); + fprintf (stdout, "\t<action name=\"off\" />\n"); + fprintf (stdout, "\t<action name=\"monitor\" />\n"); + fprintf (stdout, "\t<action name=\"metadata\" />\n"); + fprintf (stdout, "\t<action name=\"validate-all\" />\n"); + fprintf (stdout, "</actions>\n"); + + fprintf (stdout, "</resource-agent>\n"); + + return (0); +} + +static void +print_usage (const char *self) +{ + fprintf (stdout, "Usage: %s [options]\n", basename (self)); + fprintf (stdout, "\n"); + fprintf (stdout, "Options:\n"); + fprintf (stdout, "\n"); + fprintf (stdout, "%s\n", + " -n, --nodename=NODE[,NODE...]List of names or IP addresses of node to be fenced"); + fprintf (stdout, "%s\n", + " -p, --ipport=PORT IP port number (default: 7410)"); + fprintf (stdout, "%s\n", + " -f, --family=FAMILY Network family: ([auto], ipv4, ipv6)"); + fprintf (stdout, "%s\n", + " -o, --action=ACTION Fencing action: ([off], monitor, metadata, validate-all)"); + fprintf (stdout, "%s\n", + " -t, --timeout=TIMEOUT Timeout in seconds (default: 60)"); + fprintf (stdout, "%s\n", + " -v, --verbose Print verbose output"); + fprintf (stdout, "%s\n", + " -V, --version Print version"); + fprintf (stdout, "%s\n", + " -h, --help Print usage"); + fprintf (stdout, "\n"); + + return; +} + +static int +get_options_node (fence_kdump_opts_t *opts) +{ + int error; + struct addrinfo hints; + fence_kdump_node_t *node; + + node = malloc (sizeof (fence_kdump_node_t)); + if (!node) { + log_error (2, "malloc (%s)\n", strerror (errno)); + return (1); + } + + memset (node, 0, sizeof (fence_kdump_node_t)); + memset (&hints, 0, sizeof (hints)); + + hints.ai_family = opts->family; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICSERV; + + strncpy (node->name, opts->nodename, sizeof (node->name) - 1); + snprintf (node->port, sizeof (node->port), "%d", opts->ipport); + + node->info = NULL; + error = getaddrinfo (node->name, node->port, &hints, &node->info); + if (error != 0) { + log_error (2, "getaddrinfo (%s)\n", gai_strerror (error)); + free_node (node); + return (1); + } + + error = getnameinfo (node->info->ai_addr, node->info->ai_addrlen, + node->addr, sizeof (node->addr), + node->port, sizeof (node->port), + NI_NUMERICHOST | NI_NUMERICSERV); + if (error != 0) { + log_error (2, "getnameinfo (%s)\n", gai_strerror (error)); + free_node (node); + return (1); + } + + node->socket = socket (node->info->ai_family, + node->info->ai_socktype, + node->info->ai_protocol); + if (node->socket < 0) { + log_error (2, "socket (%s)\n", strerror (errno)); + free_node (node); + return (1); + } + + list_add_tail (&node->list, &opts->nodes); + + return (0); +} + +static void +get_options (int argc, char **argv, fence_kdump_opts_t *opts) +{ + int opt; + + struct option options[] = { + { "nodename", required_argument, NULL, 'n' }, + { "ipport", required_argument, NULL, 'p' }, + { "family", required_argument, NULL, 'f' }, + { "action", required_argument, NULL, 'o' }, + { "timeout", required_argument, NULL, 't' }, + { "verbose", optional_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + while ((opt = getopt_long (argc, argv, "n:p:f:o:t:v::Vh", options, NULL)) != EOF) { + switch (opt) { + case 'n': + set_option_nodename (opts, optarg); + break; + case 'p': + set_option_ipport (opts, optarg); + break; + case 'f': + set_option_family (opts, optarg); + break; + case 'o': + set_option_action (opts, optarg); + break; + case 't': + set_option_timeout (opts, optarg); + break; + case 'v': + set_option_verbose (opts, optarg); + break; + case 'V': + print_version (argv[0]); + exit (0); + case 'h': + print_usage (argv[0]); + exit (0); + default: + print_usage (argv[0]); + exit (1); + } + } + + verbose = opts->verbose; + + return; +} + +static void +get_options_stdin (fence_kdump_opts_t *opts) +{ + char buf[1024]; + char *opt; + char *arg; + + while (fgets (buf, sizeof (buf), stdin) != 0) { + if (trim (buf) == 0) { + continue; + } + if (buf[0] == '#') { + continue; + } + + opt = buf; + + if ((arg = strchr (opt, '=')) != 0) { + *arg = 0; + arg += 1; + } else { + continue; + } + + if (!strcasecmp (opt, "nodename")) { + set_option_nodename (opts, arg); + continue; + } + if (!strcasecmp (opt, "ipport")) { + set_option_ipport (opts, arg); + continue; + } + if (!strcasecmp (opt, "family")) { + set_option_family (opts, arg); + continue; + } + if (!strcasecmp (opt, "action")) { + set_option_action (opts, arg); + continue; + } + if (!strcasecmp (opt, "timeout")) { + set_option_timeout (opts, arg); + continue; + } + if (!strcasecmp (opt, "verbose")) { + set_option_verbose (opts, arg); + continue; + } + } + + verbose = opts->verbose; + + return; +} + +int +main (int argc, char **argv) +{ + int error = 1; + fence_kdump_opts_t opts; + char *ptr; + char *node_list; + + init_options (&opts); + + if (argc > 1) { + get_options (argc, argv, &opts); + } else { + get_options_stdin (&opts); + } + + openlog ("fence_kdump", LOG_CONS|LOG_PID, LOG_DAEMON); + + if (opts.action == FENCE_KDUMP_ACTION_OFF) { + if (opts.nodename == NULL) { + log_error (0, "action 'off' requires nodename\n"); + exit (1); + } + node_list = (char *)malloc(strlen(opts.nodename)+1); + + strcpy(node_list, opts.nodename); //make local copy of nodename on which we can safely iterate + // iterate through node_list + for (ptr = strtok(node_list, ","); ptr != NULL; ptr = strtok(NULL, ",")) { + set_option_nodename (&opts, ptr); //overwrite nodename for next function + if (get_options_node (&opts) != 0) { + log_error (0, "failed to get node '%s'\n", opts.nodename); + exit (1); + } + } + free(node_list); + } + + if (verbose != 0) { + //clear nodename to avoid showing just last nodename here + free(opts.nodename); + opts.nodename = NULL; + print_options (&opts); + } + + switch (opts.action) { + case FENCE_KDUMP_ACTION_OFF: + error = do_action_off (&opts); + break; + case FENCE_KDUMP_ACTION_METADATA: + error = do_action_metadata (argv[0]); + break; + case FENCE_KDUMP_ACTION_MONITOR: + error = do_action_monitor (); + break; + case FENCE_KDUMP_ACTION_VALIDATE: + error = 0; + break; + default: + break; + } + + free_options (&opts); + + return (error); +} diff --git a/agents/kdump/fence_kdump_send.8 b/agents/kdump/fence_kdump_send.8 new file mode 100644 index 0000000..ab95836 --- /dev/null +++ b/agents/kdump/fence_kdump_send.8 @@ -0,0 +1,50 @@ +.TH fence_kdump_send 8 +.SH NAME +fence_kdump_send - send kdump acknowlegement message to cluster nodes +.SH SYNOPSIS +.B +fence_kdump_send +[\fIOPTIONS]\fR... [NODE]... +.SH DESCRIPTION +\fIfence_kdump_send\fP is a utility used to send messages that +acknowledge that the node has entered the kdump crash recovery +service. This utility is intended to be used the the \fIfence_kdump\fP +agent as a means detect that a failed node has entered the kdump crash +recovery service. +The \fIfence_kdump_send\fP utility is typically run from within the +kdump kernel after a cluster node has encountered a kernel panic. Once +the cluster node has entered the kdump crash recovery service, +\fIfence_kdump_send\fP will periodically send messages to all cluster +nodes. When the \fIfence_kdump\fP agent receives a valid message from +the failed node, fencing is complete. +.SH OPTIONS +.TP +.B -p, --ipport=\fIPORT\fP +IP port number that the \fIfence_kdump\fP agent is using to listen for +messages. (default: 7410) +.TP +.B -f, --family=\fIFAMILY\fP +IP network family. Force the \fIfence_kdump_send\fP utility to use a +particular network family. Value for \fIFAMILY\fP can be "auto", +"ipv4", or "ipv6". (default: auto) +.TP +.B -c, --count=\fICOUNT\fP +Number of messages to send. If \fICOUNT\fP is zero, +\fIfence_kdump_send\fP will send messages indefinitely. (default: 0) +.TP +.B -i, --interval=\fIINTERVAL\fP +Time to wait between sending a message. The value for \fIINTERVAL\fP +must be greater than zero. (default: 10) +.TP +.B -v, --verbose +Print verbose output. +.TP +.B -V, --version +Print version and exit. +.TP +.B -h, --help +Print usage and exit. +.SH AUTHOR +Ryan O'Hara <rohara@redhat.com> +.SH SEE ALSO +fence_kdump(8), mkdumprd(8), kdump.conf(5) diff --git a/agents/kdump/fence_kdump_send.c b/agents/kdump/fence_kdump_send.c new file mode 100644 index 0000000..638f8c9 --- /dev/null +++ b/agents/kdump/fence_kdump_send.c @@ -0,0 +1,255 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- + * + * Copyright (c) Ryan O'Hara (rohara@redhat.com) + * Copyright (c) Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <syslog.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include "options.h" +#include "message.h" +#include "version.h" + +static int verbose = 0; + +#define log_debug(lvl, fmt, args...) \ +do { \ + if (lvl <= verbose) \ + fprintf (stdout, "[debug]: " fmt, ##args); \ +} while (0); + +#define log_error(lvl, fmt, args...) \ +do { \ + if (lvl <= verbose) \ + fprintf (stderr, "[error]: " fmt, ##args); \ +} while (0); + +static int +send_message (const fence_kdump_node_t *node, void *msg, int len) +{ + int error; + + error = sendto (node->socket, msg, len, 0, node->info->ai_addr, node->info->ai_addrlen); + if (error < 0) { + log_error (2, "sendto (%s)\n", strerror (errno)); + goto out; + } + + log_debug (1, "message sent to node '%s'\n", node->addr); + +out: + return (error); +} + +static void +print_usage (const char *self) +{ + fprintf (stdout, "Usage: %s [options] [nodes]\n", basename (self)); + fprintf (stdout, "\n"); + fprintf (stdout, "Options:\n"); + fprintf (stdout, "\n"); + fprintf (stdout, "%s\n", + " -p, --ipport=PORT Port number (default: 7410)"); + fprintf (stdout, "%s\n", + " -f, --family=FAMILY Network family ([auto], ipv4, ipv6)"); + fprintf (stdout, "%s\n", + " -c, --count=COUNT Number of messages to send (default: 0)"); + fprintf (stdout, "%s\n", + " -i, --interval=INTERVAL Interval in seconds (default: 10)"); + fprintf (stdout, "%s\n", + " -v, --verbose Print verbose output"); + fprintf (stdout, "%s\n", + " -V, --version Print version"); + fprintf (stdout, "%s\n", + " -h, --help Print usage"); + fprintf (stdout, "\n"); + + return; +} + +static int +get_options_node (fence_kdump_opts_t *opts) +{ + int error; + struct addrinfo hints; + fence_kdump_node_t *node; + + node = malloc (sizeof (fence_kdump_node_t)); + if (!node) { + log_error (2, "malloc (%s)\n", strerror (errno)); + return (1); + } + + memset (node, 0, sizeof (fence_kdump_node_t)); + memset (&hints, 0, sizeof (hints)); + + hints.ai_family = opts->family; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICSERV; + + strncpy (node->name, opts->nodename, sizeof (node->name) - 1); + snprintf (node->port, sizeof (node->port), "%d", opts->ipport); + + node->info = NULL; + error = getaddrinfo (node->name, node->port, &hints, &node->info); + if (error != 0) { + log_error (2, "getaddrinfo (%s)\n", gai_strerror (error)); + free_node (node); + return (1); + } + + error = getnameinfo (node->info->ai_addr, node->info->ai_addrlen, + node->addr, sizeof (node->addr), + node->port, sizeof (node->port), + NI_NUMERICHOST | NI_NUMERICSERV); + if (error != 0) { + log_error (2, "getnameinfo (%s)\n", gai_strerror (error)); + free_node (node); + return (1); + } + + node->socket = socket (node->info->ai_family, + node->info->ai_socktype, + node->info->ai_protocol); + if (node->socket < 0) { + log_error (2, "socket (%s)\n", strerror (errno)); + free_node (node); + return (1); + } + + list_add_tail (&node->list, &opts->nodes); + + return (0); +} + +static void +get_options (int argc, char **argv, fence_kdump_opts_t *opts) +{ + int opt; + + struct option options[] = { + { "ipport", required_argument, NULL, 'p' }, + { "family", required_argument, NULL, 'f' }, + { "count", required_argument, NULL, 'c' }, + { "interval", required_argument, NULL, 'i' }, + { "verbose", optional_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + while ((opt = getopt_long (argc, argv, "p:f:c:i:v::Vh", options, NULL)) != EOF) { + switch (opt) { + case 'p': + set_option_ipport (opts, optarg); + break; + case 'f': + set_option_family (opts, optarg); + break; + case 'c': + set_option_count (opts, optarg); + break; + case 'i': + set_option_interval (opts, optarg); + break; + case 'v': + set_option_verbose (opts, optarg); + break; + case 'V': + print_version (argv[0]); + exit (0); + case 'h': + print_usage (argv[0]); + exit (0); + default: + print_usage (argv[0]); + exit (1); + } + } + + verbose = opts->verbose; + + return; +} + +int +main (int argc, char **argv) +{ + int count = 1; + fence_kdump_msg_t msg; + fence_kdump_opts_t opts; + fence_kdump_node_t *node; + + init_options (&opts); + + if (argc > 1) { + get_options (argc, argv, &opts); + } else { + print_usage (argv[0]); + exit (1); + } + + for (; optind < argc; optind++) { + opts.nodename = argv[optind]; + if (get_options_node (&opts) != 0) { + log_error (1, "failed to get node '%s'\n", opts.nodename); + } + opts.nodename = NULL; + } + + if (list_empty (&opts.nodes)) { + print_usage (argv[0]); + exit (1); + } + + if (verbose != 0) { + print_options (&opts); + } + + init_message (&msg); + + for (;;) { + list_for_each_entry (node, &opts.nodes, list) { + send_message (node, &msg, sizeof (msg)); + } + + if ((opts.count != 0) && (++count > opts.count)) { + break; + } + + sleep (opts.interval); + } + + free_options (&opts); + + return (0); +} diff --git a/agents/kdump/list.h b/agents/kdump/list.h new file mode 100644 index 0000000..8945a62 --- /dev/null +++ b/agents/kdump/list.h @@ -0,0 +1,573 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include <stddef.h> + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, + struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, + struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, + struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, + struct list_head *head) +{ + __list_del_entry(list); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del_entry(list); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + + return (next == head) && (next == head->prev); +} + +/** + * list_rotate_left - rotate the list to the left + * @head: the head of the list + */ +static inline void list_rotate_left(struct list_head *head) +{ + struct list_head *first; + + if (!list_empty(head)) { + first = head->next; + list_move_tail(first, head); + } +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, + struct list_head *entry) +{ + struct list_head *new_first = entry->next; + + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + */ +static inline void list_cut_position(struct list_head *list, + struct list_head *head, + struct list_head *entry) +{ + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(const struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head, head->next); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head->prev, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head, head->next); + INIT_LIST_HEAD(list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue - continue list iteration safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from - iterate over list from current point safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/** + * list_safe_reset_next - reset a stale list_for_each_entry_safe loop + * @pos: the loop cursor used in the list_for_each_entry_safe loop + * @n: temporary storage used in list_for_each_entry_safe + * @member: the name of the list_struct within the struct. + * + * list_safe_reset_next is not safe to use in general if the list may be + * modified concurrently (eg. the lock is dropped in the loop body). An + * exception to this is if the cursor element (pos) is pinned in the list, + * and list_safe_reset_next is called after re-taking the lock and before + * completing the current iteration of the loop body. + */ +#define list_safe_reset_next(pos, n, member) \ + n = list_entry(pos->member.next, typeof(*pos), member) + +#endif /* _LINUX_LIST_H */ diff --git a/agents/kdump/message.h b/agents/kdump/message.h new file mode 100644 index 0000000..2c82229 --- /dev/null +++ b/agents/kdump/message.h @@ -0,0 +1,41 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- + * + * Copyright (c) Ryan O'Hara (rohara@redhat.com) + * Copyright (c) Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef _FENCE_KDUMP_MESSAGE_H +#define _FENCE_KDUMP_MESSAGE_H + +#define FENCE_KDUMP_MAGIC 0x1B302A40 + +#define FENCE_KDUMP_MSGV1 0x1 + +typedef struct __attribute__ ((packed)) fence_kdump_msg { + uint32_t magic; + uint32_t version; +} fence_kdump_msg_t; + +static inline void +init_message (fence_kdump_msg_t *msg) +{ + msg->magic = FENCE_KDUMP_MAGIC; + msg->version = FENCE_KDUMP_MSGV1; +} + +#endif /* _FENCE_KDUMP_MESSAGE_H */ diff --git a/agents/kdump/options.h b/agents/kdump/options.h new file mode 100644 index 0000000..3cf7b43 --- /dev/null +++ b/agents/kdump/options.h @@ -0,0 +1,260 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- + * + * Copyright (c) Ryan O'Hara (rohara@redhat.com) + * Copyright (c) Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef _FENCE_KDUMP_OPTIONS_H +#define _FENCE_KDUMP_OPTIONS_H + +#include "list.h" + +#define FENCE_KDUMP_NAME_LEN 256 +#define FENCE_KDUMP_ADDR_LEN 46 +#define FENCE_KDUMP_PORT_LEN 6 + +enum { + FENCE_KDUMP_ACTION_OFF = 0, + FENCE_KDUMP_ACTION_ON = 1, + FENCE_KDUMP_ACTION_REBOOT = 2, + FENCE_KDUMP_ACTION_STATUS = 3, + FENCE_KDUMP_ACTION_LIST = 4, + FENCE_KDUMP_ACTION_MONITOR = 5, + FENCE_KDUMP_ACTION_METADATA = 6, + FENCE_KDUMP_ACTION_VALIDATE = 7, +}; + +enum { + FENCE_KDUMP_FAMILY_AUTO = AF_UNSPEC, + FENCE_KDUMP_FAMILY_IPV6 = AF_INET6, + FENCE_KDUMP_FAMILY_IPV4 = AF_INET, +}; + +#define FENCE_KDUMP_DEFAULT_IPPORT 7410 +#define FENCE_KDUMP_DEFAULT_FAMILY 0 +#define FENCE_KDUMP_DEFAULT_ACTION 0 +#define FENCE_KDUMP_DEFAULT_COUNT 0 +#define FENCE_KDUMP_DEFAULT_INTERVAL 10 +#define FENCE_KDUMP_DEFAULT_TIMEOUT 60 +#define FENCE_KDUMP_DEFAULT_VERBOSE 0 + +typedef struct fence_kdump_opts { + char *nodename; + int ipport; + int family; + int action; + int count; + int interval; + int timeout; + int verbose; + struct list_head nodes; +} fence_kdump_opts_t; + +typedef struct fence_kdump_node { + char name[FENCE_KDUMP_NAME_LEN]; + char addr[FENCE_KDUMP_ADDR_LEN]; + char port[FENCE_KDUMP_PORT_LEN]; + int socket; + struct addrinfo *info; + struct list_head list; +} fence_kdump_node_t; + +static inline void +init_node (fence_kdump_node_t *node) +{ + node->info = NULL; +} + +static inline void +free_node (fence_kdump_node_t *node) +{ + freeaddrinfo (node->info); + free (node); +} + +static inline void +print_node (const fence_kdump_node_t *node) +{ + fprintf (stdout, "[debug]: node { \n"); + fprintf (stdout, "[debug]: name = %s\n", node->name); + fprintf (stdout, "[debug]: addr = %s\n", node->addr); + fprintf (stdout, "[debug]: port = %s\n", node->port); + fprintf (stdout, "[debug]: info = %p\n", node->info); + fprintf (stdout, "[debug]: } \n"); +} + +static inline void +init_options (fence_kdump_opts_t *opts) +{ + opts->nodename = NULL; + opts->ipport = FENCE_KDUMP_DEFAULT_IPPORT; + opts->family = FENCE_KDUMP_DEFAULT_FAMILY; + opts->action = FENCE_KDUMP_DEFAULT_ACTION; + opts->count = FENCE_KDUMP_DEFAULT_COUNT; + opts->interval = FENCE_KDUMP_DEFAULT_INTERVAL; + opts->timeout = FENCE_KDUMP_DEFAULT_TIMEOUT; + opts->verbose = FENCE_KDUMP_DEFAULT_VERBOSE; + + INIT_LIST_HEAD (&opts->nodes); +} + +static inline void +free_options (fence_kdump_opts_t *opts) +{ + fence_kdump_node_t *node; + fence_kdump_node_t *safe; + + list_for_each_entry_safe (node, safe, &opts->nodes, list) { + list_del (&node->list); + free_node (node); + } + + free (opts->nodename); +} + +static inline void +print_options (fence_kdump_opts_t *opts) +{ + fence_kdump_node_t *node; + + fprintf (stdout, "[debug]: options { \n"); + fprintf (stdout, "[debug]: nodename = %s\n", opts->nodename); + fprintf (stdout, "[debug]: ipport = %d\n", opts->ipport); + fprintf (stdout, "[debug]: family = %d\n", opts->family); + fprintf (stdout, "[debug]: count = %d\n", opts->count); + fprintf (stdout, "[debug]: interval = %d\n", opts->interval); + fprintf (stdout, "[debug]: timeout = %d\n", opts->timeout); + fprintf (stdout, "[debug]: verbose = %d\n", opts->verbose); + fprintf (stdout, "[debug]: } \n"); + + list_for_each_entry (node, &opts->nodes, list) { + print_node (node); + } +} + +static inline void +set_option_nodename (fence_kdump_opts_t *opts, const char *arg) +{ + if (opts->nodename != NULL) { + free (opts->nodename); + } + + opts->nodename = strdup (arg); +} + +static inline void +set_option_ipport (fence_kdump_opts_t *opts, const char *arg) +{ + opts->ipport = atoi (arg); + + if ((opts->ipport < 1) || (opts->ipport > 65535)) { + fprintf (stderr, "[error]: invalid ipport '%s'\n", arg); + exit (1); + } +} + +static inline void +set_option_family (fence_kdump_opts_t *opts, const char *arg) +{ + if (!strcasecmp (arg, "auto")) { + opts->family = FENCE_KDUMP_FAMILY_AUTO; + } else if (!strcasecmp (arg, "ipv6")) { + opts->family = FENCE_KDUMP_FAMILY_IPV6; + } else if (!strcasecmp (arg, "ipv4")) { + opts->family = FENCE_KDUMP_FAMILY_IPV4; + } else { + fprintf (stderr, "[error]: unsupported family '%s'\n", arg); + exit (1); + } +} + +static inline void +set_option_action (fence_kdump_opts_t *opts, const char *arg) +{ + if (!strcasecmp (arg, "off")) { + opts->action = FENCE_KDUMP_ACTION_OFF; + } else if (!strcasecmp (arg, "metadata")) { + opts->action = FENCE_KDUMP_ACTION_METADATA; + } else if (!strcasecmp (arg, "monitor")) { + opts->action = FENCE_KDUMP_ACTION_MONITOR; + } else if (!strcasecmp (arg, "validate-all")) { + opts->action = FENCE_KDUMP_ACTION_VALIDATE; + } else { + fprintf (stderr, "[error]: unsupported action '%s'\n", arg); + exit (1); + } +} + +static inline void +set_option_count (fence_kdump_opts_t *opts, const char *arg) +{ + opts->count = atoi (arg); + + if (opts->count < 0) { + fprintf (stderr, "[error]: invalid count '%s'\n", arg); + exit (1); + } +} + +static inline void +set_option_interval (fence_kdump_opts_t *opts, const char *arg) +{ + opts->interval = atoi (arg); + + if (opts->interval < 1) { + fprintf (stderr, "[error]: invalid interval '%s'\n", arg); + exit (1); + } +} + +static inline void +set_option_timeout (fence_kdump_opts_t *opts, const char *arg) +{ + opts->timeout = atoi (arg); + + if (opts->timeout < 1) { + fprintf (stderr, "[error]: invalid timeout '%s'\n", arg); + exit (1); + } +} + +static inline void +set_option_verbose (fence_kdump_opts_t *opts, const char *arg) +{ + int i; + + if (arg != NULL) { + if (isdigit(arg[0])) { + opts->verbose += atoi (arg); + } else { + opts->verbose += 1; /* initial -v */ + for (i = 0; i < strlen(arg); i++) { + if (arg[i] == 'v') { + opts->verbose += 1; + } else { + fprintf (stderr, "[error]: invalid value '%c' for verbose\n", arg[i]); + return; + } + } + } + } else { + opts->verbose += 1; + } +} + +#endif /* _FENCE_KDUMP_OPTIONS_H */ diff --git a/agents/kdump/version.h b/agents/kdump/version.h new file mode 100644 index 0000000..ed178b1 --- /dev/null +++ b/agents/kdump/version.h @@ -0,0 +1,33 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- + * + * Copyright (c) Ryan O'Hara (rohara@redhat.com) + * Copyright (c) Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef _FENCE_KDUMP_VERSION_H +#define _FENCE_KDUMP_VERSION_H + +#define FENCE_KDUMP_VERSION "0.1" + +static inline void +print_version (const char *self) +{ + fprintf (stdout, "%s %s\n", basename (self), FENCE_KDUMP_VERSION); +} + +#endif /* _FENCE_KDUMP_VERSION_H */ diff --git a/agents/kubevirt/fence_kubevirt.py b/agents/kubevirt/fence_kubevirt.py new file mode 100755 index 0000000..8c27a03 --- /dev/null +++ b/agents/kubevirt/fence_kubevirt.py @@ -0,0 +1,154 @@ +#!@PYTHON@ -tt + +import sys +import logging +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, run_delay, EC_STATUS, EC_FETCH_VM_UUID + +try: + from kubernetes.client.exceptions import ApiException +except ImportError: + logging.error("Couldn\'t import kubernetes.client.exceptions.ApiException - not found or not accessible") + +def _get_namespace(options): + from kubernetes import config + + ns = options.get("--namespace") + if ns is None: + ns = config.kube_config.list_kube_config_contexts()[1]['context']['namespace'] + + return ns + +def get_nodes_list(conn, options): + logging.debug("Starting list/monitor operation") + result = {} + try: + apiversion = options.get("--apiversion") + namespace = _get_namespace(options) + include_uninitialized = True + vm_api = conn.resources.get(api_version=apiversion, kind='VirtualMachine') + vm_list = vm_api.get(namespace=namespace) + for vm in vm_list.items: + result[vm.metadata.name] = ("", None) + except Exception as e: + logging.error("Exception when calling VirtualMachine list: %s", e) + return result + +def get_power_status(conn, options): + logging.debug("Starting get status operation") + try: + apiversion = options.get("--apiversion") + namespace = _get_namespace(options) + name = options.get("--plug") + vmi_api = conn.resources.get(api_version=apiversion, + kind='VirtualMachineInstance') + vmi = vmi_api.get(name=name, namespace=namespace) + return translate_status(vmi.status.phase) + except ApiException as e: + if e.status == 404: + try: + vm_api = conn.resources.get(api_version=apiversion, kind='VirtualMachine') + vm = vm_api.get(name=name, namespace=namespace) + except ApiException as e: + logging.error("VM %s doesn't exist", name) + fail(EC_FETCH_VM_UUID) + return "off" + logging.error("Failed to get power status, with API Exception: %s", e) + fail(EC_STATUS) + except Exception as e: + logging.error("Failed to get power status, with Exception: %s", e) + fail(EC_STATUS) + +def translate_status(instance_status): + if instance_status == "Running": + return "on" + return "unknown" + +def set_power_status(conn, options): + logging.debug("Starting set status operation") + try: + apiversion= options.get("--apiversion") + namespace = _get_namespace(options) + name = options.get("--plug") + action = 'start' if options["--action"] == "on" else 'stop' + virtctl_vm_action(conn, action, namespace, name, apiversion) + except Exception as e: + logging.error("Failed to set power status, with Exception: %s", e) + fail(EC_STATUS) + +def define_new_opts(): + all_opt["namespace"] = { + "getopt" : ":", + "longopt" : "namespace", + "help" : "--namespace=[namespace] Namespace of the KubeVirt machine", + "shortdesc" : "Namespace of the KubeVirt machine.", + "required" : "0", + "order" : 2 + } + all_opt["kubeconfig"] = { + "getopt" : ":", + "longopt" : "kubeconfig", + "help" : "--kubeconfig=[kubeconfig] Kubeconfig file path", + "shortdesc": "Kubeconfig file path", + "required": "0", + "order": 4 + } + all_opt["apiversion"] = { + "getopt" : ":", + "longopt" : "apiversion", + "help" : "--apiversion=[apiversion] Version of the KubeVirt API", + "shortdesc" : "Version of the KubeVirt API.", + "required" : "0", + "default" : "kubevirt.io/v1", + "order" : 5 + } + +def virtctl_vm_action(conn, action, namespace, name, apiversion): + path = '/apis/subresources.{api_version}/namespaces/{namespace}/virtualmachines/{name}/{action}' + path = path.format(api_version=apiversion, namespace=namespace, name=name, action=action) + return conn.request('put', path, header_params={'accept': '*/*'}) + +# Main agent method +def main(): + conn = None + + device_opt = ["port", "namespace", "kubeconfig", "ssl_insecure", "no_password", "apiversion"] + + atexit.register(atexit_handler) + define_new_opts() + + all_opt["power_timeout"]["default"] = "40" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for KubeVirt" + docs["longdesc"] = "fence_kubevirt is an I/O Fencing agent for KubeVirt." + docs["vendorurl"] = "https://kubevirt.io/" + show_docs(options, docs) + + run_delay(options) + + # Disable insecure-certificate-warning message + if "--ssl-insecure" in options: + import urllib3 + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + try: + from kubernetes import config + from openshift.dynamic import DynamicClient + kubeconfig = options.get('--kubeconfig') + k8s_client = config.new_client_from_config(config_file=kubeconfig) + conn = DynamicClient(k8s_client) + except ImportError: + logging.error("Couldn\'t import kubernetes.config or " + "openshift.dynamic.DynamicClient - not found or not accessible") + + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/ldom/fence_ldom.py b/agents/ldom/fence_ldom.py new file mode 100644 index 0000000..0cb3320 --- /dev/null +++ b/agents/ldom/fence_ldom.py @@ -0,0 +1,102 @@ +#!@PYTHON@ -tt + +## +## The Following Agent Has Been Tested On - LDOM 1.0.3 +## The interface is backward compatible so it will work +## with 1.0, 1.0.1 and .2 too. +## +##### + +import sys, re, pexpect +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage + +COMMAND_PROMPT_REG = r"\[PEXPECT\]$" +COMMAND_PROMPT_NEW = "[PEXPECT]" + +# Start comunicating after login. Prepare good environment. +def start_communication(conn, options): + conn.send_eol("PS1='" + COMMAND_PROMPT_NEW + "'") + res = conn.expect([pexpect.TIMEOUT, COMMAND_PROMPT_REG], int(options["--shell-timeout"])) + if res == 0: + #CSH stuff + conn.send_eol("set prompt='" + COMMAND_PROMPT_NEW + "'") + conn.log_expect(COMMAND_PROMPT_REG, int(options["--shell-timeout"])) + +def get_power_status(conn, options): + start_communication(conn, options) + + conn.send_eol("ldm ls") + + conn.log_expect(COMMAND_PROMPT_REG, int(options["--shell-timeout"])) + + result = {} + + #This is status of mini finite automata. 0 = we didn't found NAME and STATE, 1 = we did + fa_status = 0 + + for line in conn.before.splitlines(): + domain = re.search(r"^(\S+)\s+(\S+)\s+.*$", line) + + if domain != None: + if fa_status == 0 and domain.group(1) == "NAME" and domain.group(2) == "STATE": + fa_status = 1 + elif fa_status == 1: + result[domain.group(1)] = ("", (domain.group(2).lower() == "bound" and "off" or "on")) + + if not options["--action"] in ['monitor', 'list']: + if not options["--plug"] in result: + fail_usage("Failed: You have to enter existing logical domain!") + else: + return result[options["--plug"]][1] + else: + return result + +def set_power_status(conn, options): + start_communication(conn, options) + + cmd_line = "ldm "+ (options["--action"] == "on" and "start" or "stop -f") + " \"" + options["--plug"] + "\"" + + conn.send_eol(cmd_line) + + conn.log_expect(COMMAND_PROMPT_REG, int(options["--power-timeout"])) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port"] + + atexit.register(atexit_handler) + + all_opt["secure"]["default"] = "1" + all_opt["cmd_prompt"]["default"] = [r"\ $"] + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Sun LDOM" + docs["longdesc"] = "fence_ldom is an I/O Fencing agent \ +which can be used with LDoms virtual machines. This agent works \ +so, that run ldm command on host machine. So ldm must be directly \ +runnable.\ +\n.P\n\ +Very useful parameter is -c (or cmd_prompt in stdin mode). This \ +must be set to something, what is displayed after successful login \ +to host machine. Default string is space on end of string (default \ +for root in bash). But (for example) csh use ], so in that case you \ +must use parameter -c with argument ]. Very similar situation is, \ +if you use bash and login to host machine with other user than \ +root. Than prompt is $, so again, you must use parameter -c." + docs["vendorurl"] = "http://www.sun.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + fence_logout(conn, "logout") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/lindy_pdu/fence_lindypdu.py b/agents/lindy_pdu/fence_lindypdu.py new file mode 100644 index 0000000..432b741 --- /dev/null +++ b/agents/lindy_pdu/fence_lindypdu.py @@ -0,0 +1,206 @@ +#!@PYTHON@ -tt + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see +# <http://www.gnu.org/licenses/>. + +# The Following agent has been tested on: +# Lindy PDU model 32657 +# Firmware release s4.82-091012-1cb08s +# Probably works on different models with same MIB .. but is better test on them +# +# (C) 2021 Daimonlab -- Damiano Scaramuzza (cesello) cesello@daimonlab.it + +import sys +import atexit +import logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage +from fencing_snmp import FencingSnmp + +### CONSTANTS ### +# oid defining fence device +OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' + +### GLOBAL VARIABLES ### +# Device - see Lindy PDU +device = None + +# Port ID +port_id = None +# Switch ID +switch_id = None + +# Classes describing Device params +# Here I follow the MIBS specs that use "switch" and "plug" concepts but +# the pdu really have one switch only and 8-16 plugs. +# Probably the "switch" term is used for future uses or more advanced pdus +class LindyPDU(object): + # PDU + status_oid = '.1.3.6.1.4.1.17420.1.2.9.%d.13.0' + control_oid = '.1.3.6.1.4.1.17420.1.2.9.%d.13.0' + outlet_table_oid = '.1.3.6.1.4.1.17420.1.2.9.%d.14' + pdu_table_oid = '.1.3.6.1.4.1.17420.1.2.9' + attached_pdus = '.1.3.6.1.4.1.17420.1.2.5.0' + ident_str = "Lindy 32657 PDU" + state_on = 1 + state_off = 0 + turn_on = 1 + turn_off = 0 + has_switches = True + +### FUNCTIONS ### +def lpdu_set_device(conn, options): + global device + + agents_dir = {'.1.3.6.1.4.1.17420':LindyPDU} + + # First resolve type of PDU device + pdu_type = conn.walk(OID_SYS_OBJECT_ID) + + if not ((len(pdu_type) == 1) and (pdu_type[0][1] in agents_dir)): + pdu_type = [[None, None]] + + device = agents_dir[pdu_type[0][1]] + + logging.debug("Trying %s"%(device.ident_str)) + +def lpdu_resolv_port_id(conn, options): + + if device == None: + lpdu_set_device(conn, options) + + port_id=switch_id=None + # Now we resolv port_id/switch_id + if options["--plug"].isdigit() and ((not device.has_switches) or (options["--switch"].isdigit())): + port_id = int(options["--plug"]) + + if device.has_switches: + switch_id = int(options["--switch"]) + else: + table = conn.walk(device.pdu_table_oid, 30) + + for x in table: + if x[1].strip('"').split(',')[0] == options["--plug"]: + t = x[0].split('.') + if device.has_switches: + port_id = int(t[len(t)-1]) + switch_id = int(t[len(t)-3]) + else: + port_id = int(t[len(t)-1]) + + if port_id == None: + fail_usage("Can't find port with name %s!"%(options["--plug"])) + + return (switch_id,port_id) + +def get_power_status(conn, options): + + (switch_id,port_id)=lpdu_resolv_port_id(conn, options) + + oid = ((device.has_switches) and device.status_oid%(switch_id) or device.status_oid%(port_id)) + + + try: + (oid, status) = conn.get(oid) + # status is a comma separated string + # one line only as "1,1,1,0,1,1,1,1". + state=status.strip('"').split(',')[port_id-1] + if state == str(device.state_on): + return "on" + elif state == str(device.state_off): + return "off" + else: + return None + except Exception: + return None + +def set_power_status(conn, options): + + (switch_id,port_id)=lpdu_resolv_port_id(conn, options) + + oid = ((device.has_switches) and device.control_oid%(switch_id) or device.control_oid%(port_id)) + + (oid, status) = conn.get(oid) + # status is a comma separated string + state=status.strip('"').split(',') + state[port_id-1]=str((options["--action"] == "on" and device.turn_on or device.turn_off)) + conn.set(oid, ",".join(state)) + + +def get_outlets_status(conn, options): + result = {} + pdu_id=[] + + if device == None: + lpdu_set_device(conn, options) + + if (device.has_switches and options["--switch"].isdigit()): + pdu_id.append(options["--switch"]) + + elif (device.has_switches): + #search for all pdu + pdus=conn.walk(device.attached_pdus, 30) + pdus_info=pdus[0][1].strip('"').split(',') + pdu_id=pdus_info[1:] + else: + #I really don't know what to do with this case. I haven't a different lindy pdu to test + table_oid=device.pdu_table_oid + + + for switch in pdu_id: + table_oid = device.outlet_table_oid % int(switch) + res_ports = conn.walk(table_oid, 30) + status_oid=device.status_oid % int(switch) + port_status=conn.walk(status_oid, 30) + state=port_status[0][1].strip('"').split(',') + for x in res_ports: + t = x[0].split('.') + port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-4], t[len(t)-2]) or "%s"%(t[len(t)-2])) + port_name = x[1].strip('"').split(',')[0] + result[port_num] = (port_name, "on" if state[int(t[len(t)-2])-1]=='1' else "off") + + return result + +# Main agent method +def main(): + global device + + device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ + "port", "snmp_version", "snmp","switch"] + + atexit.register(atexit_handler) + + all_opt["snmp_version"]["default"] = "1" + all_opt["community"]["default"] = "public" + all_opt["switch"]["default"] = "1" + device = LindyPDU + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Lindy over SNMP" + docs["longdesc"] = "fence_lindypdu is an I/O Fencing agent \ +which can be used with the Lindy PDU network power switch. It logs \ +into a device via SNMP and reboots a specified outlet. It supports \ +SNMP v1 with all combinations of authenticity/privacy settings." + docs["vendorurl"] = "http://www.lindy.co.uk" + show_docs(options, docs) + + # Operate the fencing device + result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) +if __name__ == "__main__": + main() diff --git a/agents/lpar/fence_lpar.py b/agents/lpar/fence_lpar.py new file mode 100644 index 0000000..975971a --- /dev/null +++ b/agents/lpar/fence_lpar.py @@ -0,0 +1,197 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## Version +## +---------------------------------------------+ +## Tested on HMC +## +##### + +import sys, re +import atexit +import logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, EC_STATUS_HMC + +## +## Transformation to standard ON/OFF status if possible +def _normalize_status(status): + if status in ["Running", "Open Firmware", "Shutting Down", "Starting"]: + status = "on" + else: + status = "off" + + return status + +def get_power_status(conn, options): + if options["--hmc-version"] == "3": + command = "lssyscfg -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -F name,state\n" + elif options["--hmc-version"] in ["4", "IVM"]: + command = "lssyscfg -r lpar -m "+ options["--managed"] + \ + " --filter 'lpar_names=" + options["--plug"] + "'\n" + else: + # Bad HMC Version cannot be reached + fail(EC_STATUS_HMC) + + conn.send(command) + # First line (command) may cause parsing issues if long + conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + try: + if options["--hmc-version"] == "3": + status = re.compile("^" + options["--plug"] + ",(.*?),.*$", + re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) + elif options["--hmc-version"] in ["4", "IVM"]: + status = re.compile(",state=(.*?),", re.IGNORECASE).search(conn.before).group(1) + except AttributeError as e: + logging.debug("Command on HMC failed: {}\n{}".format(command, str(e))) + fail(EC_STATUS_HMC) + + return _normalize_status(status) + +def is_comanaged(conn, options): + conn.send("lscomgmt -m " + options["--managed"] + "\n" ) + conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + try: + cm = re.compile(",curr_master_mtms=(.*?),", re.IGNORECASE).search(conn.before).group(1) + except AttributeError as e: + cm = False + + return cm + +def set_power_status(conn, options): + if options["--hmc-version"] == "3": + conn.send("chsysstate -o " + options["--action"] + " -r lpar -m " + options["--managed"] + + " -n " + options["--plug"] + "\n") + + # First line (command) may cause parsing issues if long + conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + elif options["--hmc-version"] in ["4", "IVM"]: + if options["--action"] == "on": + if is_comanaged(conn, options): + profile = "" + else: + profile = " -f `lssyscfg -r lpar -F curr_profile " + \ + " -m " + options["--managed"] + \ + " --filter \"lpar_names=" + options["--plug"] + "\"`" + conn.send("chsysstate -o on -r lpar" + + " -m " + options["--managed"] + + " -n " + options["--plug"] + + profile + + "\n") + else: + conn.send("chsysstate -o shutdown -r lpar --immed" + + " -m " + options["--managed"] + " -n " + options["--plug"] + "\n") + + # First line (command) may cause parsing issues if long + conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +def get_lpar_list(conn, options): + outlets = {} + if options["--hmc-version"] == "3": + conn.send("query_partition_names -m " + options["--managed"] + "\n") + + ## We have to remove first line (command) + conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + ## We have to remove next 2 lines (header) and last line (part of new prompt) + #### + res = re.search("^(.+?\n){2}(.*)\n.*$", conn.before, re.S) + + if res == None: + fail_usage("Unable to parse output of list command") + + lines = res.group(2).split("\n") + for outlet_line in lines: + outlets[outlet_line.rstrip()] = ("", "") + elif options["--hmc-version"] in ["4", "IVM"]: + sep = ":" if options["--hmc-version"] == "4" else "," + + conn.send("lssyscfg -r lpar -m " + options["--managed"] + + " -F name" + sep + "state\n") + + ## We have to remove first line (command) + conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + ## We have to remove last line (part of new prompt) + #### + res = re.search("^(.*)\n.*$", conn.before, re.S) + + if res == None: + fail_usage("Unable to parse output of list command") + + lines = res.group(1).split("\n") + for outlet_line in lines: + try: + (port, status) = outlet_line.rstrip().split(sep) + except ValueError: + fail_usage('Output does not match expected HMC version, try different one'); + outlets[port] = ("", _normalize_status(status)) + + return outlets + +def define_new_opts(): + all_opt["managed"] = { + "getopt" : "s:", + "longopt" : "managed", + "help" : "-s, --managed=[id] Name of the managed system", + "required" : "1", + "shortdesc" : "Managed system name", + "order" : 1} + all_opt["hmc_version"] = { + "getopt" : "H:", + "longopt" : "hmc-version", + "help" : "-H, --hmc-version=[version] Force HMC version to use: (3|4|ivm) (default: 4)", + "required" : "0", + "shortdesc" : "Force HMC version to use", + "default" : "4", + "choices" : ["3", "4", "ivm"], + "order" : 1} + +def main(): + device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", \ + "port", "managed", "hmc_version"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["login_timeout"]["default"] = "15" + all_opt["secure"]["default"] = "1" + all_opt["cmd_prompt"]["default"] = [r":~>", r"]\$", r"\$ "] + + options = check_input(device_opt, process_input(device_opt), other_conditions = True) + + docs = {} + docs["shortdesc"] = "Fence agent for IBM LPAR" + docs["longdesc"] = "" + docs["vendorurl"] = "http://www.ibm.com" + show_docs(options, docs) + + if "--managed" not in options: + fail_usage("Failed: You have to enter name of managed system") + + if options["--action"] == "validate-all": + sys.exit(0) + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, get_lpar_list) + fence_logout(conn, "quit\r\n") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/manual/fence_ack_manual.8 b/agents/manual/fence_ack_manual.8 new file mode 100644 index 0000000..6b4cd14 --- /dev/null +++ b/agents/manual/fence_ack_manual.8 @@ -0,0 +1,39 @@ +.TH FENCE_ACK_MANUAL 8 2009-12-21 cluster cluster + +.SH NAME +fence_ack_manual \- a program to override fenced fencing operations + +.SH SYNOPSIS +.B fence_ack_manual +[OPTIONS] +.I nodename + +.SH DESCRIPTION +When +.BR fenced (8) +fails to fence a node, it retries indefinately. +.BR fence_ack_manual (8) +tells fenced to stop retrying and consider the node fenced. + +.P +It is important that this only be done after the node has been manually +turned off or prevented from writing to shared storage. +Without this manual action and verification, the storage that fencing +protects may become corrupted. + +.P +When fenced fences a node that has no fence devices defined in the cluster +configuration, the fencing operation fails. This failure will be repeated +indefinately until fence_ack_manual is run by an operator to indicate +the node is in a safe state to proceed. +(Defining no fencing devices for node is the equivalent of using the +fence_manual agent in previous versions.) + +.SH OPTIONS +.TP +.B \-h +Print a help message describing available options, then exit. + +.SH SEE ALSO +.BR fenced (8) + diff --git a/agents/manual/fence_ack_manual.in b/agents/manual/fence_ack_manual.in new file mode 100644 index 0000000..e8b4998 --- /dev/null +++ b/agents/manual/fence_ack_manual.in @@ -0,0 +1,37 @@ +#!/bin/bash +# +# Manual override after fencing has failed. +# + +if [ "$1" = "-n" ]; then + shift +fi + +if [ -z "$1" ] || [ "${1:0:1}" = "-" ]; then + echo "usage:" + echo " $0 <nodename>" + echo " $0 -n <nodename>" + echo + echo "The -n flag exists to preserve compatibility with previous " + echo "releases of $0, and is no longer required." + exit 1 +fi + +declare answer + +echo "About to override fencing for $1." +echo "Improper use of this command can cause severe file system damage." +echo +read -p "Continue [NO/absolutely]? " answer + +if [ "$answer" != "absolutely" ]; then + echo "Aborted." + exit 1 +fi + +while ! [ -e @clustervarrun@/fenced_override ]; do + sleep 1 +done + +echo $1>@clustervarrun@/fenced_override +echo Done diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py new file mode 100644 index 0000000..ee81eab --- /dev/null +++ b/agents/mpath/fence_mpath.py @@ -0,0 +1,341 @@ +#!@PYTHON@ -tt + +import sys +import stat +import re +import os +import time +import logging +import atexit +import ctypes +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import fail_usage, run_command, atexit_handler, check_input, process_input, show_docs +from fencing import fence_action, all_opt, run_delay + +def get_status(conn, options): + del conn + status = "off" + for dev in options["devices"]: + is_block_device(dev) + if options["--plug"] in get_registration_keys(options, dev): + status = "on" + else: + logging.debug("No registration for key "\ + + options["--plug"] + " on device " + dev + "\n") + + if options["--action"] == "monitor": + dev_read(options) + + return status + + +def set_status(conn, options): + del conn + count = 0 + if options["--action"] == "on": + for dev in options["devices"]: + is_block_device(dev) + + register_dev(options, dev) + if options["--plug"] not in get_registration_keys(options, dev): + count += 1 + logging.debug("Failed to register key "\ + + options["--plug"] + "on device " + dev + "\n") + continue + dev_write(options, dev) + + if get_reservation_key(options, dev) is None \ + and not reserve_dev(options, dev) \ + and get_reservation_key(options, dev) is None: + count += 1 + logging.debug("Failed to create reservation (key="\ + + options["--plug"] + ", device=" + dev + ")\n") + + else: + dev_keys = dev_read(options) + + for dev in options["devices"]: + is_block_device(dev) + + if options["--plug"] in get_registration_keys(options, dev): + preempt_abort(options, dev_keys[dev], dev) + + for dev in options["devices"]: + if options["--plug"] in get_registration_keys(options, dev): + count += 1 + logging.debug("Failed to remove key "\ + + options["--plug"] + " on device " + dev + "\n") + continue + + if not get_reservation_key(options, dev): + count += 1 + logging.debug("No reservation exists on device " + dev + "\n") + if count: + logging.error("Failed to verify " + str(count) + " device(s)") + sys.exit(1) + + +# run command, returns dict, ret["rc"] = exit code; ret["out"] = output; +# ret["err"] = error +def run_cmd(options, cmd): + ret = {} + + if "--use-sudo" in options: + prefix = options["--sudo-path"] + " " + else: + prefix = "" + + (ret["rc"], ret["out"], ret["err"]) = run_command(options, + prefix + cmd) + ret["out"] = "".join([i for i in ret["out"] if i is not None]) + ret["err"] = "".join([i for i in ret["err"] if i is not None]) + return ret + + +# check if device exist and is block device +def is_block_device(dev): + if not os.path.exists(dev): + fail_usage("Failed: device \"" + dev + "\" does not exist") + if not stat.S_ISBLK(os.stat(dev).st_mode): + fail_usage("Failed: device \"" + dev + "\" is not a block device") + +# cancel registration +def preempt_abort(options, host, dev): + cmd = options["--mpathpersist-path"] + " -o --preempt-abort --prout-type=5 --param-rk=" + host +" --param-sark=" + options["--plug"] +" -d " + dev + return not bool(run_cmd(options, cmd)["rc"]) + +def register_dev(options, dev): + cmd = options["--mpathpersist-path"] + " -o --register --param-sark=" + options["--plug"] + " -d " + dev + #cmd return code != 0 but registration can be successful + return not bool(run_cmd(options, cmd)["rc"]) + +def reserve_dev(options, dev): + cmd = options["--mpathpersist-path"] + " -o --reserve --prout-type=5 --param-rk=" + options["--plug"] + " -d " + dev + return not bool(run_cmd(options, cmd)["rc"]) + +def get_reservation_key(options, dev): + cmd = options["--mpathpersist-path"] + " -i -r -d " + dev + out = run_cmd(options, cmd) + if out["rc"]: + fail_usage('Cannot get reservation key on device "' + dev + + '": ' + out["err"]) + match = re.search(r"\s+key\s*=\s*0x(\S+)\s+", out["out"], re.IGNORECASE) + return match.group(1) if match else None + +def get_registration_keys(options, dev, fail=True): + keys = [] + cmd = options["--mpathpersist-path"] + " -i -k -d " + dev + out = run_cmd(options, cmd) + if out["rc"]: + fail_usage('Cannot get registration keys on device "' + dev + + '": ' + out["err"], fail) + if not fail: + return [] + for line in out["out"].split("\n"): + match = re.search(r"\s+0x(\S+)\s*", line) + if match: + keys.append(match.group(1)) + return keys + +def dev_write(options, dev): + file_path = options["--store-path"] + "/mpath.devices" + + if not os.path.isdir(options["--store-path"]): + os.makedirs(options["--store-path"]) + + try: + store_fh = open(file_path, "a+") + except IOError: + fail_usage("Failed: Cannot open file \""+ file_path + "\"") + out = store_fh.read() + if not re.search(r"^" + dev + r"\s+", out): + store_fh.write(dev + "\t" + options["--plug"] + "\n") + store_fh.close() + +def dev_read(options, fail=True): + dev_key = {} + file_path = options["--store-path"] + "/mpath.devices" + try: + store_fh = open(file_path, "r") + except IOError: + if fail: + fail_usage("Failed: Cannot open file \"" + file_path + "\"") + else: + return None + # get not empty lines from file + for (device, key) in [line.strip().split() for line in store_fh if line.strip()]: + dev_key[device] = key + store_fh.close() + return dev_key + +def mpath_check_get_options(options): + try: + f = open("/etc/sysconfig/stonith", "r") + except IOError: + return options + + match = re.findall(r"^\s*(\S*)\s*=\s*(\S*)\s*", "".join(f.readlines()), re.MULTILINE) + + for m in match: + options[m[0].lower()] = m[1].lower() + + f.close() + + return options + +def mpath_check(hardreboot=False): + if len(sys.argv) >= 3 and sys.argv[1] == "repair": + return int(sys.argv[2]) + options = {} + options["--mpathpersist-path"] = "/usr/sbin/mpathpersist" + options["--store-path"] = "@STORE_PATH@" + options["--power-timeout"] = "5" + options["retry"] = "0" + options["retry-sleep"] = "1" + options = mpath_check_get_options(options) + if "verbose" in options and options["verbose"] == "yes": + logging.getLogger().setLevel(logging.DEBUG) + devs = dev_read(options, fail=False) + if not devs: + if "--suppress-errors" not in options: + logging.error("No devices found") + return 0 + for dev, key in list(devs.items()): + for n in range(int(options["retry"]) + 1): + if n > 0: + logging.debug("retry: " + str(n) + " of " + options["retry"]) + if key in get_registration_keys(options, dev, fail=False): + logging.debug("key " + key + " registered with device " + dev) + return 0 + else: + logging.debug("key " + key + " not registered with device " + dev) + + if n < int(options["retry"]): + time.sleep(float(options["retry-sleep"])) + logging.debug("key " + key + " registered with any devices") + + if hardreboot == True: + libc = ctypes.cdll['libc.so.6'] + libc.reboot(0x1234567) + return 2 + +def define_new_opts(): + all_opt["devices"] = { + "getopt" : "d:", + "longopt" : "devices", + "help" : "-d, --devices=[devices] List of devices to use for current operation", + "required" : "0", + "shortdesc" : "List of devices to use for current operation. Devices can \ +be comma-separated list of device-mapper multipath devices (eg. /dev/mapper/3600508b400105df70000e00000ac0000 or /dev/mapper/mpath1). \ +Each device must support SCSI-3 persistent reservations.", + "order": 1 + } + all_opt["key"] = { + "getopt" : "k:", + "longopt" : "key", + "help" : "-k, --key=[key] Replaced by -n, --plug", + "required" : "0", + "shortdesc" : "Replaced by port/-n/--plug", + "order": 1 + } + all_opt["suppress-errors"] = { + "getopt" : "", + "longopt" : "suppress-errors", + "help" : "--suppress-errors Suppress error log. Suppresses error logging when run from the watchdog service before pacemaker starts.", + "required" : "0", + "shortdesc" : "Error log suppression.", + "order": 4 + } + all_opt["mpathpersist_path"] = { + "getopt" : ":", + "longopt" : "mpathpersist-path", + "help" : "--mpathpersist-path=[path] Path to mpathpersist binary", + "required" : "0", + "shortdesc" : "Path to mpathpersist binary", + "default" : "@MPATH_PATH@", + "order": 200 + } + all_opt["store_path"] = { + "getopt" : ":", + "longopt" : "store-path", + "help" : "--store-path=[path] Path to directory containing cached keys", + "required" : "0", + "shortdesc" : "Path to directory where fence agent can store information", + "default" : "@STORE_PATH@", + "order": 200 + } + +def main(): + atexit.register(atexit_handler) + + device_opt = ["no_login", "no_password", "devices", "key", "sudo", \ + "fabric_fencing", "on_target", "store_path", \ + "suppress-errors", "mpathpersist_path", "force_on", "port", "no_port"] + + define_new_opts() + + all_opt["port"]["required"] = "0" + all_opt["port"]["help"] = "-n, --plug=[key] Key to use for the current operation" + all_opt["port"]["shortdesc"] = "Key to use for the current operation. \ +This key should be unique to a node and have to be written in \ +/etc/multipath.conf. For the \"on\" action, the key specifies the key use to \ +register the local node. For the \"off\" action, this key specifies the key to \ +be removed from the device(s)." + + # fence_mpath_check + if os.path.basename(sys.argv[0]) == "fence_mpath_check": + sys.exit(mpath_check()) + elif os.path.basename(sys.argv[0]) == "fence_mpath_check_hardreboot": + sys.exit(mpath_check(hardreboot=True)) + + options = check_input(device_opt, process_input(device_opt), other_conditions=True) + + # hack to remove list/list-status actions which are not supported + options["device_opt"] = [ o for o in options["device_opt"] if o != "separator" ] + + # workaround to avoid regressions + if "--key" in options: + options["--plug"] = options["--key"] + del options["--key"] + elif "--help" not in options and options["--action"] in ["off", "on", \ + "reboot", "status", "validate-all"] and "--plug" not in options: + stop_after_error = False if options["--action"] == "validate-all" else True + fail_usage("Failed: You have to enter plug number or machine identification", stop_after_error) + + docs = {} + docs["shortdesc"] = "Fence agent for multipath persistent reservation" + docs["longdesc"] = "fence_mpath is an I/O fencing agent that uses SCSI-3 \ +persistent reservations to control access multipath devices. Underlying \ +devices must support SCSI-3 persistent reservations (SPC-3 or greater) as \ +well as the \"preempt-and-abort\" subcommand.\nThe fence_mpath agent works by \ +having a unique key for each node that has to be set in /etc/multipath.conf. \ +Once registered, a single node will become the reservation holder \ +by creating a \"write exclusive, registrants only\" reservation on the \ +device(s). The result is that only registered nodes may write to the \ +device(s). When a node failure occurs, the fence_mpath agent will remove the \ +key belonging to the failed node from the device(s). The failed node will no \ +longer be able to write to the device(s). A manual reboot is required.\ +\n.P\n\ +When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and \ +verbose=yes parameters in /etc/sysconfig/stonith if you have issues with it \ +failing." + docs["vendorurl"] = "https://www.sourceware.org/dm/" + show_docs(options, docs) + + run_delay(options) + + # Input control BEGIN + if options["--action"] == "validate-all": + sys.exit(0) + + if not ("--devices" in options and options["--devices"]): + fail_usage("Failed: No devices found") + + options["devices"] = [d for d in re.split("\s*,\s*|\s+", options["--devices"].strip()) if d] + # Input control END + + result = fence_action(None, options, set_status, get_status) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/netio/fence_netio.py b/agents/netio/fence_netio.py new file mode 100755 index 0000000..4fb59cf --- /dev/null +++ b/agents/netio/fence_netio.py @@ -0,0 +1,94 @@ +#!@PYTHON@ -tt + +import sys, re, pexpect +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fspawn, fail, EC_LOGIN_DENIED, run_delay + +def get_power_status(conn, options): + conn.send_eol("port %s" % options["--plug"]) + re_status = re.compile("250 [01imt]") + conn.log_expect(re_status, int(options["--shell-timeout"])) + status = { + "0" : "off", + "1" : "on", + "i" : "reboot", + "m" : "manual", + "t" : "timer" + }[conn.after.split()[1]] + + return status + +def set_power_status(conn, options): + action = { + "on" : "1", + "off" : "0", + "reboot" : "i" + }[options["--action"]] + + conn.send_eol("port %s %s" % (options["--plug"], action)) + conn.log_expect("250 OK", int(options["--shell-timeout"])) + +def get_outlet_list(conn, options): + result = {} + + try: + # the NETIO-230B has 4 ports, counting start at 1 + for plug in ["1", "2", "3", "4"]: + conn.send_eol("port setup %s" % plug) + conn.log_expect("250 .+", int(options["--shell-timeout"])) + # the name is enclosed in "", drop those with [1:-1] + name = conn.after.split()[1][1:-1] + result[plug] = (name, "unknown") + except Exception as exn: + print(str(exn)) + + return result + +def main(): + device_opt = ["ipaddr", "login", "passwd", "port", "telnet"] + + atexit.register(atexit_handler) + + all_opt["ipport"]["default"] = "1234" + + opt = process_input(device_opt) + opt["eol"] = "\r\n" + options = check_input(device_opt, opt) + + docs = {} + docs["shortdesc"] = "I/O Fencing agent for Koukaam NETIO-230B" + docs["longdesc"] = "fence_netio is an I/O Fencing agent which can be \ +used with the Koukaam NETIO-230B Power Distribution Unit. It logs into \ +device via telnet and reboots a specified outlet. Lengthy telnet connections \ +should be avoided while a GFS cluster is running because the connection will \ +block any necessary fencing actions." + docs["vendorurl"] = "http://www.koukaam.se/" + show_docs(options, docs) + + ## + ## Operate the fencing device + ## We can not use fence_login(), username and passwd are sent on one line + #### + run_delay(options) + try: + conn = fspawn(options, options["--telnet-path"]) + conn.send("set binary\n") + conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) + + conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) + conn.log_expect("100 HELLO .*", int(options["--shell-timeout"])) + conn.send_eol("login %s %s" % (options["--username"], options["--password"])) + conn.log_expect("250 OK", int(options["--shell-timeout"])) + except pexpect.EOF: + fail(EC_LOGIN_DENIED) + except pexpect.TIMEOUT: + fail(EC_LOGIN_DENIED) + + result = fence_action(conn, options, set_power_status, get_power_status, get_outlet_list) + fence_logout(conn, "quit\n") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/openstack/fence_openstack.py b/agents/openstack/fence_openstack.py new file mode 100644 index 0000000..666016d --- /dev/null +++ b/agents/openstack/fence_openstack.py @@ -0,0 +1,381 @@ +#!@PYTHON@ -tt + +import atexit +import logging +import sys +import os + +import urllib3 + +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage, run_delay, source_env + +try: + from novaclient import client + from novaclient.exceptions import Conflict, NotFound +except ImportError: + pass + +urllib3.disable_warnings(urllib3.exceptions.SecurityWarning) + + +def translate_status(instance_status): + if instance_status == "ACTIVE": + return "on" + elif instance_status == "SHUTOFF": + return "off" + return "unknown" + +def get_cloud(options): + import yaml + + clouds_yaml = "~/.config/openstack/clouds.yaml" + if not os.path.exists(os.path.expanduser(clouds_yaml)): + clouds_yaml = "/etc/openstack/clouds.yaml" + if not os.path.exists(os.path.expanduser(clouds_yaml)): + fail_usage("Failed: ~/.config/openstack/clouds.yaml and /etc/openstack/clouds.yaml does not exist") + + clouds_yaml = os.path.expanduser(clouds_yaml) + if os.path.exists(clouds_yaml): + with open(clouds_yaml, "r") as yaml_stream: + try: + clouds = yaml.safe_load(yaml_stream) + except yaml.YAMLError as exc: + fail_usage("Failed: Unable to read: " + clouds_yaml) + + cloud = clouds.get("clouds").get(options["--cloud"]) + if not cloud: + fail_usage("Cloud: {} not found.".format(options["--cloud"])) + + return cloud + + +def get_nodes_list(conn, options): + logging.info("Running %s action", options["--action"]) + result = {} + response = conn.servers.list(detailed=True) + if response is not None: + for item in response: + instance_id = item.id + instance_name = item.name + instance_status = item.status + result[instance_id] = (instance_name, translate_status(instance_status)) + return result + + +def get_power_status(conn, options): + logging.info("Running %s action on %s", options["--action"], options["--plug"]) + server = None + try: + server = conn.servers.get(options["--plug"]) + except NotFound as e: + fail_usage("Failed: Not Found: " + str(e)) + if server is None: + fail_usage("Server %s not found", options["--plug"]) + state = server.status + status = translate_status(state) + logging.info("get_power_status: %s (state: %s)" % (status, state)) + return status + + +def set_power_status(conn, options): + logging.info("Running %s action on %s", options["--action"], options["--plug"]) + action = options["--action"] + server = None + try: + server = conn.servers.get(options["--plug"]) + except NotFound as e: + fail_usage("Failed: Not Found: " + str(e)) + if server is None: + fail_usage("Server %s not found", options["--plug"]) + if action == "on": + logging.info("Starting instance " + server.name) + try: + server.start() + except Conflict as e: + fail_usage(e) + logging.info("Called start API call for " + server.id) + if action == "off": + logging.info("Stopping instance " + server.name) + try: + server.stop() + except Conflict as e: + fail_usage(e) + logging.info("Called stop API call for " + server.id) + if action == "reboot": + logging.info("Rebooting instance " + server.name) + try: + server.reboot("HARD") + except Conflict as e: + fail_usage(e) + logging.info("Called reboot hard API call for " + server.id) + + +def nova_login(username, password, projectname, auth_url, user_domain_name, + project_domain_name, ssl_insecure, cacert, apitimeout): + legacy_import = False + + try: + from keystoneauth1 import loading + from keystoneauth1 import session as ksc_session + from keystoneauth1.exceptions.discovery import DiscoveryFailure + from keystoneauth1.exceptions.http import Unauthorized + except ImportError: + try: + from keystoneclient import session as ksc_session + from keystoneclient.auth.identity import v3 + + legacy_import = True + except ImportError: + fail_usage("Failed: Keystone client not found or not accessible") + + if not legacy_import: + loader = loading.get_plugin_loader("password") + auth = loader.load_from_options( + auth_url=auth_url, + username=username, + password=password, + project_name=projectname, + user_domain_name=user_domain_name, + project_domain_name=project_domain_name, + ) + else: + auth = v3.Password( + auth_url=auth_url, + username=username, + password=password, + project_name=projectname, + user_domain_name=user_domain_name, + project_domain_name=project_domain_name, + cacert=cacert, + ) + + caverify=True + if ssl_insecure: + caverify=False + elif cacert: + caverify=cacert + + session = ksc_session.Session(auth=auth, verify=caverify, timeout=apitimeout) + nova = client.Client("2", session=session, timeout=apitimeout) + apiversion = None + try: + apiversion = nova.versions.get_current() + except DiscoveryFailure as e: + fail_usage("Failed: Discovery Failure: " + str(e)) + except Unauthorized as e: + fail_usage("Failed: Unauthorized: " + str(e)) + except Exception as e: + logging.error(e) + logging.debug("Nova version: %s", apiversion) + return nova + + +def define_new_opts(): + all_opt["auth-url"] = { + "getopt": ":", + "longopt": "auth-url", + "help": "--auth-url=[authurl] Keystone Auth URL", + "required": "0", + "shortdesc": "Keystone Auth URL", + "order": 2, + } + all_opt["project-name"] = { + "getopt": ":", + "longopt": "project-name", + "help": "--project-name=[project] Tenant Or Project Name", + "required": "0", + "shortdesc": "Keystone Project", + "default": "admin", + "order": 3, + } + all_opt["user-domain-name"] = { + "getopt": ":", + "longopt": "user-domain-name", + "help": "--user-domain-name=[domain] Keystone User Domain Name", + "required": "0", + "shortdesc": "Keystone User Domain Name", + "default": "Default", + "order": 4, + } + all_opt["project-domain-name"] = { + "getopt": ":", + "longopt": "project-domain-name", + "help": "--project-domain-name=[domain] Keystone Project Domain Name", + "required": "0", + "shortdesc": "Keystone Project Domain Name", + "default": "Default", + "order": 5, + } + all_opt["cloud"] = { + "getopt": ":", + "longopt": "cloud", + "help": "--cloud=[cloud] Openstack cloud (from ~/.config/openstack/clouds.yaml or /etc/openstack/clouds.yaml).", + "required": "0", + "shortdesc": "Cloud from clouds.yaml", + "order": 6, + } + all_opt["openrc"] = { + "getopt": ":", + "longopt": "openrc", + "help": "--openrc=[openrc] Path to the openrc config file", + "required": "0", + "shortdesc": "openrc config file", + "order": 7, + } + all_opt["uuid"] = { + "getopt": ":", + "longopt": "uuid", + "help": "--uuid=[uuid] Replaced by -n, --plug", + "required": "0", + "shortdesc": "Replaced by port/-n/--plug", + "order": 8, + } + all_opt["cacert"] = { + "getopt": ":", + "longopt": "cacert", + "help": "--cacert=[cacert] Path to the PEM file with trusted authority certificates (override global CA trust)", + "required": "0", + "shortdesc": "SSL X.509 certificates file", + "default": "", + "order": 9, + } + all_opt["apitimeout"] = { + "getopt": ":", + "type": "second", + "longopt": "apitimeout", + "help": "--apitimeout=[seconds] Timeout to use for API calls", + "shortdesc": "Timeout in seconds to use for API calls, default is 60.", + "required": "0", + "default": 60, + "order": 10, + } + + +def main(): + conn = None + + device_opt = [ + "login", + "no_login", + "passwd", + "no_password", + "auth-url", + "project-name", + "user-domain-name", + "project-domain-name", + "cloud", + "openrc", + "port", + "no_port", + "uuid", + "ssl_insecure", + "cacert", + "apitimeout", + ] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["port"]["required"] = "0" + all_opt["port"]["help"] = "-n, --plug=[UUID] UUID of the node to be fenced" + all_opt["port"]["shortdesc"] = "UUID of the node to be fenced." + all_opt["power_timeout"]["default"] = "60" + + options = check_input(device_opt, process_input(device_opt)) + + # workaround to avoid regressions + if "--uuid" in options: + options["--plug"] = options["--uuid"] + del options["--uuid"] + elif ("--help" not in options + and options["--action"] in ["off", "on", "reboot", "status", "validate-all"] + and "--plug" not in options): + stop_after_error = False if options["--action"] == "validate-all" else True + fail_usage( + "Failed: You have to enter plug number or machine identification", + stop_after_error, + ) + + docs = {} + docs["shortdesc"] = "Fence agent for OpenStack's Nova service" + docs["longdesc"] = "fence_openstack is a Fencing agent \ +which can be used with machines controlled by the Openstack's Nova service. \ +This agent calls the python-novaclient and it is mandatory to be installed " + docs["vendorurl"] = "https://wiki.openstack.org/wiki/Nova" + show_docs(options, docs) + + run_delay(options) + + if options.get("--cloud"): + cloud = get_cloud(options) + username = cloud.get("auth").get("username") + password = cloud.get("auth").get("password") + projectname = cloud.get("auth").get("project_name") + auth_url = None + try: + auth_url = cloud.get("auth").get("auth_url") + except KeyError: + fail_usage("Failed: You have to set the Keystone service endpoint for authorization") + user_domain_name = cloud.get("auth").get("user_domain_name") + project_domain_name = cloud.get("auth").get("project_domain_name") + caverify = cloud.get("verify") + if caverify in [True, False]: + options["--ssl-insecure"] = caverify + else: + options["--cacert"] = caverify + elif options.get("--openrc"): + if not os.path.exists(os.path.expanduser(options["--openrc"])): + fail_usage("Failed: {} does not exist".format(options.get("--openrc"))) + source_env(options["--openrc"]) + env = os.environ + username = env.get("OS_USERNAME") + password = env.get("OS_PASSWORD") + projectname = env.get("OS_PROJECT_NAME") + auth_url = None + try: + auth_url = env["OS_AUTH_URL"] + except KeyError: + fail_usage("Failed: You have to set the Keystone service endpoint for authorization") + user_domain_name = env.get("OS_USER_DOMAIN_NAME") + project_domain_name = env.get("OS_PROJECT_DOMAIN_NAME") + else: + username = options["--username"] + password = options["--password"] + projectname = options["--project-name"] + auth_url = None + try: + auth_url = options["--auth-url"] + except KeyError: + fail_usage("Failed: You have to set the Keystone service endpoint for authorization") + user_domain_name = options["--user-domain-name"] + project_domain_name = options["--project-domain-name"] + + ssl_insecure = "--ssl-insecure" in options + cacert = options["--cacert"] + apitimeout = options["--apitimeout"] + + try: + conn = nova_login( + username, + password, + projectname, + auth_url, + user_domain_name, + project_domain_name, + ssl_insecure, + cacert, + apitimeout, + ) + except Exception as e: + fail_usage("Failed: Unable to connect to Nova: " + str(e)) + + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) + sys.exit(result) + + +if __name__ == "__main__": + main() diff --git a/agents/ovh/fence_ovh.py b/agents/ovh/fence_ovh.py new file mode 100644 index 0000000..2b7eb86 --- /dev/null +++ b/agents/ovh/fence_ovh.py @@ -0,0 +1,164 @@ +#!@PYTHON@ -tt +# Copyright 2013 Adrian Gibanel Lopez (bTactic) +# Adrian Gibanel improved this script at 2013 to add verification of success and to output metadata + +# Based on: +# This is a fence agent for use at OVH +# As there are no other fence devices available, we must use OVH's SOAP API #Quick-and-dirty +# assemled by Dennis Busch, secofor GmbH, Germany +# This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. + +import sys, time +import shutil, tempfile +import logging +import atexit +from datetime import datetime +from suds.client import Client +from suds.xsd.doctor import ImportDoctor, Import +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, EC_LOGIN_DENIED, run_delay + +OVH_RESCUE_PRO_NETBOOT_ID = '28' +OVH_HARD_DISK_NETBOOT_ID = '1' + +STATUS_HARD_DISK_SLEEP = 240 # Wait 4 minutes to SO to boot +STATUS_RESCUE_PRO_SLEEP = 150 # Wait 2 minutes 30 seconds to Rescue-Pro to run + +def define_new_opts(): + all_opt["email"] = { + "getopt" : "Z:", + "longopt" : "email", + "help" : "-Z, --email=[email] email for reboot message: admin@domain.com", + "required" : "1", + "shortdesc" : "Reboot email", + "order" : 1} + +def netboot_reboot(conn, options, mode): + # dedicatedNetbootModifyById changes the mode of the next reboot + conn.service.dedicatedNetbootModifyById(options["session"], options["--plug"], mode, '', options["--email"]) + + # dedicatedHardRebootDo initiates a hard reboot on the given node + conn.service.dedicatedHardRebootDo(options["session"], + options["--plug"], 'Fencing initiated by cluster', '', 'en') + + conn.logout(options["session"]) + +def reboot_time(conn, options): + result = conn.service.dedicatedHardRebootStatus(options["session"], options["--plug"]) + tmpstart = datetime.strptime(result.start, '%Y-%m-%d %H:%M:%S') + tmpend = datetime.strptime(result.end, '%Y-%m-%d %H:%M:%S') + result.start = tmpstart + result.end = tmpend + + return result + +def soap_login(options): + imp = Import('http://schemas.xmlsoap.org/soap/encoding/') + url = 'https://www.ovh.com/soapi/soapi-re-1.59.wsdl' + imp.filter.add('http://soapi.ovh.com/manager') + d = ImportDoctor(imp) + + tmp_dir = tempfile.mkdtemp() + tempfile.tempdir = tmp_dir + atexit.register(remove_tmp_dir, tmp_dir) + + try: + soap = Client(url, doctor=d) + session = soap.service.login(options["--username"], options["--password"], 'en', 0) + except Exception as e: + logging.error("Failed: {}".format(str(e))) + fail(EC_LOGIN_DENIED) + + options["session"] = session + return soap + +def remove_tmp_dir(tmp_dir): + shutil.rmtree(tmp_dir) + +def main(): + device_opt = ["login", "passwd", "port", "email", "no_status", "web"] + + atexit.register(atexit_handler) + + define_new_opts() + options = check_input(device_opt, process_input(device_opt), other_conditions=True) + + docs = {} + docs["shortdesc"] = "Fence agent for OVH" + docs["longdesc"] = "fence_ovh is an Power Fencing agent \ +which can be used within OVH datecentre. \ +Poweroff is simulated with a reboot into rescue-pro mode." + + docs["vendorurl"] = "http://www.ovh.net" + show_docs(options, docs) + + if options["--action"] == "list": + fail_usage("Action 'list' is not supported in this fence agent") + + if options["--action"] == "list-status": + fail_usage("Action 'list-status' is not supported in this fence agent") + + if "--email" not in options: + fail_usage("You have to enter e-mail address which is notified by fence agent") + + if options["--action"] == "validate-all": + sys.exit(0) + + if options["--action"] != "monitor" and not options["--plug"].endswith(".ovh.net"): + options["--plug"] += ".ovh.net" + + run_delay(options) + + conn = soap_login(options) + + if options["--action"] == 'monitor': + try: + conn.service.logout(options["session"]) + except Exception: + pass + sys.exit(0) + + # Save datetime just before changing netboot + before_netboot_reboot = datetime.now() + + if options["--action"] == 'off': + # Reboot in Rescue-pro + netboot_reboot(conn, options, OVH_RESCUE_PRO_NETBOOT_ID) + time.sleep(STATUS_RESCUE_PRO_SLEEP) + elif options["--action"] in ['on', 'reboot']: + # Reboot from HD + netboot_reboot(conn, options, OVH_HARD_DISK_NETBOOT_ID) + time.sleep(STATUS_HARD_DISK_SLEEP) + + # Save datetime just after reboot + after_netboot_reboot = datetime.now() + + # Verify that action was completed sucesfully + reboot_t = reboot_time(conn, options) + + logging.debug("reboot_start_end.start: %s\n", + reboot_t.start.strftime('%Y-%m-%d %H:%M:%S')) + logging.debug("before_netboot_reboot: %s\n", + before_netboot_reboot.strftime('%Y-%m-%d %H:%M:%S')) + logging.debug("reboot_start_end.end: %s\n", + reboot_t.end.strftime('%Y-%m-%d %H:%M:%S')) + logging.debug("after_netboot_reboot: %s\n", + after_netboot_reboot.strftime('%Y-%m-%d %H:%M:%S')) + + if reboot_t.start < after_netboot_reboot < reboot_t.end: + result = 0 + logging.debug("Netboot reboot went OK.\n") + else: + result = 1 + logging.debug("ERROR: Netboot reboot wasn't OK.\n") + + try: + conn.service.logout(options["session"]) + except Exception: + pass + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/powerman/fence_powerman.py b/agents/powerman/fence_powerman.py new file mode 100755 index 0000000..7aeeaf1 --- /dev/null +++ b/agents/powerman/fence_powerman.py @@ -0,0 +1,257 @@ +#!@PYTHON@ -tt +import os +import time +from datetime import datetime +import sys +import subprocess +import re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import is_executable, fail_usage, run_delay +import logging + +#### important!!! ####### +class PowerMan: + """Python wrapper for calling powerman commands + + This class makes calls to a powerman deamon for a cluster of computers. + The make-up of such a call looks something like: + $ pm -h elssd1:10101 <option> <node> + where option is something like --off, --on, --cycle and where node is + elssd8, or whatever values are setup in powerman.conf. Note that powerman + itself must be configured for this fence agent to work. + """ + + def __init__(self, powerman_path, server_name, port): + """ + Args: + server_name: (string) host or ip of powerman server + port: (str) port number that the powerman server is listening on + """ + self.powerman_path = powerman_path + self.server_name = server_name + self.port = port + self.server_and_port = server_name + ":" + str(port) + self.base_cmd = [ + self.powerman_path, + "--server-host", + self.server_and_port + ] + + def _run(self, cmd, only_first_line): + # Args: + # cmd: (list) commands and arguments to pass to the program_name + + run_this = self.base_cmd + cmd + try: + popen = subprocess.Popen(run_this, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + out = popen.communicate() + except OSError as e: + logging.error("_run command error: %s\n", e) + sys.exit(1) + if only_first_line == True: + result_line = out[0].decode().strip() + return (result_line, popen.returncode) + else: + result_list = [] + for line in out: + result_list.append(line) + return (result_list, popen.returncode) + + def is_running(self): + """simple query to see if powerman server is responding. Returns boolean""" + cmd = ["-q"] # just check if we get a response from the server + result, ret_code = self._run(cmd, True) + if ret_code != 0: + return False + return True + + ## Some devices respond to on or off actions as if the action was successful, + ## when it was not. + ## + ## This is not unique to powerman, and so fence_action ignores the return code + ## from the set_power_fn and queries the device to confirm the power status of + ## the machine. + ## + ## For this reason we do not do a query ourself, retry, etc. in on() or off(). + + def on(self, host): + logging.debug("PowerMan on: %s\n", host) + cmd = ["--on", host] + try: + result, ret_code = self._run(cmd, True) + except OSError as e: + logging.error("PowerMan Error: The command '--on' failed: %s\n", e) + return -1 + except ValueError as e: + logging.error("PowerMan Error: Popen: invalid arguments: %s\n", e) + return -1 + logging.debug("pm.on result: %s ret_code: %s\n", result, ret_code) + + return ret_code + + def off(self, host): + logging.debug("PowerMan off: %s\n", host) + cmd = ["--off", host] + try: + result, ret_code = self._run(cmd, True) + except OSError as e: + logging.error("PowerMan Error: The command '%s' failed: %s\n", cmd, e) + return -1 + except ValueError as e: + logging.error("PowerMan Error: Popen: invalid arguments: %s\n", e) + return -1 + logging.debug("pm.off result: %s ret_code: %s\n", result, ret_code) + + return ret_code + + def list(self): + ## Error checking here is faulty. Try passing + ## invalid args, e.g. --query --exprange to see failure + cmd = ["-q","--exprange"] + try: + result, ret_code = self._run(cmd, False) + except OSError as e: + logging.error("PowerMan Error: The command '%s' failed: %s\n", cmd, e) + return -1 + except ValueError as e: + logging.error("PowerMan Error: Popen: invalid arguments: %s\n", e) + return -1 + if ret_code < 0: + # there was an error with the command + return ret_code + else: + state = {} + for line in result[0].split('\n'): + if len(line) > 2: + fields = line.split(':') + if len(fields) == 2: + state[fields[0]] = (fields[0],fields[1]) + return state + + def query(self, host): + cmd = ["--query", host] + try: + result, ret_code = self._run(cmd, True) + except OSError as e: + logging.error("PowerMan Error: The command '%s' failed: %s\n", cmd, e) + return -1 + except ValueError as e: + logging.error("PowerMan Error: Popen: invalid arguments: %s\n", e) + return -1 + if ret_code < 0: + # there was an error with the command + return ret_code + else: + res = result.split('\n') + res = [r.split() for r in res] + # find the host in command's returned output + for lst in res: + if lst[0] == 'No' and lst[1] == 'such' and lst[2] == 'nodes:': + return -1 + if host in lst: + return lst[0][:-1] # lst[0] would be 'off:'-- this removes the colon + # host isn't in the output + return -1 + + +def get_power_status(conn, options): + logging.debug("get_power_status function:\noptions: %s\n", str(options)) + pm = PowerMan(options['--powerman-path'], options['--ip'], options['--ipport']) + # if Pacemaker is checking the status of the Powerman server... + if options['--action'] == 'monitor': + if pm.is_running(): + logging.debug("Powerman is running\n") + return "on" + logging.debug("Powerman is NOT running\n") + return "error" + else: + status = pm.query(options['--plug']) + if isinstance(int, type(status)): + # query only returns ints on error + logging.error("get_power_status: query returned %s\n", str(status)) + fail(EC_STATUS) + return status + + +def set_power_status(conn, options): + logging.debug("set_power_status function:\noptions: %s", str(options)) + pm = PowerMan(options['--powerman-path'], options['--ip'], options['--ipport']) + + action = options["--action"] + if action == "on": + pm.on(options['--plug']) + elif action == "off": + pm.off(options['--plug']) + + return + + +def get_list(conn, options): + logging.debug("get_list function:\noptions: %s", str(options)) + pm = PowerMan(options['--powerman-path'], options['--ip'], options['--ipport']) + + outlets = pm.list() + logging.debug("get_list outlets.keys: %s", str(outlets.keys())) + return outlets + + +def define_new_opts(): + all_opt["powerman_path"] = { + "getopt" : ":", + "longopt" : "powerman-path", + "help" : "--powerman-path=[path] Path to powerman binary", + "required" : "0", + "shortdesc" : "Path to powerman binary", + "default" : "@POWERMAN_PATH@", + "order": 200 + } + + +def main(): + device_opt = [ + 'ipaddr', + 'no_password', + 'no_login', + 'powerman_path', + ] + + atexit.register(atexit_handler) + + define_new_opts() + + # redefine default values for the options given by fencing.py + # these 3 different values are derived from the lssd test cluster and may + # need to adjusted depending on how other systems fare + all_opt['ipport']['default'] = '10101' + all_opt['delay']['default'] = '3' + all_opt['power_wait']['default'] = '3' + + options = check_input(device_opt, process_input(device_opt)) + docs = {} + docs["shortdesc"] = "Fence Agent for Powerman" + docs["longdesc"] = "This is a Pacemaker Fence Agent for the \ +Powerman management utility that was designed for LLNL systems." + docs["vendorurl"] = "https://github.com/chaos/powerman" + show_docs(options, docs) + + run_delay(options) + + if not is_executable(options["--powerman-path"]): + fail_usage("Powerman not found or not executable at path " + options["--powerman-path"]) + + # call the fencing.fence_action function, passing in my various fence functions + result = fence_action( + None, + options, + set_power_status, + get_power_status, + get_list, + None + ) + sys.exit(result) + + +if __name__ == "__main__": + main() diff --git a/agents/pve/fence_pve.py b/agents/pve/fence_pve.py new file mode 100755 index 0000000..0d82035 --- /dev/null +++ b/agents/pve/fence_pve.py @@ -0,0 +1,240 @@ +#!@PYTHON@ -tt + +# This agent uses Proxmox VE API +# Thanks to Frank Brendel (author of original perl fence_pve) +# for help with writing and testing this agent. + +import sys +import json +import pycurl +import io +import atexit +import logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import fail, fail_usage, EC_LOGIN_DENIED, atexit_handler, all_opt, check_input, process_input, show_docs, fence_action, run_delay + +if sys.version_info[0] > 2: import urllib.parse as urllib +else: import urllib + +def get_power_status(conn, options): + del conn + state = {"running" : "on", "stopped" : "off"} + if options["--pve-node"] is None: + nodes = send_cmd(options, "nodes") + if type(nodes) is not dict or "data" not in nodes or type(nodes["data"]) is not list: + return None + for node in nodes["data"]: # lookup the node holding the vm + if type(node) is not dict or "node" not in node: + return None + options["--pve-node"] = node["node"] + status = get_power_status(None, options) + if status is not None: + logging.info("vm found on node: " + options["--pve-node"]) + break + else: + options["--pve-node"] = None + return status + else: + cmd = "nodes/" + options["--pve-node"] + "/" + options["--vmtype"] +"/" + options["--plug"] + "/status/current" + result = send_cmd(options, cmd) + if type(result) is dict and "data" in result: + if type(result["data"]) is dict and "status" in result["data"]: + if result["data"]["status"] in state: + return state[result["data"]["status"]] + return None + + +def set_power_status(conn, options): + del conn + action = { + 'on' : "start", + 'off': "stop" + }[options["--action"]] + cmd = "nodes/" + options["--pve-node"] + "/" + options["--vmtype"] +"/" + options["--plug"] + "/status/" + action + send_cmd(options, cmd, post={"skiplock":1}) + + +def reboot_cycle(conn, options): + del conn + cmd = "nodes/" + options["--pve-node"] + "/" + options["--vmtype"] + "/" + options["--plug"] + "/status/reset" + result = send_cmd(options, cmd, post={"skiplock":1}) + return type(result) is dict and "data" in result + + +def get_outlet_list(conn, options): + del conn + nodes = send_cmd(options, "nodes") + outlets = dict() + if type(nodes) is not dict or "data" not in nodes or type(nodes["data"]) is not list: + return None + for node in nodes["data"]: + if type(node) is not dict or "node" not in node: + return None + vms = send_cmd(options, "nodes/" + node["node"] + "/" + options["--vmtype"]) + if type(vms) is not dict or "data" not in vms or type(vms["data"]) is not list: + return None + for vm in vms["data"]: + outlets[vm["vmid"]] = [vm["name"], vm["status"]] + return outlets + + +def get_ticket(options): + post = {'username': options["--username"], 'password': options["--password"]} + result = send_cmd(options, "access/ticket", post=post) + if type(result) is dict and "data" in result: + if type(result["data"]) is dict and "ticket" in result["data"] and "CSRFPreventionToken" in result["data"]: + return { + "ticket" : str("PVEAuthCookie=" + result["data"]["ticket"] + "; " + \ + "version=0; path=/; domain=" + options["--ip"] + \ + "; port=" + str(options["--ipport"]) + "; path_spec=0; secure=1; " + \ + "expires=7200; discard=0"), + "CSRF_token" : str("CSRFPreventionToken: " + result["data"]["CSRFPreventionToken"]) + } + return None + + +def send_cmd(options, cmd, post=None): + url = options["url"] + cmd + conn = pycurl.Curl() + output_buffer = io.BytesIO() + if logging.getLogger().getEffectiveLevel() < logging.WARNING: + conn.setopt(pycurl.VERBOSE, True) + conn.setopt(pycurl.HTTPGET, 1) + conn.setopt(pycurl.URL, url.encode("ascii")) + if "auth" in options and options["auth"] is not None: + conn.setopt(pycurl.COOKIE, options["auth"]["ticket"]) + conn.setopt(pycurl.HTTPHEADER, [options["auth"]["CSRF_token"]]) + if post is not None: + if "skiplock" in post: + conn.setopt(conn.CUSTOMREQUEST, 'POST') + else: + conn.setopt(pycurl.POSTFIELDS, urllib.urlencode(post)) + conn.setopt(pycurl.WRITEFUNCTION, output_buffer.write) + conn.setopt(pycurl.TIMEOUT, int(options["--shell-timeout"])) + + if "--ssl-insecure" in options: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + else: + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + + logging.debug("URL: " + url) + + try: + conn.perform() + result = output_buffer.getvalue().decode() + + logging.debug("RESULT [" + str(conn.getinfo(pycurl.RESPONSE_CODE)) + \ + "]: " + result) + conn.close() + + return json.loads(result) + except pycurl.error: + logging.error("Connection failed") + except: + logging.error("Cannot parse json") + return None + + +def main(): + atexit.register(atexit_handler) + + all_opt["pve_node_auto"] = { + "getopt" : "A", + "longopt" : "pve-node-auto", + "help" : "-A, --pve-node-auto " + "Automatically select proxmox node", + "required" : "0", + "shortdesc" : "Automatically select proxmox node. " + "(This option overrides --pve-node)", + "type": "boolean", + "order": 2 + } + all_opt["pve_node"] = { + "getopt" : "N:", + "longopt" : "pve-node", + "help" : "-N, --pve-node=[node_name] " + "Proxmox node name on which machine is located", + "required" : "0", + "shortdesc" : "Proxmox node name on which machine is located. " + "(Must be specified if not using --pve-node-auto)", + "order": 2 + } + all_opt["node_name"] = { + "getopt" : ":", + "longopt" : "nodename", + "help" : "--nodename " + "Replaced by --pve-node", + "required" : "0", + "shortdesc" : "Replaced by --pve-node", + "order": 3 + } + all_opt["vmtype"] = { + "getopt" : ":", + "longopt" : "vmtype", + "default" : "qemu", + "help" : "--vmtype " + "Virtual machine type lxc or qemu (default: qemu)", + "required" : "1", + "shortdesc" : "Virtual machine type lxc or qemu. " + "(Default: qemu)", + "order": 2 + } + + device_opt = ["ipaddr", "login", "passwd", "ssl", "web", "port", "pve_node", "pve_node_auto", "node_name", "vmtype", "method"] + + all_opt["login"]["required"] = "0" + all_opt["login"]["default"] = "root@pam" + all_opt["ipport"]["default"] = "8006" + all_opt["ssl"]["default"] = "1" + all_opt["port"]["shortdesc"] = "Id of the virtual machine." + all_opt["ipaddr"]["shortdesc"] = "IP Address or Hostname of a node " +\ + "within the Proxmox cluster." + + options = check_input(device_opt, process_input(device_opt)) + docs = {} + docs["shortdesc"] = "Fencing agent for the Proxmox Virtual Environment" + docs["longdesc"] = "The fence_pve agent can be used to fence virtual \ +machines acting as nodes in a virtualized cluster." + docs["vendorurl"] = "http://www.proxmox.com/" + + show_docs(options, docs) + + run_delay(options) + + if "--pve-node-auto" in options: + # Force pve-node to None to allow autodiscovery + options["--pve-node"] = None + elif "--pve-node" in options and options["--pve-node"]: + # Leave pve-node alone + pass + elif "--nodename" in options and options["--nodename"]: + # map nodename into pve-node to support legacy implementations + options["--pve-node"] = options["--nodename"] + else: + fail_usage("At least one of pve-node-auto or pve-node must be supplied") + + + if options["--vmtype"] != "qemu": + # For vmtypes other than qemu, only the onoff method is valid + options["--method"] = "onoff" + + options["url"] = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + "/api2/json/" + + options["auth"] = get_ticket(options) + if options["auth"] is None: + fail(EC_LOGIN_DENIED) + + # Workaround for unsupported API call on some Proxmox hosts + outlets = get_outlet_list(None, options) # Unsupported API-Call will result in value: None + if outlets is None: + result = fence_action(None, options, set_power_status, get_power_status, None, reboot_cycle) + sys.exit(result) + + result = fence_action(None, options, set_power_status, get_power_status, get_outlet_list, reboot_cycle) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/raritan/fence_raritan.py b/agents/raritan/fence_raritan.py new file mode 100644 index 0000000..169fa81 --- /dev/null +++ b/agents/raritan/fence_raritan.py @@ -0,0 +1,87 @@ +#!@PYTHON@ -tt + +import sys, re, pexpect +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fspawn, fail, EC_LOGIN_DENIED, run_delay + +def get_power_status(conn, options): + conn.send_eol("show -d properties=powerState %s" % options["--plug"]) + re_status = re.compile(".*powerState is [12].*") + conn.log_expect(re_status, int(options["--shell-timeout"])) + status = { + #"0" : "off", + "1" : "on", + "2" : "off", + }[conn.after.split()[2]] + + return status + +def set_power_status(conn, options): + action = { + "on" : "on", + "off" : "off", + }[options["--action"]] + + conn.send_eol("set %s powerState=%s" % (options["--plug"], action)) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "port", "telnet"] + + atexit.register(atexit_handler) + + opt = process_input(device_opt) + + all_opt["ipport"]["default"] = "23" + + opt["eol"] = "\r\n" + options = check_input(device_opt, opt) + + docs = {} + docs["shortdesc"] = "I/O Fencing agent for Raritan Dominion PX" + docs["longdesc"] = "fence_raritan is an I/O Fencing agent which can be \ +used with the Raritan DPXS12-20 Power Distribution Unit. It logs into \ +device via telnet and reboots a specified outlet. Lengthy telnet connections \ +should be avoided while a GFS cluster is running because the connection will \ +block any necessary fencing actions." + docs["vendorurl"] = "http://www.raritan.com/" + show_docs(options, docs) + + # add support also for delay before login which is very useful for 2-node clusters + run_delay(options) + + # Convert pure port/plug number to /system1/outlet${plug} + try: + plug_int = int(options["--plug"]) + options["--plug"] = "/system1/outlet" + str(plug_int) + except ValueError: + pass + ## + ## Operate the fencing device + ## We can not use fence_login(), username and passwd are sent on one line + #### + try: + conn = fspawn(options, options["--telnet-path"], encoding="latin1") + conn.send("set binary\n") + conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) + conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) + conn.log_expect("Login.*", int(options["--shell-timeout"])) + conn.send_eol("%s" % (options["--username"])) + conn.log_expect("Password.*", int(options["--shell-timeout"])) + conn.send_eol("%s" % (options["--password"])) + conn.log_expect("clp.*", int(options["--shell-timeout"])) + except pexpect.EOF: + fail(EC_LOGIN_DENIED) + except pexpect.TIMEOUT: + fail(EC_LOGIN_DENIED) + + result = 0 + if options["--action"] != "monitor": + result = fence_action(conn, options, set_power_status, get_power_status) + + fence_logout(conn, "exit\n") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/raritan_px3/fence_raritan_px3.py b/agents/raritan_px3/fence_raritan_px3.py new file mode 100644 index 0000000..137f160 --- /dev/null +++ b/agents/raritan_px3/fence_raritan_px3.py @@ -0,0 +1,195 @@ +#!@PYTHON@ -tt + +import logging +import sys +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import EC_STATUS + +""" +Raritan PX3 family is totaly different the PX family (PX2 seem to be +compatible with PX3 and seem to share the same BIOS, so this fence should +work with PX2 as well). +It has another command line prompt and totally other commands +and output. + +It follows the concept of separating outlets and outletgroups (if created). +You can reach outlets via a fixed, not changeble "plug" number +(from 1-20 on my device). +Additionally one can, but does not need to assign names to each plug. + +Plugs/outlets can be combined to outletgroups. +There can be zero to N (N = No. outlets) outletgroups. + +While it's possible to create outletgroups with one plug, this does not +make sense and might slow things down. + +--plug=X paramter can be: +1. X == outlet No +2. X == outlet Name (if one got assigned) +3. X == outlet group Name + +-> One cannot reach a group by number +-> Groups need an extra call (first single outlet devices are + searched for given No/Name, then OutletGroups +""" + + +class FenceRaritanPX3: + outlets={} + # Plug id of outlet + plug=None + outletgroups={} + # Group name if outlet plug id/name have not been found + group_name=None + +def px3_get_outlet_group(conn, options): + + conn.send_eol("show outletgroups") + conn.expect(options["--command-prompt"], int(options["--shell-timeout"])) + for line in conn.after.splitlines(): + split_line = line.split(" ") + """ + Groups always have a name assigned: + ``` + Outlet Group 1 - test: + Member outlets: 10-11 + State: 2 on + ``` + """ + if len(split_line) == 5 and split_line[0] == "Outlet" and split_line[1] == "Group": + group_no = split_line[2] + group_name = split_line[4][:-1] + + if len(split_line) > 0 and split_line[0] == "State:": + group_state = split_line[-1] + FenceRaritanPX3.outletgroups[group_no] = [ group_name, group_state ] + logging.debug("Outletgroups found:\n%s", FenceRaritanPX3.outletgroups) + return FenceRaritanPX3.outletgroups + +def px3_get_outlet_list(conn, options): + + conn.send_eol("show outlets") + conn.expect(options["--command-prompt"], int(options["--shell-timeout"])) + for line in conn.after.splitlines(): + split_line = line.split(" ") + """ + Plug with no name assigned: + ``` + Outlet 1: + Power state: On + ``` + """ + if len(split_line) == 2 and split_line[0] == "Outlet": + outlet_no = split_line[1][:-1] + outlet_name = "" + """ + Plug with name assigned: + ``` + Outlet 8 - Test: + Power state: On + ``` + """ + if len(split_line) == 4 and split_line[0] == "Outlet": + outlet_no = split_line[1] + outlet_name = split_line[3][:-1] + + # fetch state of previously parsed outlet from next line/iter + if len(split_line) == 3 and split_line[0] == "Power" and split_line[1] == "state:": + outlet_state = split_line[2] + FenceRaritanPX3.outlets[outlet_no] = [outlet_name, outlet_state] + logging.debug("Outlets found:\n%s", FenceRaritanPX3.outlets) + return FenceRaritanPX3.outlets + +def get_power_status(conn, options): + + if FenceRaritanPX3.plug: + return FenceRaritanPX3.outlets[str(FenceRaritanPX3.plug)][1].lower() + elif FenceRaritanPX3.group_name: + return FenceRaritanPX3.outletgroups[FenceRaritanPX3.group_name][1].lower() + sys.exit(EC_STATUS) + +def set_power_status(conn, options): + action = { + "on" : "on", + "off" : "off", + "reboot" : "cycle", + }[options["--action"]] + + if FenceRaritanPX3.plug: + conn.send_eol("power outlets %s %s" % (FenceRaritanPX3.plug, action)) + # Do you wish to turn outlet 5 off? [y/n] + elif FenceRaritanPX3.group_name: + conn.send_eol("power outletgroup %s %s" % (FenceRaritanPX3.group_name, action)) + # Do you wish to turn on all 2 outlets in group 1? [y/n] + conn.log_expect("Do you wish to turn.*", int(options["--shell-timeout"])) + conn.send_eol("y") + print("YYYYY") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + print("XXXXXXXX") + +def disconnect(conn): + conn.sendline("EXIT") + conn.close() + +def main(): + device_opt = ["ipaddr", "login", "passwd", "port", "telnet", "cmd_prompt", "secure"] + + atexit.register(atexit_handler) + + opt = process_input(device_opt) + all_opt["cmd_prompt"]["default"] = ".*\[My PDU\] #" + all_opt["ipport"]["default"] = "23" + all_opt["shell_timeout"]["default"] = "8" + + opt["eol"] = "\r\n" + options = check_input(device_opt, opt) + + docs = {} + docs["shortdesc"] = "I/O Fencing agent for Raritan Dominion PX2 and PX3" + docs["longdesc"] = "fence_raritan is an I/O Fencing agent which can be \ +used with the Raritan PX2 and PX3 Power Distribution Unit series. It logs into \ +device via telnet or ssh and reboots a specified outlet. Single outlets and \ +grouped outlets are supported. The fence is tested on this model: PX3-5466V. \ +There have been issues seen with the telnet prompt on 3.4.x and 3.5.x Raritan \ +firmware versions. It's recommended to update to at least version 3.6.x" + docs["vendorurl"] = "http://www.raritan.com/" + show_docs(options, docs) + + conn = fence_login(options, re_login_string="Username.*") + + px3_get_outlet_list(conn, options) + try: + FenceRaritanPX3.plug = int(options["--plug"]) + if FenceRaritanPX3.plug > len(FenceRaritanPX3.outlets): + logging.error("Plug no exceeds no of outlets") + sys.exit(EC_STATUS) + except ValueError: + for no, values in FenceRaritanPX3.outlets.items(): + if values[0] == options["--plug"]: + FenceRaritanPX3.plug = no + break + if not FenceRaritanPX3.plug: + px3_get_outlet_group(conn, options) + for no, values in FenceRaritanPX3.outletgroups.items(): + if values[0] == options["--plug"]: + FenceRaritanPX3.group_name = no + break + if not FenceRaritanPX3.group_name: + logging.error("Plug %s not found", options["--plug"]) + sys.exit(EC_STATUS) + + logging.debug("\nSingle outlet: %s\nGroup outlet: %s" % (FenceRaritanPX3.plug, FenceRaritanPX3.group_name)) + + result = 0 + if options["--action"] != "monitor": + result = fence_action(conn, options, set_power_status, get_power_status, + get_outlet_list=px3_get_outlet_list, reboot_cycle_fn=set_power_status) + + atexit.register(disconnect, conn) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/rcd_serial/fence_rcd_serial.py b/agents/rcd_serial/fence_rcd_serial.py new file mode 100644 index 0000000..2614772 --- /dev/null +++ b/agents/rcd_serial/fence_rcd_serial.py @@ -0,0 +1,100 @@ +#!@PYTHON@ -tt + +# Copyright 2018 Infoxchange, Danielle Madeley, Sam McLeod-Jones + +# Controls an RCD serial device +# Ported from stonith/rcd_serial.c + +# The Following Agent Has Been Tested On: +# CentOS Linux release 7.5.1804 + +# Resource example: +# primitive stonith_node_1 ocf:rcd_serial_py params port="/dev/ttyS0" time=1000 hostlist=stonith_node_1 stonith-timeout=5s + +import sys +import atexit +import os +import struct +import logging +import time +from fcntl import ioctl +from termios import TIOCMBIC, TIOCMBIS, TIOCM_RTS, TIOCM_DTR +from time import sleep + +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * + +class RCDSerial(object): + """Control class for serial device""" + + def __init__(self, port='/dev/ttyS0'): + self.fd = fd = os.open(port, os.O_RDONLY | os.O_NDELAY) + logging.debug("Opened %s on fd %i", port, fd) + ioctl(fd, TIOCMBIC, struct.pack('I', TIOCM_RTS | TIOCM_DTR)) + + def close(self): + """Close the serial device""" + logging.debug("Closing serial device") + ret = os.close(self.fd) + + return ret + + def toggle_pin(self, pin=TIOCM_DTR, time=1000): + """Toggle the pin high for the time specified""" + + logging.debug("Set pin high") + ioctl(self.fd, TIOCMBIS, struct.pack('I', pin)) + + sleep(float(time) / 1000.) + + logging.debug("Set pin low") + ioctl(self.fd, TIOCMBIC, struct.pack('I', pin)) + +def reboot_device(conn, options): + conn.toggle_pin(time=options["--power-wait"]) + return True + +def main(): + device_opt = ["serial_port", "no_status", "no_password", "no_login", "method", "no_on", "no_off"] + + atexit.register(atexit_handler) + + all_opt["serial_port"] = { + "getopt" : ":", + "longopt" : "serial-port", + "help":"--serial-port=[port] Port of the serial device (e.g. /dev/ttyS0)", + "required" : "1", + "shortdesc" : "Port of the serial device", + "default" : "/dev/ttyS0", + "order": 1 + } + + all_opt["method"]["default"] = "cycle" + all_opt["power_wait"]["default"] = "2" + all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "rcd_serial fence agent" + docs["longdesc"] = "fence_rcd_serial operates a serial cable that toggles a \ +reset of an opposing server using the reset switch on its motherboard. The \ +cable itself is simple with no power, network or moving parts. An example of \ +the cable is available here: https://smcleod.net/rcd-stonith/ and the circuit \ +design is available in the fence-agents src as SVG" + docs["vendorurl"] = "https://github.com/sammcj/fence_rcd_serial" + show_docs(options, docs) + + if options["--action"] in ["off", "reboot"]: + time.sleep(int(options["--delay"])) + + ## Operate the fencing device + conn = RCDSerial(port=options["--serial-port"]) + result = fence_action(conn, options, None, None, reboot_cycle_fn=reboot_device) + conn.close() + + sys.exit(result) + +if __name__ == "__main__": + main() + diff --git a/agents/rcd_serial/rcd_serial_cable_diagram.svg b/agents/rcd_serial/rcd_serial_cable_diagram.svg new file mode 100644 index 0000000..36f219f --- /dev/null +++ b/agents/rcd_serial/rcd_serial_cable_diagram.svg @@ -0,0 +1,276 @@ +<?xml version="1.0"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg viewBox="24 24 1460 442" preserveAspectRatio="xMinYMin meet" version="1.1" xmlns="http://www.w3.org/2000/svg"> +<g class="Diode"> +<line x1="320" y1="128" x2="342" y2="128" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="361" y1="128" x2="384" y2="128" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polygon fill="#000000" stroke="none" points="342,115 342,141 361,128 " /> +<polygon stroke="#000000" stroke-width="2" fill="none" points="342,115 342,141 361,128 " /> +<line x1="361" y1="115" x2="361" y2="141" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<text x="322" y="103" font-family="sans-serif">1N4148</text> +</g> +<g class="Diode"> +<line x1="320" y1="288" x2="342" y2="288" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="361" y1="288" x2="384" y2="288" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polygon fill="#000000" stroke="none" points="342,275 342,301 361,288 " /> +<polygon stroke="#000000" stroke-width="2" fill="none" points="342,275 342,301 361,288 " /> +<line x1="361" y1="275" x2="361" y2="301" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<text x="317" y="263" font-family="sans-serif">1N4148.</text> +</g> +<g class="Resistor"> +<line x1="448" y1="128" x2="464" y2="128" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="496" y1="128" x2="512" y2="128" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="464,128 466.6667,120 469.3333,128 472,136 474.6667,128 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="474.6667,128 477.3333,120 480,128 482.6667,136 485.3333,128 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="485.3333,128 488,120 490.6667,128 493.3333,136 496,128 " /> +<text x="465" y="113" font-family="sans-serif">10k</text> +</g> +<g class="Resistor"> +<line x1="448" y1="288" x2="464" y2="288" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="496" y1="288" x2="512" y2="288" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="464,288 466.6667,280 469.3333,288 472,296 474.6667,288 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="474.6667,288 477.3333,280 480,288 482.6667,296 485.3333,288 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="485.3333,288 488,280 490.6667,288 493.3333,296 496,288 " /> +<text x="465" y="273" font-family="sans-serif">10k</text> +</g> +<g class="Resistor"> +<line x1="576" y1="384" x2="576" y2="368" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="576" y1="336" x2="576" y2="320" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="576,368 568,365.3333 576,362.6667 584,360 576,357.3333 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="576,357.3333 568,354.6667 576,352 584,349.3333 576,346.6667 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="576,346.6667 568,344 576,341.3333 584,338.6667 576,336 " /> +<text x="591" y="357" font-family="sans-serif">20k</text> +</g> +<g class="Resistor"> +<line x1="672" y1="224" x2="672" y2="208" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="672" y1="176" x2="672" y2="160" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="672,208 664,205.3333 672,202.6667 680,200 672,197.3333 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="672,197.3333 664,194.6667 672,192 680,189.3333 672,186.6667 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="672,186.6667 664,184 672,181.3333 680,178.6667 672,176 " /> +<text x="687" y="197" font-family="sans-serif">120</text> +</g> +<g class="Wire"> +<line x1="448" y1="128" x2="384" y2="128" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +</g> +<g class="Wire"> +<line x1="448" y1="288" x2="384" y2="288" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +</g> +<g class="Wire"> +<line x1="512" y1="288" x2="576" y2="288" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="576" cy="288" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="576" y1="288" x2="608" y2="288" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="576" cy="288" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="512" y1="128" x2="672" y2="128" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="672" cy="128" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="672" y1="128" x2="672" y2="160" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="672" cy="128" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="672" y1="256" x2="672" y2="224" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +</g> +<g class="Wire"> +<line x1="672" y1="416" x2="576" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="672" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +<ellipse cx="576" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="320" y1="128" x2="288" y2="128" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +</g> +<g class="Wire"> +<line x1="288" y1="288" x2="320" y2="288" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +</g> +<g class="Resistor"> +<line x1="800" y1="320" x2="800" y2="304" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="800" y1="272" x2="800" y2="256" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="800,304 792,301.3333 800,298.6667 808,296 800,293.3333 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="800,293.3333 792,290.6667 800,288 808,285.3333 800,282.6667 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="800,282.6667 792,280 800,277.3333 808,274.6667 800,272 " /> +<text x="815" y="293" font-family="sans-serif">100k</text> +</g> +<g class="Capacitor"> +<line x1="896" y1="320" x2="896" y2="292" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="884" y1="292" x2="908" y2="292" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="896" y1="256" x2="896" y2="284" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<path d="M 907.313708566442 279.313708431527 A 16 16 0 0 1 884.686291748284 279.313708746254" stroke="#000000" stroke-width="3" fill="none" /> +<text x="918" y="293" font-family="sans-serif">100uF</text> +</g> +<g class="Wire"> +<line x1="800" y1="256" x2="800" y2="128" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="800" cy="128" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="896" y1="256" x2="896" y2="128" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="896" cy="128" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="896" y1="128" x2="800" y2="128" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="896" cy="128" rx="4" ry="4" fill="#000000" stroke="none" /> +<ellipse cx="800" cy="128" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="896" y1="416" x2="800" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="896" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +<ellipse cx="800" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="LED"> +<line x1="992" y1="160" x2="992" y2="182" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="992" y1="201" x2="992" y2="224" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polygon fill="#FFFFFF" stroke="none" points="1005,182 979,182 992,201 " /> +<polygon stroke="#000000" stroke-width="2" fill="none" points="1005,182 979,182 992,201 " /> +<line x1="1005" y1="201" x2="979" y2="201" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<text x="1013" y="197" font-family="sans-serif">Red LED</text> +<line x1="1003" y1="192" x2="1007" y2="195" stroke="#000000" stroke-width="2" stroke-linecap="round" fill="none" /> +<line x1="1006" y1="188" x2="1010" y2="191" stroke="#000000" stroke-width="2" stroke-linecap="round" fill="none" /> +</g> +<g class="LED"> +<line x1="992" y1="288" x2="992" y2="310" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="992" y1="329" x2="992" y2="352" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polygon fill="#FFFFFF" stroke="none" points="1005,310 979,310 992,329 " /> +<polygon stroke="#000000" stroke-width="2" fill="none" points="1005,310 979,310 992,329 " /> +<line x1="1005" y1="329" x2="979" y2="329" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="1003" y1="320" x2="1007" y2="323" stroke="#000000" stroke-width="2" stroke-linecap="round" fill="none" /> +<line x1="1006" y1="316" x2="1010" y2="319" stroke="#000000" stroke-width="2" stroke-linecap="round" fill="none" /> +</g> +<g class="BJT Transistor (NPN)"> +<line x1="1088" y1="288" x2="1060" y2="308" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="1088" y1="352" x2="1060" y2="332" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polygon fill="#000000" stroke="none" points="1088,352 1080,336 1070,349 " /> +<line x1="1024" y1="320" x2="1056" y2="320" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polygon fill="#000000" stroke="none" points="1056,294 1062,294 1062,346 1056,346 " /> +<text x="1087" y="325" font-family="sans-serif">PS2501 Optocoupler</text> +<ellipse cx="1024" cy="320" rx="4" ry="4" stroke="#000000" stroke-width="1" fill="none" /> +</g> +<g class="Wire"> +<line x1="992" y1="288" x2="992" y2="224" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<text x="1007" y="261" font-family="sans-serif">1</text> +</g> +<g class="Port"> +<polygon fill="#FFFFFF" stroke="none" points="1184,256 1192,246 1248,246 1248,266 1192,266 " /> +<polygon stroke="#000000" stroke-width="1" fill="none" points="1184,256 1192,246 1248,246 1248,266 1192,266 " /> +<text x="1211" y="261" font-family="sans-serif">1</text> +<text x="1256" y="261" font-family="sans-serif">RWL</text> +</g> +<g class="Port"> +<polygon fill="#FFFFFF" stroke="none" points="1184,384 1192,374 1248,374 1248,394 1192,394 " /> +<polygon stroke="#000000" stroke-width="1" fill="none" points="1184,384 1192,374 1248,374 1248,394 1192,394 " /> +<text x="1211" y="389" font-family="sans-serif">2</text> +<text x="1256" y="389" font-family="sans-serif">RWG</text> +</g> +<g class="Port"> +<polygon fill="#FFFFFF" stroke="none" points="288,128 280,138 224,138 224,118 280,118 " /> +<polygon stroke="#000000" stroke-width="1" fill="none" points="288,128 280,138 224,138 224,118 280,118 " /> +<text x="251" y="133" font-family="sans-serif">7</text> +<text x="186" y="133" font-family="sans-serif">RTS</text> +</g> +<g class="Port"> +<polygon fill="#FFFFFF" stroke="none" points="288,288 280,298 224,298 224,278 280,278 " /> +<polygon stroke="#000000" stroke-width="1" fill="none" points="288,288 280,298 224,298 224,278 280,278 " /> +<text x="251" y="293" font-family="sans-serif">4</text> +<text x="186" y="293" font-family="sans-serif">DTR</text> +</g> +<g class="Port"> +<polygon fill="#FFFFFF" stroke="none" points="288,416 280,426 224,426 224,406 280,406 " /> +<polygon stroke="#000000" stroke-width="1" fill="none" points="288,416 280,426 224,426 224,406 280,406 " /> +<text x="251" y="421" font-family="sans-serif">5</text> +<text x="196" y="421" font-family="sans-serif">SG</text> +</g> +<g class="Wire"> +<line x1="576" y1="416" x2="288" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="576" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="896" y1="416" x2="992" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="896" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="896" y1="128" x2="992" y2="128" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="896" cy="128" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="992" y1="160" x2="992" y2="128" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +</g> +<g class="Wire"> +<line x1="1088" y1="256" x2="1184" y2="256" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<text x="1131" y="241" font-family="sans-serif">4</text> +</g> +<g class="Wire"> +<line x1="1088" y1="384" x2="1184" y2="384" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<text x="1131" y="369" font-family="sans-serif">3</text> +</g> +<g class="RS232 Serial Connector"> +<rect x="56" y="248" width="106" height="62" fill="#FFFFFF" stroke="none" /> +<rect x="56" y="248" width="106" height="62" rx="5" ry="5" stroke="#000000" stroke-width="2" fill="none" /> +<text x="84" y="266" font-family="sans-serif">RS232</text> +<text x="79" y="284" font-family="sans-serif">Serial</text> +<text x="64" y="302" font-family="sans-serif">Connector</text> +</g> +<g class="Motherboard Reset Pins"> +<rect x="1304" y="280" width="126" height="62" fill="#FFFFFF" stroke="none" /> +<rect x="1304" y="280" width="126" height="62" rx="5" ry="5" stroke="#000000" stroke-width="2" fill="none" /> +<text x="1312" y="298" font-family="sans-serif">Motherboard</text> +<text x="1342" y="316" font-family="sans-serif">Reset</text> +<text x="1347" y="334" font-family="sans-serif">Pins</text> +</g> +<g class="n-MOSFET"> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="640,312 672,312 672,320 " /> +<polyline stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" fill="none" points="640,264 672,264 672,256 " /> +<line x1="640" y1="312" x2="640" y2="288" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="640" y1="288" x2="640" y2="264" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="640" y1="312" x2="640" y2="320" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="640" y1="264" x2="640" y2="256" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<polygon fill="#000000" stroke="none" points="672,312 656,304 656,320 " /> +<line x1="608" y1="288" x2="630" y2="288" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<line x1="630" y1="264" x2="630" y2="312" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none" /> +<text x="679" y="293" font-family="sans-serif">6512A-ND1</text> +</g> +<g class="Wire"> +<line x1="672" y1="128" x2="800" y2="128" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="672" cy="128" rx="4" ry="4" fill="#000000" stroke="none" /> +<ellipse cx="800" cy="128" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="672" y1="416" x2="800" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="672" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +<ellipse cx="800" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="576" y1="288" x2="576" y2="320" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="576" cy="288" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="576" y1="384" x2="576" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="576" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="992" y1="352" x2="992" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<text x="1007" y="389" font-family="sans-serif">2</text> +</g> +<g class="Wire"> +<line x1="672" y1="320" x2="672" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="672" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="896" y1="320" x2="896" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="896" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Wire"> +<line x1="800" y1="320" x2="800" y2="416" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +<ellipse cx="800" cy="416" rx="4" ry="4" fill="#000000" stroke="none" /> +</g> +<g class="Delayed Serial Cable For STONITH"> +<rect x="536" y="56" width="336" height="26" fill="#FFFFFF" stroke="none" /> +<text x="544" y="74" font-family="sans-serif">Delayed Serial Cable For STONITH</text> +</g> +<g class="Wire"> +<line x1="1088" y1="256" x2="1088" y2="288" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +</g> +<g class="Wire"> +<line x1="1088" y1="384" x2="1088" y2="352" stroke="#000000" stroke-width="1.5" stroke-linecap="round" fill="none" /> +</g> +</svg> diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py new file mode 100644 index 0000000..0f5af52 --- /dev/null +++ b/agents/redfish/fence_redfish.py @@ -0,0 +1,177 @@ +#!@PYTHON@ -tt + +# Copyright (c) 2018 Dell Inc. or its subsidiaries. All Rights Reserved. + +# Fence agent for devices that support the Redfish API Specification. + +import sys +import re +import logging +import json +import requests +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") + +from fencing import * +from fencing import fail_usage, run_delay + +GET_HEADERS = {'accept': 'application/json', 'OData-Version': '4.0'} +POST_HEADERS = {'content-type': 'application/json', 'accept': 'application/json', + 'OData-Version': '4.0'} + + +def get_power_status(conn, options): + response = send_get_request(options, options["--systems-uri"]) + if response['ret'] is False: + fail_usage("Couldn't get power information") + data = response['data'] + + try: + logging.debug("PowerState is: " + data[u'PowerState']) + except Exception: + fail_usage("Unable to get PowerState: " + "https://" + options["--ip"] + ":" + str(options["--ipport"]) + options["--systems-uri"]) + + if data[u'PowerState'].strip() == "Off": + return "off" + else: + return "on" + +def set_power_status(conn, options): + action = { + 'on' : "On", + 'off': "ForceOff", + 'reboot': "ForceRestart", + 'diag': "Nmi" + }[options.get("original-action") or options["--action"]] + + payload = {'ResetType': action} + + # Search for 'Actions' key and extract URI from it + response = send_get_request(options, options["--systems-uri"]) + if response['ret'] is False: + return {'ret': False} + data = response['data'] + action_uri = data["Actions"]["#ComputerSystem.Reset"]["target"] + + response = send_post_request(options, action_uri, payload) + if response['ret'] is False: + fail_usage("Error sending power command") + if options.get("original-action") == "diag": + return True + return + +def send_get_request(options, uri): + full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri + try: + resp = requests.get(full_uri, verify=not "--ssl-insecure" in options, + headers=GET_HEADERS, + auth=(options["--username"], options["--password"])) + data = resp.json() + except Exception as e: + fail_usage("Failed: send_get_request: " + str(e)) + return {'ret': True, 'data': data} + +def send_post_request(options, uri, payload): + full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri + try: + requests.post(full_uri, data=json.dumps(payload), + headers=POST_HEADERS, verify=not "--ssl-insecure" in options, + auth=(options["--username"], options["--password"])) + except Exception as e: + fail_usage("Failed: send_post_request: " + str(e)) + return {'ret': True} + +def find_systems_resource(options): + response = send_get_request(options, options["--redfish-uri"]) + if response['ret'] is False: + return {'ret': False} + data = response['data'] + + if 'Systems' not in data: + # Systems resource not found" + return {'ret': False} + else: + response = send_get_request(options, data["Systems"]["@odata.id"]) + if response['ret'] is False: + return {'ret': False} + data = response['data'] + + # need to be able to handle more than one entry + for member in data[u'Members']: + system_uri = member[u'@odata.id'] + return {'ret': True, 'uri': system_uri} + +def define_new_opts(): + all_opt["redfish-uri"] = { + "getopt" : ":", + "longopt" : "redfish-uri", + "help" : "--redfish-uri=[uri] Base or starting Redfish URI", + "required" : "0", + "default" : "/redfish/v1", + "shortdesc" : "Base or starting Redfish URI", + "order": 1 + } + all_opt["systems-uri"] = { + "getopt" : ":", + "longopt" : "systems-uri", + "help" : "--systems-uri=[uri] Redfish Systems resource URI", + "required" : "0", + "shortdesc" : "Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1", + "order": 1 + } + +def main(): + atexit.register(atexit_handler) + device_opt = ["ipaddr", "login", "passwd", "redfish-uri", "systems-uri", + "ssl", "diag"] + define_new_opts() + + opt = process_input(device_opt) + + all_opt["ssl"]["default"] = "1" + options = check_input(device_opt, opt) + + docs = {} + docs["shortdesc"] = "I/O Fencing agent for Redfish" + docs["longdesc"] = "fence_redfish is an I/O Fencing agent which can be used with \ +Out-of-Band controllers that support Redfish APIs. These controllers provide remote \ +access to control power on a server." + docs["vendorurl"] = "http://www.dmtf.org" + show_docs(options, docs) + run_delay(options) + + ## + ## Operate the fencing device + #### + + # Disable insecure-certificate-warning message + if "--ssl-insecure" in opt: + import urllib3 + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + # backwards compatibility for <ip>:<port> + if options["--ip"].count(":") == 1: + (options["--ip"], options["--ipport"]) = options["--ip"].split(":") + + if "--systems-uri" not in opt: + # Systems URI not provided, find it + sysresult = find_systems_resource(options) + if sysresult['ret'] is False: + sys.exit(1) + else: + options["--systems-uri"] = sysresult["uri"] + + reboot_fn = None + if options["--action"] == "diag": + # Diag is a special action that can't be verified so we will reuse reboot functionality + # to minimize impact on generic library + options["original-action"] = options["--action"] + options["--action"] = "reboot" + options["--method"] = "cycle" + reboot_fn = set_power_status + + result = fence_action(None, options, set_power_status, get_power_status, None, reboot_fn) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py new file mode 100644 index 0000000..5f74d06 --- /dev/null +++ b/agents/rhevm/fence_rhevm.py @@ -0,0 +1,249 @@ +#!@PYTHON@ -tt + +import sys, re +import pycurl, io +import logging +import atexit +import tempfile +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_FETCH_VM_UUID, run_delay + +RE_GET_ID = re.compile("<vm( .*)? id=\"(.*?)\"", re.IGNORECASE) +RE_STATUS = re.compile("<status>(.*?)</status>", re.IGNORECASE) +RE_STATE = re.compile("<state>(.*?)</state>", re.IGNORECASE) +RE_GET_NAME = re.compile("<name>(.*?)</name>", re.IGNORECASE) + +def get_power_status(conn, options): + del conn + + ### Obtain real ID from name + res = send_command(options, "vms/?search=name%3D" + options["--plug"]) + + result = RE_GET_ID.search(res) + if result == None: + # Unable to obtain ID needed to access virtual machine + fail(EC_FETCH_VM_UUID) + + options["id"] = result.group(2) + + if tuple(map(int, options["--api-version"].split(".")))[0] > 3: + result = RE_STATUS.search(res) + else: + result = RE_STATE.search(res) + if result == None: + # We were able to parse ID so output is correct + # in some cases it is possible that RHEV-M output does not + # contain <status> line. We can assume machine is OFF then + return "off" + else: + status = result.group(1) + + if status.lower() == "down": + return "off" + else: + return "on" + +def set_power_status(conn, options): + del conn + action = { + 'on' : "start", + 'off' : "stop" + }[options["--action"]] + + url = "vms/" + options["id"] + "/" + action + send_command(options, url, "POST") + +def get_list(conn, options): + del conn + outlets = {} + + try: + res = send_command(options, "vms") + + lines = res.split("<vm ") + for i in range(1, len(lines)): + name = RE_GET_NAME.search(lines[i]).group(1) + if tuple(map(int, options["--api-version"].split(".")))[0] > 3: + status = RE_STATUS.search(lines[i]).group(1) + else: + status = RE_STATE.search(lines[i]).group(1) + outlets[name] = ("", status) + except AttributeError: + return {} + except IndexError: + return {} + + return outlets + +def send_command(opt, command, method="GET"): + if opt["--api-version"] == "auto": + opt["--api-version"] = "4" + res = send_command(opt, "") + if re.search("<title>Error</title>", res): + opt["--api-version"] = "3" + logging.debug("auto-detected API version: " + opt["--api-version"]) + + ## setup correct URL + if "--ssl-secure" in opt or "--ssl-insecure" in opt: + url = "https:" + else: + url = "http:" + if "--api-path" in opt: + api_path = opt["--api-path"] + else: + api_path = "/ovirt-engine/api" + if "--disable-http-filter" in opt: + http_filter = 'false' + else: + http_filter = 'true' + + url += "//" + opt["--ip"] + ":" + str(opt["--ipport"]) + api_path + "/" + command + + ## send command through pycurl + conn = pycurl.Curl() + web_buffer = io.BytesIO() + conn.setopt(pycurl.URL, url.encode("UTF-8")) + conn.setopt(pycurl.HTTPHEADER, [ + "Version: {}".format(opt["--api-version"]), + "Content-type: application/xml", + "Accept: application/xml", + "Prefer: persistent-auth", + "Filter: {}".format(http_filter), + ]) + + if "cookie" in opt: + conn.setopt(pycurl.COOKIE, opt["cookie"]) + else: + conn.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC) + conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"]) + if "--use-cookies" in opt: + if "--cookie-file" in opt: + cookie_file = opt["--cookie-file"] + else: + cookie_file = tempfile.gettempdir() + "/fence_rhevm_" + opt["--ip"] + "_" + opt["--username"] + "_cookie.dat" + conn.setopt(pycurl.COOKIEFILE, cookie_file) + conn.setopt(pycurl.COOKIEJAR, cookie_file) + + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) + + if "--ssl-secure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + elif "--ssl-insecure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + + if method == "POST": + conn.setopt(pycurl.POSTFIELDS, "<action />") + + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + conn.perform() + + if "cookie" not in opt and "--use-cookies" in opt: + cookie = "" + for c in conn.getinfo(pycurl.INFO_COOKIELIST): + tokens = c.split("\t",7) + cookie = cookie + tokens[5] + "=" + tokens[6] + ";" + + opt["cookie"] = cookie + + result = web_buffer.getvalue().decode("UTF-8") + + logging.debug("url: %s\n", url.encode("UTF-8")) + logging.debug("command: %s\n", command.encode("UTF-8")) + logging.debug("result: %s\n", result.encode("UTF-8")) + + return result + +def define_new_opts(): + + all_opt["port"] = { + "getopt" : "n:", + "longopt" : "plug", + "help" : "-n, --plug=[name] " + "VM name in RHV", + "required" : "1", + "order" : 1} + all_opt["use_cookies"] = { + "getopt" : "", + "longopt" : "use-cookies", + "help" : "--use-cookies Reuse cookies for authentication", + "required" : "0", + "shortdesc" : "Reuse cookies for authentication", + "order" : 1} + all_opt["cookie_file"] = { + "getopt" : ":", + "longopt" : "cookie-file", + "help" : "--cookie-file Path to cookie file for authentication\n" + "\t\t\t\t (Default: /tmp/fence_rhevm_ip_username_cookie.dat)", + "required" : "0", + "shortdesc" : "Path to cookie file for authentication", + "order" : 2} + all_opt["api_version"] = { + "getopt" : ":", + "longopt" : "api-version", + "help" : "--api-version " + "Version of RHEV API (default: auto)", + "required" : "0", + "order" : 2, + "default" : "auto", + } + all_opt["api_path"] = { + "getopt" : ":", + "longopt" : "api-path", + "help" : "--api-path=[path] The path part of the API URL", + "default" : "/ovirt-engine/api", + "required" : "0", + "shortdesc" : "The path part of the API URL", + "order" : 3} + all_opt["disable_http_filter"] = { + "getopt" : "", + "longopt" : "disable-http-filter", + "help" : "--disable-http-filter Set HTTP Filter header to false", + "required" : "0", + "shortdesc" : "Set HTTP Filter header to false", + "order" : 4} + + +def main(): + device_opt = [ + "ipaddr", + "login", + "passwd", + "ssl", + "notls", + "web", + "port", + "use_cookies", + "cookie_file", + "api_version", + "api_path", + "disable_http_filter", + ] + + atexit.register(atexit_handler) + define_new_opts() + + all_opt["power_wait"]["default"] = "1" + all_opt["shell_timeout"]["default"] = "5" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for RHEV-M REST API" + docs["longdesc"] = "fence_rhevm is an I/O Fencing agent which can be \ +used with RHEV-M REST API to fence virtual machines." + docs["vendorurl"] = "http://www.redhat.com" + show_docs(options, docs) + + ## + ## Fence operations + #### + run_delay(options) + result = fence_action(None, options, set_power_status, get_power_status, get_list) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/rsa/fence_rsa.py b/agents/rsa/fence_rsa.py new file mode 100644 index 0000000..44fdd9d --- /dev/null +++ b/agents/rsa/fence_rsa.py @@ -0,0 +1,63 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## Main GFEP25A & Boot GFBP25A +## +##### + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * + +def get_power_status(conn, options): + conn.send_eol("power state") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + match = re.compile("Power: (.*)", re.IGNORECASE).search(conn.before) + if match != None: + status = match.group(1) + else: + status = "undefined" + + return status.lower().strip() + +def set_power_status(conn, options): + conn.send_eol("power " + options["--action"]) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "telnet"] + + atexit.register(atexit_handler) + + all_opt["login_timeout"]["default"] = 10 + all_opt["cmd_prompt"]["default"] = [">"] + # This device will not allow us to login even with LANG=C + all_opt["ssh_options"]["default"] = "-F /dev/null" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for IBM RSA" + docs["longdesc"] = "fence_rsa is an I/O Fencing agent \ +which can be used with the IBM RSA II management interface. It \ +logs into an RSA II device via telnet and reboots the associated \ +machine. Lengthy telnet connections to the RSA II device should \ +be avoided while a GFS cluster is running because the connection \ +will block any necessary fencing actions." + docs["vendorurl"] = "http://www.ibm.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + ###### + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, None) + fence_logout(conn, "exit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/rsb/fence_rsb.py b/agents/rsb/fence_rsb.py new file mode 100755 index 0000000..45355f5 --- /dev/null +++ b/agents/rsb/fence_rsb.py @@ -0,0 +1,70 @@ +#!@PYTHON@ -tt + +import sys, re +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * + +def get_power_status(conn, options): + conn.send("2") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + status = re.compile(r"Power Status[\s]*: (on|off)", re.IGNORECASE).search(conn.before).group(1) + conn.send("0") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + return status.lower().strip() + +def set_power_status(conn, options): + action = { + 'on' : "4", + 'off': "1" + }[options["--action"]] + + conn.send("2") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.send_eol(action) + conn.log_expect(["want to power " + options["--action"], + "yes/no", "'yes' or 'no'"], int(options["--shell-timeout"])) + conn.send_eol("yes") + conn.log_expect("any key to continue", int(options["--power-timeout"])) + conn.send_eol("") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + conn.send_eol("0") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["to quit:"] + + opt = process_input(device_opt) + + if "--ssh" not in opt and "--ipport" not in opt: + # set default value like it should be set as usually + all_opt["ipport"]["default"] = "3172" + opt["--ipport"] = all_opt["ipport"]["default"] + + options = check_input(device_opt, opt) + + docs = {} + docs["shortdesc"] = "I/O Fencing agent for Fujitsu-Siemens RSB" + docs["longdesc"] = "fence_rsb is an I/O Fencing agent \ +which can be used with the Fujitsu-Siemens RSB management interface. It logs \ +into device via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh \ +connections should be avoided while a GFS cluster is running because the connection \ +will block any necessary fencing actions." + docs["vendorurl"] = "http://www.fujitsu.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, None) + fence_logout(conn, "0") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/sanbox2/fence_sanbox2.py b/agents/sanbox2/fence_sanbox2.py new file mode 100644 index 0000000..179fe0e --- /dev/null +++ b/agents/sanbox2/fence_sanbox2.py @@ -0,0 +1,155 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## Version Firmware +## +-----------------+---------------------------+ +##### + +import sys, re, pexpect +import logging +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_TIMED_OUT, EC_GENERIC_ERROR + +def get_power_status(conn, options): + status_trans = { + 'online' : "on", + 'offline' : "off" + } + try: + conn.send_eol("show port " + options["--plug"]) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + except pexpect.TIMEOUT: + try: + conn.send_eol("admin end") + conn.send_eol("exit") + conn.close() + except Exception as e: + logging.error("Failed: {}".format(str(e))) + pass + fail(EC_TIMED_OUT) + + status = re.compile(r".*AdminState\s+(online|offline)\s+", + re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) + + try: + return status_trans[status.lower().strip()] + except KeyError: + return "PROBLEM" + +def set_power_status(conn, options): + action = { + 'on' : "online", + 'off' : "offline" + }[options["--action"]] + + try: + conn.send_eol("set port " + options["--plug"] + " state " + action) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + except pexpect.TIMEOUT: + try: + conn.send_eol("admin end") + conn.send_eol("exit") + conn.close() + except Exception as e: + logging.error("Failed: {}".format(str(e))) + pass + fail(EC_TIMED_OUT) + + try: + conn.send_eol("set port " + options["--plug"] + " state " + action) + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + except pexpect.TIMEOUT: + try: + conn.send_eol("admin end") + conn.send_eol("exit") + conn.close() + except Exception as e: + logging.error("Failed: {}".format(str(e))) + pass + fail(EC_TIMED_OUT) + +def get_list_devices(conn, options): + outlets = {} + + try: + conn.send_eol("show port") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + list_re = re.compile(r"^\s+(\d+?)\s+(Online|Offline)\s+", re.IGNORECASE) + for line in conn.before.splitlines(): + if list_re.search(line): + status = { + 'online' : "ON", + 'offline' : "OFF" + }[list_re.search(line).group(2).lower()] + outlets[list_re.search(line).group(1)] = ("", status) + + except pexpect.TIMEOUT: + try: + conn.send_eol("admin end") + conn.send_eol("exit") + conn.close() + except Exception as e: + logging.error("Failed: {}".format(str(e))) + pass + fail(EC_TIMED_OUT) + + return outlets + +def main(): + device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "cmd_prompt", \ + "port", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = [" #> "] + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for QLogic SANBox2 FC switches" + docs["longdesc"] = "fence_sanbox2 is an I/O Fencing agent which can be used with \ +QLogic SANBox2 FC switches. It logs into a SANBox2 switch via telnet and disables a specified \ +port. Disabling the port which a machine is connected to effectively fences that machine. \ +Lengthy telnet connections to the switch should be avoided while a GFS cluster is running \ +because the connection will block any necessary fencing actions." + docs["vendorurl"] = "http://www.qlogic.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + ## + conn = fence_login(options) + + conn.send_eol("admin start") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + if re.search(r"\(admin\)", conn.before, re.MULTILINE) == None: + ## Someone else is in admin section, we can't enable/disable + ## ports so we will rather exit + logging.error("Failed: Unable to switch to admin section\n") + sys.exit(EC_GENERIC_ERROR) + + result = fence_action(conn, options, set_power_status, get_power_status, get_list_devices) + + ## + ## Logout from system + ###### + try: + conn.send_eol("admin end") + conn.send_eol("exit\n") + conn.close() + except OSError: + pass + except pexpect.ExceptionPexpect: + pass + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/sbd/fence_sbd.py b/agents/sbd/fence_sbd.py new file mode 100644 index 0000000..2b0127d --- /dev/null +++ b/agents/sbd/fence_sbd.py @@ -0,0 +1,435 @@ +#!@PYTHON@ -tt + +import sys, stat +import logging +import os +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import fail_usage, run_commands, fence_action, all_opt +from fencing import atexit_handler, check_input, process_input, show_docs +from fencing import run_delay +import itertools + +DEVICE_INIT = 1 +DEVICE_NOT_INIT = -3 +PATH_NOT_EXISTS = -1 +PATH_NOT_BLOCK = -2 + +def is_block_device(filename): + """Checks if a given path is a valid block device + + Key arguments: + filename -- the file to check + + Return codes: + True if it's a valid block device + False, otherwise + """ + + try: + mode = os.lstat(filename).st_mode + except OSError: + return False + else: + return stat.S_ISBLK(mode) + +def is_link(filename): + """Checks if a given path is a link. + + Key arguments: + filename -- the file to check + + Return codes: + True if it's a link + False, otherwise + """ + + try: + mode = os.lstat(filename).st_mode + except OSError: + return False + else: + return stat.S_ISLNK(mode) + +def check_sbd_device(options, device_path): + """checks that a given sbd device exists and is initialized + + Key arguments: + options -- options dictionary + device_path -- device path to check + + Return Codes: + 1 / DEVICE_INIT if the device exists and is initialized + -1 / PATH_NOT_EXISTS if the path does not exists + -2 / PATH_NOT_BLOCK if the path exists but is not a valid block device + -3 / DEVICE_NOT_INIT if the sbd device is not initialized + """ + + # First of all we need to check if the device is valid + if not os.path.exists(device_path): + return PATH_NOT_EXISTS + + # We need to check if device path is a symbolic link. If so we resolve that + # link. + if is_link(device_path): + link_target = os.readlink(device_path) + device_path = os.path.join(os.path.dirname(device_path), link_target) + + # As second step we make sure it's a valid block device + if not is_block_device(device_path): + return PATH_NOT_BLOCK + + cmd = "%s -d %s dump" % (options["--sbd-path"], device_path) + + (return_code, out, err) = run_commands(options, [ cmd ]) + + for line in itertools.chain(out.split("\n"), err.split("\n")): + if len(line) == 0: + continue + + # If we read "NOT dumped" something went wrong, e.g. the device is not + # initialized. + if "NOT dumped" in line: + return DEVICE_NOT_INIT + + return DEVICE_INIT + + +def generate_sbd_command(options, command, arguments=None): + """Generates a sbd command based on given arguments. + + Return Value: + generated list of sbd commands (strings) depending + on command multiple commands with a device each + or a single command with multiple devices + """ + cmds = [] + + if not command in ["list", "dump"]: + cmd = options["--sbd-path"] + + # add "-d" for each sbd device + for device in parse_sbd_devices(options): + cmd += " -d %s" % device + + cmd += " %s %s" % (command, arguments) + cmds.append(cmd) + + else: + for device in parse_sbd_devices(options): + cmd = options["--sbd-path"] + cmd += " -d %s" % device + cmd += " %s %s" % (command, arguments) + cmds.append(cmd) + + return cmds + +def send_sbd_message(conn, options, plug, message): + """Sends a message to all sbd devices. + + Key arguments: + conn -- connection structure + options -- options dictionary + plug -- plug to sent the message to + message -- message to send + + Return Value: + (return_code, out, err) Tuple containing the error code, + """ + + del conn + + arguments = "%s %s" % (plug, message) + cmd = generate_sbd_command(options, "message", arguments) + + (return_code, out, err) = run_commands(options, cmd) + + return (return_code, out, err) + +def get_msg_timeout(options): + """Reads the configured sbd message timeout from each device. + + Key arguments: + options -- options dictionary + + Return Value: + msg_timeout (integer, seconds) + """ + + # get the defined msg_timeout + msg_timeout = -1 # default sbd msg timeout + + cmd = generate_sbd_command(options, "dump") + + (return_code, out, err) = run_commands(options, cmd) + + for line in itertools.chain(out.split("\n"), err.split("\n")): + if len(line) == 0: + continue + + if "msgwait" in line: + tmp_msg_timeout = int(line.split(':')[1]) + if -1 != msg_timeout and tmp_msg_timeout != msg_timeout: + logging.warn(\ + "sbd message timeouts differ in different devices") + # we only save the highest timeout + if tmp_msg_timeout > msg_timeout: + msg_timeout = tmp_msg_timeout + + return msg_timeout + +def set_power_status(conn, options): + """send status to sbd device (poison pill) + + Key arguments: + conn -- connection structure + options -- options dictionary + + Return Value: + return_code -- action result (bool) + """ + + target_status = options["--action"] + plug = options["--plug"] + return_code = 99 + out = "" + err = "" + + # Map fencing actions to sbd messages + if "on" == target_status: + (return_code, out, err) = send_sbd_message(conn, options, plug, "clear") + elif "off" == target_status: + (return_code, out, err) = send_sbd_message(conn, options, plug, "off") + elif "reboot" == target_status: + (return_code, out, err) = send_sbd_message(conn, options, plug, "reset") + + if 0 != return_code: + logging.error("sending message to sbd device(s) \ + failed with return code %d", return_code) + logging.error("DETAIL: output on stdout was \"%s\"", out) + logging.error("DETAIL: output on stderr was \"%s\"", err) + + return not bool(return_code) + +def reboot_cycle(conn, options): + """" trigger reboot by sbd messages + + Key arguments: + conn -- connection structure + options -- options dictionary + + Return Value: + return_code -- action result (bool) + """ + + plug = options["--plug"] + return_code = 99 + out = "" + err = "" + + (return_code, out, err) = send_sbd_message(conn, options, plug, "reset") + return not bool(return_code) + +def get_power_status(conn, options): + """Returns the status of a specific node. + + Key arguments: + conn -- connection structure + options -- option dictionary + + Return Value: + status -- status code (string) + """ + + status = "UNKWNOWN" + plug = options["--plug"] + + nodelist = get_node_list(conn, options) + + # We need to check if the specified plug / node a already a allocated slot + # on the device. + if plug not in nodelist: + logging.error("node \"%s\" not found in node list", plug) + else: + status = nodelist[plug][1] + + + return status + +def translate_status(sbd_status): + """Translates the sbd status to fencing status. + + Key arguments: + sbd_status -- status to translate (string) + + Return Value: + status -- fencing status (string) + """ + + status = "UNKNOWN" + + + # Currently we only accept "clear" to be marked as online. Eventually we + # should also check against "test" + online_status = ["clear"] + + offline_status = ["reset", "off"] + + if any(online_status_element in sbd_status \ + for online_status_element in online_status): + status = "on" + + if any(offline_status_element in sbd_status \ + for offline_status_element in offline_status): + status = "off" + + return status + +def get_node_list(conn, options): + """Returns a list of hostnames, registerd on the sbd device. + + Key arguments: + conn -- connection options + options -- options + + Return Value: + nodelist -- dictionary wich contains all node names and there status + """ + + del conn + + nodelist = {} + + cmd = generate_sbd_command(options, "list") + + (return_code, out, err) = run_commands(options, cmd) + + for line in out.split("\n"): + if len(line) == 0: + continue + + # if we read "unreadable" something went wrong + if "NOT dumped" in line: + return nodelist + + words = line.split() + port = words[1] + sbd_status = words[2] + nodelist[port] = (port, translate_status(sbd_status)) + + return nodelist + +def parse_sbd_devices(options): + """Returns an array of all sbd devices. + + Key arguments: + options -- options dictionary + + Return Value: + devices -- array of device paths + """ + + devices = [str.strip(dev) \ + for dev in str.split(options["--devices"], ",")] + + return devices + +def define_new_opts(): + """Defines the all opt list + """ + all_opt["devices"] = { + "getopt" : ":", + "longopt" : "devices", + "help":"--devices=[device_a,device_b] \ +Comma separated list of sbd devices", + "required" : "1", + "shortdesc" : "SBD Device", + "order": 1 + } + + all_opt["sbd_path"] = { + "getopt" : ":", + "longopt" : "sbd-path", + "help" : "--sbd-path=[path] Path to SBD binary", + "required" : "0", + "default" : "@SBD_PATH@", + "order": 200 + } + +def main(): + """Main function + """ + # We need to define "no_password" otherwise we will be ask about it if + # we don't provide any password. + device_opt = ["no_password", "devices", "port", "method", "sbd_path"] + + # close stdout if we get interrupted + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["method"]["default"] = "cycle" + all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)" + all_opt["power_timeout"]["default"] = "30" + + options = check_input(device_opt, process_input(device_opt)) + + # fill the needed variables to generate metadata and help text output + docs = {} + docs["shortdesc"] = "Fence agent for sbd" + docs["longdesc"] = "fence_sbd is I/O Fencing agent \ +which can be used in environments where sbd can be used (shared storage)." + docs["vendorurl"] = "" + show_docs(options, docs) + + # We need to check if --devices is given and not empty. + if "--devices" not in options: + fail_usage("No SBD devices specified. \ + At least one SBD device is required.") + + run_delay(options) + + # We need to check if the provided sbd_devices exists. We need to do + # that for every given device. + # Just for the case we are really rebooting / powering off a device + # (pacemaker as well uses the list command to generate a dynamic list) + # we leave it to sbd to try and decide if it was successful + if not options["--action"] in ["reboot", "off", "list"]: + for device_path in parse_sbd_devices(options): + logging.debug("check device \"%s\"", device_path) + + return_code = check_sbd_device(options, device_path) + if PATH_NOT_EXISTS == return_code: + logging.error("\"%s\" does not exist", device_path) + elif PATH_NOT_BLOCK == return_code: + logging.error("\"%s\" is not a valid block device", device_path) + elif DEVICE_NOT_INIT == return_code: + logging.error("\"%s\" is not initialized", device_path) + elif DEVICE_INIT != return_code: + logging.error("UNKNOWN error while checking \"%s\"", device_path) + + # If we get any error while checking the device we need to exit at this + # point. + if DEVICE_INIT != return_code: + exit(return_code) + + # we check against the defined timeouts. If the pacemaker timeout is smaller + # then that defined within sbd we should report this. + power_timeout = int(options["--power-timeout"]) + sbd_msg_timeout = get_msg_timeout(options) + if 0 < power_timeout <= sbd_msg_timeout: + logging.warn("power timeout needs to be \ + greater then sbd message timeout") + + result = fence_action(\ + None, \ + options, \ + set_power_status, \ + get_power_status, \ + get_node_list, \ + reboot_cycle) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py new file mode 100644 index 0000000..f9e6823 --- /dev/null +++ b/agents/scsi/fence_scsi.py @@ -0,0 +1,598 @@ +#!@PYTHON@ -tt + +import sys +import stat +import re +import os +import time +import logging +import atexit +import hashlib +import ctypes +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import fail_usage, run_command, atexit_handler, check_input, process_input, show_docs, fence_action, all_opt +from fencing import run_delay + +STORE_PATH = "@STORE_PATH@" + + +def get_status(conn, options): + del conn + status = "off" + for dev in options["devices"]: + is_block_device(dev) + reset_dev(options, dev) + if options["--key"] in get_registration_keys(options, dev): + status = "on" + else: + logging.debug("No registration for key "\ + + options["--key"] + " on device " + dev + "\n") + if options["--action"] == "on": + status = "off" + break + return status + + +def set_status(conn, options): + del conn + count = 0 + if options["--action"] == "on": + set_key(options) + for dev in options["devices"]: + is_block_device(dev) + + register_dev(options, dev) + if options["--key"] not in get_registration_keys(options, dev): + count += 1 + logging.debug("Failed to register key "\ + + options["--key"] + "on device " + dev + "\n") + continue + dev_write(dev, options) + + if get_reservation_key(options, dev) is None \ + and not reserve_dev(options, dev) \ + and get_reservation_key(options, dev) is None: + count += 1 + logging.debug("Failed to create reservation (key="\ + + options["--key"] + ", device=" + dev + ")\n") + + else: + host_key = get_key() + if host_key == options["--key"].lower(): + fail_usage("Failed: keys cannot be same. You can not fence yourself.") + for dev in options["devices"]: + is_block_device(dev) + + if options["--key"] in get_registration_keys(options, dev): + preempt_abort(options, host_key, dev) + + for dev in options["devices"]: + if options["--key"] in get_registration_keys(options, dev): + count += 1 + logging.debug("Failed to remove key "\ + + options["--key"] + " on device " + dev + "\n") + continue + + if not get_reservation_key(options, dev): + count += 1 + logging.debug("No reservation exists on device " + dev + "\n") + if count: + logging.error("Failed to verify " + str(count) + " device(s)") + sys.exit(1) + + +# check if host is ready to execute actions +def do_action_monitor(options): + # Check if required binaries are installed + if bool(run_cmd(options, options["--sg_persist-path"] + " -V")["rc"]): + logging.error("Unable to run " + options["--sg_persist-path"]) + return 1 + elif bool(run_cmd(options, options["--sg_turs-path"] + " -V")["rc"]): + logging.error("Unable to run " + options["--sg_turs-path"]) + return 1 + elif ("--devices" not in options and + bool(run_cmd(options, options["--vgs-path"] + " --version")["rc"])): + logging.error("Unable to run " + options["--vgs-path"]) + return 1 + + # Keys have to be present in order to fence/unfence + get_key() + dev_read() + + return 0 + + +# run command, returns dict, ret["rc"] = exit code; ret["out"] = output; +# ret["err"] = error +def run_cmd(options, cmd): + ret = {} + (ret["rc"], ret["out"], ret["err"]) = run_command(options, cmd) + ret["out"] = "".join([i for i in ret["out"] if i is not None]) + ret["err"] = "".join([i for i in ret["err"] if i is not None]) + return ret + + +# check if device exist and is block device +def is_block_device(dev): + if not os.path.exists(dev): + fail_usage("Failed: device \"" + dev + "\" does not exist") + if not stat.S_ISBLK(os.stat(dev).st_mode): + fail_usage("Failed: device \"" + dev + "\" is not a block device") + + +# cancel registration +def preempt_abort(options, host, dev): + reset_dev(options,dev) + cmd = options["--sg_persist-path"] + " -n -o -A -T 5 -K " + host + " -S " + options["--key"] + " -d " + dev + return not bool(run_cmd(options, cmd)["rc"]) + + +def reset_dev(options, dev): + return run_cmd(options, options["--sg_turs-path"] + " " + dev)["rc"] + + +def register_dev(options, dev): + dev = os.path.realpath(dev) + if re.search(r"^dm", dev[5:]): + for slave in get_mpath_slaves(dev): + register_dev(options, slave) + return True + if get_reservation_key(options, dev, False) == options["--key"]: + return True + reset_dev(options, dev) + cmd = options["--sg_persist-path"] + " -n -o -I -S " + options["--key"] + " -d " + dev + cmd += " -Z" if "--aptpl" in options else "" + #cmd return code != 0 but registration can be successful + return not bool(run_cmd(options, cmd)["rc"]) + + +def reserve_dev(options, dev): + reset_dev(options,dev) + cmd = options["--sg_persist-path"] + " -n -o -R -T 5 -K " + options["--key"] + " -d " + dev + return not bool(run_cmd(options, cmd)["rc"]) + + +def get_reservation_key(options, dev, fail=True): + reset_dev(options,dev) + opts = "" + if "--readonly" in options: + opts = "-y " + cmd = options["--sg_persist-path"] + " -n -i " + opts + "-r -d " + dev + out = run_cmd(options, cmd) + if out["rc"] and fail: + fail_usage('Cannot get reservation key on device "' + dev + + '": ' + out["err"]) + match = re.search(r"\s+key=0x(\S+)\s+", out["out"], re.IGNORECASE) + return match.group(1) if match else None + + +def get_registration_keys(options, dev, fail=True): + reset_dev(options,dev) + keys = [] + opts = "" + if "--readonly" in options: + opts = "-y " + cmd = options["--sg_persist-path"] + " -n -i " + opts + "-k -d " + dev + out = run_cmd(options, cmd) + if out["rc"]: + fail_usage('Cannot get registration keys on device "' + dev + + '": ' + out["err"], fail) + if not fail: + return [] + for line in out["out"].split("\n"): + match = re.search(r"\s+0x(\S+)\s*", line) + if match: + keys.append(match.group(1)) + return keys + + +def get_cluster_id(options): + cmd = options["--corosync-cmap-path"] + " totem.cluster_name" + + match = re.search(r"\(str\) = (\S+)\n", run_cmd(options, cmd)["out"]) + + if not match: + fail_usage("Failed: cannot get cluster name") + + try: + return hashlib.md5(match.group(1).encode('ascii')).hexdigest() + except ValueError: + # FIPS requires usedforsecurity=False and might not be + # available on all distros: https://bugs.python.org/issue9216 + return hashlib.md5(match.group(1).encode('ascii'), usedforsecurity=False).hexdigest() + + +def get_node_id(options): + cmd = options["--corosync-cmap-path"] + " nodelist" + out = run_cmd(options, cmd)["out"] + + match = re.search(r".(\d+).name \(str\) = " + options["--plug"] + "\n", out) + + # try old format before failing + if not match: + match = re.search(r".(\d+).ring._addr \(str\) = " + options["--plug"] + "\n", out) + + return match.group(1) if match else fail_usage("Failed: unable to parse output of corosync-cmapctl or node does not exist") + +def get_node_hash(options): + try: + return hashlib.md5(options["--plug"].encode('ascii')).hexdigest() + except ValueError: + # FIPS requires usedforsecurity=False and might not be + # available on all distros: https://bugs.python.org/issue9216 + return hashlib.md5(options["--plug"].encode('ascii'), usedforsecurity=False).hexdigest() + + +def generate_key(options): + if options["--key-value"] == "hash": + return "%.4s%.4s" % (get_cluster_id(options), get_node_hash(options)) + else: + return "%.4s%.4d" % (get_cluster_id(options), int(get_node_id(options))) + + +# save node key to file +def set_key(options): + file_path = options["store_path"] + ".key" + if not os.path.isdir(os.path.dirname(options["store_path"])): + os.makedirs(os.path.dirname(options["store_path"])) + try: + f = open(file_path, "w") + except IOError: + fail_usage("Failed: Cannot open file \""+ file_path + "\"") + f.write(options["--key"].lower() + "\n") + f.close() + + +# read node key from file +def get_key(fail=True): + file_path = STORE_PATH + ".key" + try: + f = open(file_path, "r") + except IOError: + fail_usage("Failed: Cannot open file \""+ file_path + "\"", fail) + if not fail: + return None + return f.readline().strip().lower() + + +def dev_write(dev, options): + file_path = options["store_path"] + ".dev" + if not os.path.isdir(os.path.dirname(options["store_path"])): + os.makedirs(os.path.dirname(options["store_path"])) + try: + f = open(file_path, "a+") + except IOError: + fail_usage("Failed: Cannot open file \""+ file_path + "\"") + f.seek(0) + out = f.read() + if not re.search(r"^" + dev + "\s+", out, flags=re.MULTILINE): + f.write(dev + "\n") + f.close() + + +def dev_read(fail=True, opt=None): + file_path = STORE_PATH + ".dev" + try: + f = open(file_path, "r") + except IOError: + if "--suppress-errors" not in opt: + fail_usage("Failed: Cannot open file \"" + file_path + "\"", fail) + if not fail: + return None + # get not empty lines from file + devs = [line.strip() for line in f if line.strip()] + f.close() + return devs + + +def get_clvm_devices(options): + devs = [] + cmd = options["--vgs-path"] + " " +\ + "--noheadings " +\ + "--separator : " +\ + "--sort pv_uuid " +\ + "--options vg_attr,pv_name "+\ + "--config 'global { locking_type = 0 } devices { preferred_names = [ \"^/dev/dm\" ] }'" + out = run_cmd(options, cmd) + if out["rc"]: + fail_usage("Failed: Cannot get clvm devices") + for line in out["out"].split("\n"): + if 'c' in line.split(":")[0]: + devs.append(line.split(":")[1]) + return devs + + +def get_mpath_slaves(dev): + if dev[:5] == "/dev/": + dev = dev[5:] + slaves = [i for i in os.listdir("/sys/block/" + dev + "/slaves/") if i[:1] != "."] + if slaves[0][:2] == "dm": + slaves = get_mpath_slaves(slaves[0]) + else: + slaves = ["/dev/" + x for x in slaves] + return slaves + + +def define_new_opts(): + all_opt["devices"] = { + "getopt" : "d:", + "longopt" : "devices", + "help" : "-d, --devices=[devices] List of devices to use for current operation", + "required" : "0", + "shortdesc" : "List of devices to use for current operation. Devices can \ +be comma-separated list of raw devices (eg. /dev/sdc). Each device must support SCSI-3 \ +persistent reservations.", + "order": 1 + } + all_opt["nodename"] = { + "getopt" : ":", + "longopt" : "nodename", + "help" : "", + "required" : "0", + "shortdesc" : "", + "order": 1 + } + all_opt["key"] = { + "getopt" : "k:", + "longopt" : "key", + "help" : "-k, --key=[key] Key to use for the current operation", + "required" : "0", + "shortdesc" : "Key to use for the current operation. This key should be \ +unique to a node. For the \"on\" action, the key specifies the key use to \ +register the local node. For the \"off\" action, this key specifies the key to \ +be removed from the device(s).", + "order": 1 + } + all_opt["aptpl"] = { + "getopt" : "a", + "longopt" : "aptpl", + "help" : "-a, --aptpl Use the APTPL flag for registrations", + "required" : "0", + "shortdesc" : "Use the APTPL flag for registrations. This option is only used for the 'on' action.", + "order": 1 + } + all_opt["readonly"] = { + "getopt" : "", + "longopt" : "readonly", + "help" : "--readonly Open DEVICE read-only. May be useful with PRIN commands if there are unwanted side effects with the default read-write open.", + "required" : "0", + "shortdesc" : "Open DEVICE read-only.", + "order": 4 + } + all_opt["suppress-errors"] = { + "getopt" : "", + "longopt" : "suppress-errors", + "help" : "--suppress-errors Suppress error log. Suppresses error logging when run from the watchdog service before pacemaker starts.", + "required" : "0", + "shortdesc" : "Error log suppression.", + "order": 5 + } + all_opt["logfile"] = { + "getopt" : ":", + "longopt" : "logfile", + "help" : "-f, --logfile Log output (stdout and stderr) to file", + "required" : "0", + "shortdesc" : "Log output (stdout and stderr) to file", + "order": 6 + } + all_opt["corosync_cmap_path"] = { + "getopt" : ":", + "longopt" : "corosync-cmap-path", + "help" : "--corosync-cmap-path=[path] Path to corosync-cmapctl binary", + "required" : "0", + "shortdesc" : "Path to corosync-cmapctl binary", + "default" : "@COROSYNC_CMAPCTL_PATH@", + "order": 300 + } + all_opt["sg_persist_path"] = { + "getopt" : ":", + "longopt" : "sg_persist-path", + "help" : "--sg_persist-path=[path] Path to sg_persist binary", + "required" : "0", + "shortdesc" : "Path to sg_persist binary", + "default" : "@SG_PERSIST_PATH@", + "order": 300 + } + all_opt["sg_turs_path"] = { + "getopt" : ":", + "longopt" : "sg_turs-path", + "help" : "--sg_turs-path=[path] Path to sg_turs binary", + "required" : "0", + "shortdesc" : "Path to sg_turs binary", + "default" : "@SG_TURS_PATH@", + "order": 300 + } + all_opt["vgs_path"] = { + "getopt" : ":", + "longopt" : "vgs-path", + "help" : "--vgs-path=[path] Path to vgs binary", + "required" : "0", + "shortdesc" : "Path to vgs binary", + "default" : "@VGS_PATH@", + "order": 300 + } + all_opt["key_value"] = { + "getopt" : ":", + "longopt" : "key-value", + "help" : "--key-value=<id|hash> SCSI key node generation method", + "required" : "0", + "shortdesc" : "Method used to generate the SCSI key. \"id\" (default) \ +uses the positional ID from \"corosync-cmactl nodelist\" output which can get inconsistent \ +when nodes are removed from cluster without full cluster restart. \"hash\" uses part of hash \ +made out of node names which is not affected over time but there is theoretical chance that \ +hashes can collide as size of SCSI key is quite limited.", + "default" : "id", + "order": 300 + } + + +def scsi_check_get_options(options): + try: + f = open("/etc/sysconfig/stonith", "r") + except IOError: + return options + + match = re.findall(r"^\s*(\S*)\s*=\s*(\S*)\s*", "".join(f.readlines()), re.MULTILINE) + + for m in match: + options[m[0].lower()] = m[1].lower() + + f.close() + + return options + + +def scsi_check(hardreboot=False): + if len(sys.argv) >= 3 and sys.argv[1] == "repair": + return int(sys.argv[2]) + options = {} + options["--sg_turs-path"] = "@SG_TURS_PATH@" + options["--sg_persist-path"] = "@SG_PERSIST_PATH@" + options["--power-timeout"] = "5" + options["retry"] = "0" + options["retry-sleep"] = "1" + options = scsi_check_get_options(options) + if "verbose" in options and options["verbose"] == "yes": + logging.getLogger().setLevel(logging.DEBUG) + devs = dev_read(fail=False,opt=options) + if not devs: + if "--suppress-errors" not in options: + logging.error("No devices found") + return 0 + key = get_key(fail=False) + if not key: + logging.error("Key not found") + return 0 + for dev in devs: + for n in range(int(options["retry"]) + 1): + if n > 0: + logging.debug("retry: " + str(n) + " of " + options["retry"]) + if key in get_registration_keys(options, dev, fail=False): + logging.debug("key " + key + " registered with device " + dev) + return 0 + else: + logging.debug("key " + key + " not registered with device " + dev) + + if n < int(options["retry"]): + time.sleep(float(options["retry-sleep"])) + + logging.debug("key " + key + " registered with any devices") + + if hardreboot == True: + libc = ctypes.cdll['libc.so.6'] + libc.reboot(0x1234567) + return 2 + + +def main(): + + atexit.register(atexit_handler) + + device_opt = ["no_login", "no_password", "devices", "nodename", "port",\ + "no_port", "key", "aptpl", "fabric_fencing", "on_target", "corosync_cmap_path",\ + "sg_persist_path", "sg_turs_path", "readonly", "suppress-errors", "logfile", "vgs_path",\ + "force_on", "key_value"] + + define_new_opts() + + all_opt["delay"]["getopt"] = "H:" + + all_opt["port"]["help"] = "-n, --plug=[nodename] Name of the node to be fenced" + all_opt["port"]["shortdesc"] = "Name of the node to be fenced. The node name is used to \ +generate the key value used for the current operation. This option will be \ +ignored when used with the -k option." + + #fence_scsi_check + if os.path.basename(sys.argv[0]) == "fence_scsi_check": + sys.exit(scsi_check()) + elif os.path.basename(sys.argv[0]) == "fence_scsi_check_hardreboot": + sys.exit(scsi_check(True)) + + options = check_input(device_opt, process_input(device_opt), other_conditions=True) + + # hack to remove list/list-status actions which are not supported + options["device_opt"] = [ o for o in options["device_opt"] if o != "separator" ] + + docs = {} + docs["shortdesc"] = "Fence agent for SCSI persistent reservation" + docs["longdesc"] = "fence_scsi is an I/O fencing agent that uses SCSI-3 \ +persistent reservations to control access to shared storage devices. These \ +devices must support SCSI-3 persistent reservations (SPC-3 or greater) as \ +well as the \"preempt-and-abort\" subcommand.\nThe fence_scsi agent works by \ +having each node in the cluster register a unique key with the SCSI \ +device(s). Reservation key is generated from \"node id\" (default) or from \ +\"node name hash\" (RECOMMENDED) by adjusting \"key_value\" option. \ +Using hash is recommended to prevent issues when removing nodes \ +from cluster without full cluster restart. \ +Once registered, a single node will become the reservation holder \ +by creating a \"write exclusive, registrants only\" reservation on the \ +device(s). The result is that only registered nodes may write to the \ +device(s). When a node failure occurs, the fence_scsi agent will remove the \ +key belonging to the failed node from the device(s). The failed node will no \ +longer be able to write to the device(s). A manual reboot is required.\ +\n.P\n\ +When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and \ +verbose=yes parameters in /etc/sysconfig/stonith if you have issues with it \ +failing." + docs["vendorurl"] = "" + show_docs(options, docs) + + run_delay(options) + + # backward compatibility layer BEGIN + if "--logfile" in options: + try: + logfile = open(options["--logfile"], 'w') + sys.stderr = logfile + sys.stdout = logfile + except IOError: + fail_usage("Failed: Unable to create file " + options["--logfile"]) + # backward compatibility layer END + + options["store_path"] = STORE_PATH + + # Input control BEGIN + stop_after_error = False if options["--action"] == "validate-all" else True + + if options["--action"] == "monitor": + sys.exit(do_action_monitor(options)) + + # workaround to avoid regressions + if "--nodename" in options and options["--nodename"]: + options["--plug"] = options["--nodename"] + del options["--nodename"] + + if not (("--plug" in options and options["--plug"])\ + or ("--key" in options and options["--key"])): + fail_usage("Failed: nodename or key is required", stop_after_error) + + if options["--action"] != "validate-all": + if not ("--key" in options and options["--key"]): + options["--key"] = generate_key(options) + + if options["--key"] == "0" or not options["--key"]: + fail_usage("Failed: key cannot be 0", stop_after_error) + + if "--key-value" in options\ + and (options["--key-value"] != "id" and options["--key-value"] != "hash"): + fail_usage("Failed: key-value has to be 'id' or 'hash'", stop_after_error) + + if options["--action"] == "validate-all": + sys.exit(0) + + options["--key"] = options["--key"].lstrip('0') + + if not ("--devices" in options and options["--devices"].split(",")): + options["devices"] = get_clvm_devices(options) + else: + options["devices"] = options["--devices"].split(",") + + if not options["devices"]: + fail_usage("Failed: No devices found") + # Input control END + + result = fence_action(None, options, set_status, get_status) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/skalar/fence_skalar.py b/agents/skalar/fence_skalar.py new file mode 100644 index 0000000..0e11d83 --- /dev/null +++ b/agents/skalar/fence_skalar.py @@ -0,0 +1,226 @@ +#!@PYTHON@ -tt +# -*- coding: utf-8 -*- + +import sys +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, EC_STATUS, EC_LOGIN_DENIED, EC_INVALID_PRIVILEGES, run_delay +import requests +import ast +import urllib3 +import json +import logging + +from requests.exceptions import ConnectionError + + +################################################################################### +# Inner functions + + +def authorize_and_get_cookie(skala_ip, login, password, options): + URL0 = proto + str(skala_ip) + '/api/0/auth' + cred = { + "login" : str(login), + "password" : str(password) + } + + try: + with requests.Session() as session: + session.post(url=URL0, data=cred, verify=ssl_verify) + cookie = session.cookies.get_dict() + except: + logging.exception('Exception occured.') + fail(EC_LOGIN_DENIED) + if 'api_token' in cookie: + return cookie + else: + fail(EC_LOGIN_DENIED) + + +def logout(skala_ip): + URL1 = proto + str(skala_ip) + '/api/0/logout' + + try: + with requests.Session() as session: + session.post(url=URL1, verify=ssl_verify, cookies=cookie) + except: + ## Logout; we do not care about result as we will end in any case + pass + + +def get_vm_id(skala_ip, uuid, options, cookie): + URL2 = proto + str(skala_ip) + '/api/0/vm' + parameters = { + "uuid": str(uuid) + } + + vm_info = requests.get(url=URL2, verify=ssl_verify, params=parameters, cookies=cookie) + jvm_info = vm_info.json() + if jvm_info["vm_list"]["items"] == []: + raise NameError('Can not find VM by uuid.') + logging.debug("VM_INFO:\n{}".format(json.dumps(vm_info.json(), indent=4, sort_keys=True))) + return jvm_info["vm_list"]["items"][0]["vm_id"] + + +def vm_task(skala_ip, vm_id, command, options, cookie): + + # command(str) – Command for vm: ‘vm_start’, ‘vm_stop’, ‘vm_restart’, + # ‘vm_suspend’, ‘vm_resume’, ‘vm_pause’, ‘vm_reset’ + # main_request_id(TaskId) – Parent task id + # graceful(bool) – vm_stop command parameter, graceful or not, default + # false - *args[0] + # force(bool) – vm_stop command parameter, force stop or not, default + # false - *args[1] + + if "--graceful" in options: + graceful = True + else: + graceful = False + if "--force" in options: + force = True + else: + force = False + + URL3 = proto + str(skala_ip) + '/api/0/vm/' + str(vm_id) + '/task' + + logging.debug("vm_task skala_ip: " + str(skala_ip)) + logging.debug("vm_task vm_id: " + str(vm_id)) + logging.debug("vm_task command: " + str(command)) + logging.debug("vm_task cookie: " + str(cookie)) + + + def checking(vm_id, command, graceful, force): + firstcondition = type(vm_id) is int + secondcondition = command in ['vm_start', 'vm_stop', 'vm_restart', 'vm_suspend', 'vm_resume', 'vm_pause', 'vm_reset'] + thirdcondition = type(graceful) is bool + fourthcondition = type(force) is bool + return firstcondition * secondcondition * thirdcondition * fourthcondition + + if not checking(vm_id, command, graceful, force): + print('Wrong parameters! \n' + 'command(str) – Command for vm: ‘vm_start’, ‘vm_stop’, \n' + '‘vm_restart’,‘vm_suspend’, ‘vm_resume’, ‘vm_pause’, ‘vm_reset’ \n' + 'graceful(bool) – vm_stop command parameter, graceful or not, default false \n' + 'force(bool) – vm_stop command parameter, force stop or not, default false \n' + ) + else: + parameters = { + "command": command, + "graceful": graceful, + "force": force + } + + with requests.Session() as session: + response = session.post(url=URL3, params=parameters, verify=ssl_verify, cookies=cookie) + if response.status_code != 200: + raise Exception('Invalid response code from server: {}.'.format(response.status_code)) + return + +###################################################################################### + +def get_power_status(conn, options): + state = {"RUNNING": "on", "PAUSED": "on", "STOPPED": "off", "SUSPENDED": "off", "ERROR": "off", "DELETED": "off", + "CREATING": "off", "FAILED_TO_CREATE": "off", "NODE_OFFLINE": "off", "STARTING": "off", "STOPPING": "on"} + + URL4 = proto + options["--ip"] + '/api/0/vm/' + parameters = { + "uuid": str(options["--plug"]) + } + + vm_info = requests.get(url=URL4, params=parameters, verify=ssl_verify, cookies=cookie) + jvm_info = vm_info.json() + if jvm_info["vm_list"]["items"] == []: + raise NameError('Can not find VM by uuid.') + logging.debug("VM_INFO:\n{}".format(json.dumps(vm_info.json(), indent=4, sort_keys=True))) + status_v = jvm_info["vm_list"]["items"][0]["status"] + if status_v not in state: + raise Exception('Unknown VM state: {}.'.format(status_v)) + return state[status_v] + + +def set_power_status(conn, options): + action = { + "on" : "vm_start", + "reboot": "vm_restart", + "off" : "vm_stop" + } + + vm_id_v = get_vm_id(options["--ip"], options["--plug"], options, cookie) + vm_task(options["--ip"], vm_id_v, action[options["--action"]], options, cookie) + return + + +def get_list(conn, options): + outlets = {} + URL5 = proto + options["--ip"] + '/api/0/vm' + + vm_info = requests.get(url=URL5, verify=ssl_verify, cookies=cookie) + jvm_info = vm_info.json() + list_jvm = jvm_info["vm_list"]["items"] + for elem in list_jvm: + outlets[elem["name"]] = (elem["uuid"], None) + return outlets + + +def define_new_opts(): + all_opt["graceful"] = { + "getopt" : "", + "longopt" : "graceful", + "help" : "--graceful vm_stop command parameter, graceful stop or not, default false", + "required" : "0", + "shortdesc" : "vm_stop command parameter, graceful stop or not, default false", + "order" : 1} + + all_opt["force"] = { + "getopt" : "", + "longopt" : "force", + "help" : "--force vm_stop command parameter, force stop or not, default false", + "required" : "0", + "shortdesc" : "vm_stop command parameter, force stop or not, default false", + "order" : 1} + + +def main(): + global cookie, proto, ssl_verify + define_new_opts() + device_opt = ["ipaddr", "login", "passwd", "port", "web", "ssl", "verbose", "graceful", "force"] + + atexit.register(atexit_handler) + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Skala-R Fence agent" + docs["longdesc"] = "A fence agent for Skala-R." + docs["vendorurl"] = "https://www.skala-r.ru/" + show_docs(options, docs) + options["eol"] = "\r" + + run_delay(options) + + proto = "https://" + if "--ssl-secure" in options: + ssl_verify = True + elif "--ssl-insecure" in options: + ssl_verify = False + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + else: + proto = "http://" + ssl_verify = False + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + cookie = authorize_and_get_cookie(options["--ip"], options["--username"], options["--password"], options) + atexit.register(logout, options["--ip"]) + + logging.debug("OPTIONS: " + str(options) + "\n") + + try: + result = fence_action(None, options, set_power_status, get_power_status, get_list) + sys.exit(result) + except Exception: + logging.exception('Exception occured.') + fail(EC_STATUS) + +if __name__ == "__main__": + main() diff --git a/agents/vbox/fence_vbox.py b/agents/vbox/fence_vbox.py new file mode 100644 index 0000000..c2df288 --- /dev/null +++ b/agents/vbox/fence_vbox.py @@ -0,0 +1,135 @@ +#!@PYTHON@ -tt + +# The Following Agent Has Been Tested On: +# +# VirtualBox 5.0.4 x64 on openSUSE 13.2 +# + +import sys +import re +import time +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") + +from fencing import * +from fencing import fail_usage + +def _invoke(conn, options, *cmd): + prefix = options["--sudo-path"] + " " if "--use-sudo" in options else "" + conn.send_eol(prefix + options["--vboxmanage-path"] + " " + " ".join(cmd)) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + +def get_outlets_status(conn, options): + _domain_re = re.compile(r'^\"(.*)\" \{(.*)\}$') + result = {} + + _invoke(conn, options, "list", "vms") + for line in conn.before.splitlines(): + # format: "<domain>" {<uuid>} + domain = _domain_re.search(line.strip()) + if domain is not None: + result[domain.group(1)] = (domain.group(2), "off") + + _invoke(conn, options, "list", "runningvms") + for line in conn.before.splitlines(): + # format: "<domain>" {<uuid>} + domain = _domain_re.search(line.strip()) + if domain is not None: + result[domain.group(1)] = (domain.group(2), "on") + + return result + + +def get_power_status(conn, options): + outlets = get_outlets_status(conn, options) + + if options["--plug"] in outlets: + return outlets[options["--plug"]][1] + + right_uuid_line = [outlets[o] for o in outlets.keys() if outlets[o][0] == options["--plug"]] + + if len(right_uuid_line): + return right_uuid_line[0][1] + + if "--missing-as-off" in options: + return "off" + + fail_usage("Failed: You have to enter existing name/UUID of virtual machine!") + + +def set_power_status(conn, options): + if options["--action"] == "on": + _invoke(conn, options, "startvm", '"%s"' % options["--plug"], "--type", "headless") + else: + _invoke(conn, options, "controlvm", '"%s"' % options["--plug"], "poweroff") + +def define_new_opts(): + all_opt["vboxmanage_path"] = { + "getopt" : ":", + "longopt" : "vboxmanage-path", + "help" : "--vboxmanage-path=[path] Path to VBoxManage on the host", + "required" : "0", + "shortdesc" : "Path to VBoxManage on the host", + "default" : "VBoxManage", + "order" : 200 + } + all_opt["host_os"] = { + "getopt" : ":", + "longopt" : "host-os", + "help" : "--host-os=[os] Operating system of the host", + "required" : "0", + "shortdesc" : "Operating system of the host", + "choices" : ["linux", "macos", "windows"], + "default" : "linux", + "order" : 200 + } + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "sudo", + "missing_as_off", "vboxmanage_path", "host_os"] + define_new_opts() + + atexit.register(atexit_handler) + + all_opt["secure"]["default"] = "1" + + all_opt["cmd_prompt"]["default"] = [r"\[EXPECT\]#"] + all_opt["ssh_options"]["default"] = "-t '/bin/bash -c \"" + r"PS1=\\[EXPECT\\]# HISTFILE=/dev/null " + "/bin/bash --noprofile --norc\"'" + + opt = process_input(device_opt) + + opt["logout_string"] = "quit" + if "--host-os" in opt and "--vboxmanage-path" not in opt: + if opt["--host-os"] == "linux": + opt["--vboxmanage-path"] = "VBoxManage" + elif opt["--host-os"] == "macos": + opt["--vboxmanage-path"] = "/Applications/VirtualBox.app/Contents/MacOS/VBoxManage" + opt["logout_string"] = "exit" + elif opt["--host-os"] == "windows": + opt["--vboxmanage-path"] = "\"/Program Files/Oracle/VirtualBox/VBoxManage.exe" + opt["--command-prompt"] = "" + opt["--ssh-options"] = "" + + options = check_input(device_opt, opt) + options["eol"] = "\n" + + docs = {} + docs["shortdesc"] = "Fence agent for VirtualBox" + docs["longdesc"] = "fence_vbox is an I/O Fencing agent \ +which can be used with the virtual machines managed by VirtualBox. \ +It logs via ssh to a dom0 where it runs VBoxManage to do all of \ +the work. \ +\n.P\n\ +By default, vbox needs to log in as a user that is a member of the \ +vboxusers group. Also, you must allow ssh login in your sshd_config." + docs["vendorurl"] = "https://www.virtualbox.org/" + show_docs(options, docs) + + # Operate the fencing device + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, get_outlets_status) + fence_logout(conn, opt["logout_string"]) + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/virsh/fence_virsh.py b/agents/virsh/fence_virsh.py new file mode 100644 index 0000000..88cee48 --- /dev/null +++ b/agents/virsh/fence_virsh.py @@ -0,0 +1,96 @@ +#!@PYTHON@ -tt + +# The Following Agent Has Been Tested On: +# +# Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 +# + +import sys, re +import time +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail_usage + +def get_name_or_uuid(options): + return options["--uuid"] if "--uuid" in options else options["--plug"] + +def get_outlets_status(conn, options): + if "--use-sudo" in options: + prefix = options["--sudo-path"] + " " + else: + prefix = "" + + conn.sendline(prefix + "virsh list --all") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + result = {} + + #This is status of mini finite automata. 0 = we didn't found Id and Name, 1 = we did + fa_status = 0 + + for line in conn.before.splitlines(): + domain = re.search(r"^\s*(\S+)\s+(\S+)\s+(\S+).*$", line) + + if domain != None: + if fa_status == 0 and domain.group(1).lower() == "id" and domain.group(2).lower() == "name": + fa_status = 1 + elif fa_status == 1: + result[domain.group(2)] = ("", + (domain.group(3).lower() in ["running", "blocked", "idle", "no state", "paused"] and "on" or "off")) + return result + +def get_power_status(conn, options): + prefix = options["--sudo-path"] + " " if "--use-sudo" in options else "" + conn.sendline(prefix + "virsh domstate %s" % (get_name_or_uuid(options))) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + for line in conn.before.splitlines(): + if line.strip() in ["running", "blocked", "idle", "no state", "paused"]: + return "on" + if "error: failed to get domain" in line.strip() and "--missing-as-off" in options: + return "off" + if "error:" in line.strip(): + fail_usage("Failed: You have to enter existing name/UUID of virtual machine!") + + return "off" + +def set_power_status(conn, options): + prefix = options["--sudo-path"] + " " if "--use-sudo" in options else "" + conn.sendline(prefix + "virsh %s " % + (options["--action"] == "on" and "start" or "destroy") + get_name_or_uuid(options)) + + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + time.sleep(int(options["--power-wait"])) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "sudo", "missing_as_off"] + + atexit.register(atexit_handler) + + all_opt["secure"]["default"] = "1" + all_opt["cmd_prompt"]["default"] = [r"\[EXPECT\]#"] + all_opt["ssh_options"]["default"] = "-t '/bin/bash -c \"" + r"PS1=\\[EXPECT\\]# " + "/bin/bash --noprofile --norc\"'" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for virsh" + docs["longdesc"] = "fence_virsh is an I/O Fencing agent \ +which can be used with the virtual machines managed by libvirt. \ +It logs via ssh to a dom0 and there run virsh command, which does \ +all work. \ +\n.P\n\ +By default, virsh needs root account to do properly work. So you \ +must allow ssh login in your sshd_config." + docs["vendorurl"] = "http://libvirt.org" + show_docs(options, docs) + + ## Operate the fencing device + conn = fence_login(options) + result = fence_action(conn, options, set_power_status, get_power_status, get_outlets_status) + fence_logout(conn, "quit") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/virt/Makefile.am b/agents/virt/Makefile.am new file mode 100644 index 0000000..4f50c60 --- /dev/null +++ b/agents/virt/Makefile.am @@ -0,0 +1,31 @@ +############################################################################### +############################################################################### +## +## Copyright (C) 2009-2021 Red Hat, Inc. +## +## This copyrighted material is made available to anyone wishing to use, +## modify, copy, or redistribute it subject to the terms and conditions +## of the GNU General Public License v.2. +## +############################################################################### +############################################################################### + +MAINTAINERCLEANFILES = Makefile.in + +EXTRA_DIST = docs/architecture.txt docs/fence_virt.txt \ + docs/README docs/TODO include \ + fence_virtd.service.in + +SUBDIRS = config common client server man + +all-local: fence_virtd.service + +clean-local: + rm -f $(SPEC) fence_virtd.service + +fence_virtd.service: fence_virtd.service.in + SBINDIR="@sbindir@"; \ + INITCONFDIR="@initconfdir@"; \ + cat $^ > $@ ; \ + echo "EnvironmentFile=-$$INITCONFDIR/fence_virtd" >> $@ ;\ + echo "ExecStart=$$SBINDIR/fence_virtd \$$FENCE_VIRTD_ARGS" >> $@ diff --git a/agents/virt/client/Makefile.am b/agents/virt/client/Makefile.am new file mode 100644 index 0000000..4a1997b --- /dev/null +++ b/agents/virt/client/Makefile.am @@ -0,0 +1,40 @@ +############################################################################### +############################################################################### +## +## Copyright (C) 2009-2019 Red Hat, Inc. +## +## This copyrighted material is made available to anyone wishing to use, +## modify, copy, or redistribute it subject to the terms and conditions +## of the GNU General Public License v.2 +## +############################################################################### +############################################################################### + +MAINTAINERCLEANFILES = Makefile.in + +sbin_PROGRAMS = fence_virt + +TARGET = $(sbin_PROGRAMS) + +fence_virt_SOURCES = mcast.c serial.c main.c options.c tcp.c vsock.c + +fence_virt_CFLAGS = $(VIRT_AM_CFLAGS) $(nss_CFLAGS) $(xml2_CFLAGS) $(PTHREAD_CFLAGS) $(AM_CFLAGS) + +fence_virt_LDFLAGS = $(VIRT_AM_LDFLAGS) $(COMMON_LDFLAGS) +fence_virt_LDADD = $(VIRT_COMMON_LIBS) $(nss_LIBS) $(xml2_LIBS) $(PTHREAD_LIBS) + +if xvmcompat +install-exec-hook: fence_virt + (cd $(DESTDIR)/${sbindir}; $(LN_S) -nf $^ fence_xvm) + +uninstall-hook: + (cd $(DESTDIR)/${sbindir}; rm -f fence_xvm) +endif + +fence_virt.delay-check: fence_virt + $(eval INPUT=$(subst .delay-check,,$@)) + test `/usr/bin/time -p ./$(INPUT) -w 10 -n test $(FENCE_TEST_ARGS) -- 2>&1 |\ + awk -F"[. ]" -vOFS= '/real/ {print $$2,$$3}' | tail -n 1` -ge 1000 || \ + /usr/bin/time -p ./$(INPUT) -w 0 -n test $(FENCE_TEST_ARGS) -- + +include $(top_srcdir)/make/agentccheck.mk diff --git a/agents/virt/client/main.c b/agents/virt/client/main.c new file mode 100644 index 0000000..188c05d --- /dev/null +++ b/agents/virt/client/main.c @@ -0,0 +1,198 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +/* + * Author: Lon Hohberger <lhh at redhat.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/time.h> +#include <errno.h> +#include <pthread.h> +#include <libgen.h> +#include <syslog.h> + +/* Local includes */ +#include "xvm.h" +#include "options.h" +#include "debug.h" +#include "client.h" + + +int +main(int argc, char **argv) +{ + fence_virt_args_t args; + const char *my_options; + int ret = 0; + + args_init(&args); + if (!strcmp(basename(argv[0]), "fence_xvm")) { + my_options = "di:a:p:r:C:c:k:M:n:H:uo:t:?hVw:"; + args.mode = MODE_MULTICAST; + } else { + my_options = "dD:P:A:p:M:n:H:o:t:?hVT:S::C:c:k:w:"; + args.mode = MODE_SERIAL; + } + + if (argc == 1) { + args_get_stdin(my_options, &args); + } else { + args_get_getopt(argc, argv, my_options, &args); + } + + if (args.flags & F_HELP) { + args_usage(argv[0], my_options, 0); + + printf("With no command line argument, arguments are " + "read from standard input.\n"); + printf("Arguments read from standard input take " + "the form of:\n\n"); + printf(" arg1=value1\n"); + printf(" arg2=value2\n\n"); + + args_usage(argv[0], my_options, 1); + exit(0); + } + + if (args.flags & F_VERSION) { + printf("%s %s\n", basename(argv[0]), XVM_VERSION); +#ifdef VERSION + printf("fence release %s\n", VERSION); +#endif + exit(0); + } + + openlog(basename(argv[0]), LOG_NDELAY | LOG_PID, LOG_DAEMON); + + args_finalize(&args); + dset(args.debug); + + if (args.debug > 0) + args_print(&args); + + /* Additional validation here */ + if (!args.domain && (args.op != FENCE_DEVSTATUS && + args.op != FENCE_HOSTLIST && + args.op != FENCE_METADATA)) { + printf("No domain specified!\n"); + syslog(LOG_NOTICE, "No domain specified"); + args.flags |= F_ERR; + } + + if (args.net.ipaddr) + args.mode = MODE_TCP; + + if (args.net.cid >= 2) + args.mode = MODE_VSOCK; + + if (args.flags & F_ERR) { + if (args.op != FENCE_VALIDATEALL) + args_usage(argv[0], my_options, (argc == 1)); + exit(1); + } + + if (args.op == FENCE_VALIDATEALL) + exit(0); + + if (args.op == FENCE_METADATA) { + args_metadata(argv[0], my_options); + exit(0); + } + + if (args.delay > 0 && + args.op != FENCE_STATUS && + args.op != FENCE_DEVSTATUS && + args.op != FENCE_HOSTLIST) + sleep(args.delay); + + switch(args.mode) { + case MODE_MULTICAST: + ret = mcast_fence_virt(&args); + break; + case MODE_SERIAL: + ret = serial_fence_virt(&args); + break; + case MODE_TCP: + ret = tcp_fence_virt(&args); + break; + case MODE_VSOCK: + ret = vsock_fence_virt(&args); + break; + default: + ret = 1; + goto out; + } + + switch(ret) { + case RESP_OFF: + if (args.op == FENCE_STATUS) + printf("Status: OFF\n"); + else if (args.domain) + syslog(LOG_NOTICE, "Domain \"%s\" is OFF", args.domain); + break; + case 0: + if (args.op == FENCE_STATUS) + printf("Status: ON\n"); + else if (args.domain) + syslog(LOG_NOTICE, "Domain \"%s\" is ON", args.domain); + break; + case RESP_FAIL: + if (args.domain) { + syslog(LOG_NOTICE, "Fence operation failed for domain \"%s\"", + args.domain); + } else + syslog(LOG_NOTICE, "Fence operation failed"); + printf("Operation failed\n"); + break; + case RESP_PERM: + if (args.domain) { + syslog(LOG_NOTICE, + "Permission denied for Fence operation for domain \"%s\"", + args.domain); + } else + syslog(LOG_NOTICE, "Permission denied for fence operation"); + printf("Permission denied\n"); + break; + default: + if (args.domain) { + syslog(LOG_NOTICE, "Unknown response (%d) for domain \"%s\"", + ret, args.domain); + } else + syslog(LOG_NOTICE, "Unknown response (%d)", ret); + printf("Unknown response (%d)\n", ret); + break; + } + +out: + closelog(); + exit(ret); +} diff --git a/agents/virt/client/mcast.c b/agents/virt/client/mcast.c new file mode 100644 index 0000000..42f0a6b --- /dev/null +++ b/agents/virt/client/mcast.c @@ -0,0 +1,393 @@ +/* + Copyright Red Hat, Inc. 2006-2017 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +/* + * Author: Lon Hohberger <lhh at redhat.com> + */ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/time.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <libgen.h> +#include <nss.h> + +/* Local includes */ +#include "xvm.h" +#include "ip_lookup.h" +#include "simple_auth.h" +#include "options.h" +#include "tcp.h" +#include "mcast.h" +#include "debug.h" +#include "fdops.h" +#include "client.h" + + +static int +tcp_wait_connect(int lfd, int retry_tenths) +{ + int fd; + fd_set rfds; + int n; + struct timeval tv; + + dbg_printf(3, "Waiting for connection from XVM host daemon.\n"); + FD_ZERO(&rfds); + FD_SET(lfd, &rfds); + tv.tv_sec = retry_tenths / 10; + tv.tv_usec = (retry_tenths % 10) * 100000; + + n = select(lfd + 1, &rfds, NULL, NULL, &tv); + if (n == 0) { + errno = ETIMEDOUT; + return -1; + } else if (n < 0) { + return -1; + } + + fd = accept(lfd, NULL, 0); + if (fd < 0) + return -1; + + return fd; +} + + +void +do_read_hostlist(int fd, int timeout) +{ + host_state_t hinfo; + fd_set rfds; + struct timeval tv; + int ret; + + do { + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = timeout; + tv.tv_usec = 0; + + ret = _select_retry(fd+1, &rfds, NULL, NULL, &tv); + if (ret == 0) { + printf("Timed out!\n"); + break; + } + + ret = _read_retry(fd, &hinfo, sizeof(hinfo), &tv); + if (ret < sizeof(hinfo)) { + printf("Bad read!\n"); + break; + } + + if (strlen((char *)hinfo.uuid) == 0 && + strlen((char *)hinfo.domain) == 0) + break; + + printf("%-32s %s %s\n", hinfo.domain, hinfo.uuid, + (hinfo.state == 1) ? "on" : "off"); + } while (1); +} + + +static int +tcp_exchange(int fd, fence_auth_type_t auth, void *key, + size_t key_len, int timeout) +{ + fd_set rfds; + struct timeval tv; + char ret = 1; + + /* Ok, we're connected */ + dbg_printf(3, "Issuing TCP challenge\n"); + if (sock_challenge(fd, auth, key, key_len, timeout) <= 0) { + /* Challenge failed */ + printf("Invalid response to challenge\n"); + return 1; + } + + /* Now they'll send us one, so we need to respond here */ + dbg_printf(3, "Responding to TCP challenge\n"); + if (sock_response(fd, auth, key, key_len, timeout) <= 0) { + printf("Invalid response to challenge\n"); + return 1; + } + + dbg_printf(2, "TCP Exchange + Authentication done... \n"); + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = timeout; + tv.tv_usec = 0; + + ret = 1; + dbg_printf(3, "Waiting for return value from XVM host\n"); + if (_select_retry(fd + 1, &rfds, NULL, NULL, &tv) <= 0) + return -1; + + /* Read return code */ + if (_read_retry(fd, &ret, 1, &tv) < 0) + ret = 1; + + if (ret == (char)RESP_HOSTLIST) /* hostlist */ { + do_read_hostlist(fd, timeout); + ret = 0; + } + + return ret; +} + + +static int +send_multicast_packets(ip_list_t *ipl, fence_virt_args_t *args, + uint32_t seqno, void *key, size_t key_len) +{ + fence_req_t freq; + int mc_sock; + ip_addr_t *ipa; + struct sockaddr_in tgt4; + struct sockaddr_in6 tgt6; + struct sockaddr *tgt; + socklen_t tgt_len; + + for (ipa = ipl->tqh_first; ipa; ipa = ipa->ipa_entries.tqe_next) { + + if (ipa->ipa_family != args->net.family) { + dbg_printf(2, "Ignoring %s: wrong family\n", ipa->ipa_address); + continue; + } + + if (args->net.family == PF_INET) { + mc_sock = ipv4_send_sk(ipa->ipa_address, args->net.addr, + args->net.port, + (struct sockaddr *)&tgt4, + sizeof(struct sockaddr_in)); + tgt = (struct sockaddr *)&tgt4; + tgt_len = sizeof(tgt4); + } else if (args->net.family == PF_INET6) { + mc_sock = ipv6_send_sk(ipa->ipa_address, args->net.addr, + args->net.port, + (struct sockaddr *)&tgt6, + sizeof(struct sockaddr_in6)); + tgt = (struct sockaddr *)&tgt6; + tgt_len = sizeof(tgt6); + } else { + dbg_printf(2, "Unsupported family %d\n", args->net.family); + return -1; + } + + if (mc_sock < 0) + continue; + + /* Build our packet */ + memset(&freq, 0, sizeof(freq)); + if (args->domain && strlen((char *)args->domain)) { + strncpy((char *)freq.domain, args->domain, + sizeof(freq.domain) - 1); + } + freq.request = args->op; + freq.hashtype = args->net.hash; + freq.seqno = seqno; + + /* Store source address */ + if (ipa->ipa_family == PF_INET) { + freq.addrlen = sizeof(struct in_addr); + /* XXX Swap order for in_addr ? XXX */ + if (inet_pton(PF_INET, ipa->ipa_address, freq.address) != 1) { + dbg_printf(2, "Unable to convert address\n"); + close(mc_sock); + return -1; + } + } else if (ipa->ipa_family == PF_INET6) { + freq.addrlen = sizeof(struct in6_addr); + if (inet_pton(PF_INET6, ipa->ipa_address, freq.address) != 1) { + dbg_printf(2, "Unable to convert address\n"); + close(mc_sock); + return -1; + } + } + + freq.flags = 0; + if (args->flags & F_USE_UUID) + freq.flags |= RF_UUID; + freq.family = ipa->ipa_family; + freq.port = args->net.port; + + sign_request(&freq, key, key_len); + + dbg_printf(3, "Sending to %s via %s\n", args->net.addr, + ipa->ipa_address); + + if(sendto(mc_sock, &freq, sizeof(freq), 0, + (struct sockaddr *)tgt, tgt_len) < 0) { + dbg_printf(3, "Unable to send packet to %s via %s\n", + args->net.addr, ipa->ipa_address); + } + + close(mc_sock); + } + + return 0; +} + + +/* TODO: Clean this up!!! */ +int +mcast_fence_virt(fence_virt_args_t *args) +{ + ip_list_t ipl; + char key[MAX_KEY_LEN]; + struct timeval tv; + int lfd = -1, key_len = 0, fd, ret; + int attempts = 0; + uint32_t seqno; + + /* Initialize NSS; required to do hashing, as silly as that + sounds... */ + if (NSS_NoDB_Init(NULL) != SECSuccess) { + printf("Could not initialize NSS\n"); + return 1; + } + + if (args->net.auth != AUTH_NONE || args->net.hash != HASH_NONE) { + key_len = read_key_file(args->net.key_file, key, sizeof(key)); + if (key_len < 0) { + printf("Could not read %s; trying without " + "authentication\n", args->net.key_file); + args->net.auth = AUTH_NONE; + args->net.hash = HASH_NONE; + key_len = 0; + } + } + + /* Do the real work */ + if (ip_build_list(&ipl) < 0) { + printf("Error building IP address list\n"); + return 1; + } + + attempts = args->timeout * 10 / args->retr_time; + + listen_loop: + do { + switch (args->net.auth) { + case AUTH_NONE: + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + if (args->net.family == PF_INET) { + lfd = ipv4_listen(NULL, args->net.port, 10); + } else { + lfd = ipv6_listen(NULL, args->net.port, 10); + } + break; + /*case AUTH_X509:*/ + /* XXX Setup SSL listener socket here */ + default: + return 1; + } + + if (lfd < 0) { + printf("Failed to listen: %s\n", strerror(errno)); + usleep(args->retr_time * 100000); + if (--attempts > 0) + goto listen_loop; + } + } while (0); + + if (lfd < 0) + return -1; + + gettimeofday(&tv, NULL); + seqno = (uint32_t)tv.tv_usec; + + do { + if (send_multicast_packets(&ipl, args, seqno, + key, key_len)) { + close(lfd); + return -1; + } + + switch (args->net.auth) { + case AUTH_NONE: + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + fd = tcp_wait_connect(lfd, args->retr_time); + if (fd < 0 && (errno == ETIMEDOUT || + errno == EINTR)) + continue; + break; + /* case AUTH_X509: + ... = ssl_wait_connect... */ + break; + default: + close(lfd); + return 1; + } + + break; + } while (--attempts); + + if (lfd >= 0) + close(lfd); + + if (fd < 0) { + if (attempts <= 0) { + printf("Timed out waiting for response\n"); + return 1; + } + printf("Operation failed: %s\n", strerror(errno)); + return -1; + } + + switch (args->net.auth) { + case AUTH_NONE: + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + ret = tcp_exchange(fd, args->net.auth, key, key_len, + args->timeout); + break; + /* case AUTH_X509: + return ssl_exchange(...); */ + default: + ret = 1; + break; + } + + close(fd); + return ret; +} diff --git a/agents/virt/client/options.c b/agents/virt/client/options.c new file mode 100644 index 0000000..ddd6bc4 --- /dev/null +++ b/agents/virt/client/options.c @@ -0,0 +1,1000 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/time.h> +#include <fcntl.h> +#include <errno.h> +#include <libgen.h> + +/* Local includes */ +#include "xvm.h" +#include "simple_auth.h" +#include "mcast.h" +#include "tcp_listener.h" +#include "options.h" + +#define SCHEMA_COMPAT '\xfe' + + +/* Assignment functions */ + +static inline void +assign_debug(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) { + /* GNU getopt sets optarg to NULL for options w/o a param + We rely on this here... */ + args->debug++; + return; + } + + args->debug = atoi(value); + if (args->debug < 0) { + args->debug = 1; + } +} + + +static inline void +assign_family(fence_virt_args_t *args, struct arg_info *arg, + char *value) +{ + if (!value) + return; + + if (!strcasecmp(value, "ipv4")) { + args->net.family = PF_INET; + } else if (!strcasecmp(value, "ipv6")) { + args->net.family = PF_INET6; + } else if (!strcasecmp(value, "auto")) { + args->net.family = 0; + } else { + printf("Unsupported family: '%s'\n", value); + args->flags |= F_ERR; + } +} + + +static inline void +assign_address(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) + return; + + if (args->net.addr) + free(args->net.addr); + args->net.addr = strdup(value); +} + +static inline void +assign_ip_address(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) + return; + + if (args->net.ipaddr) + free(args->net.ipaddr); + args->net.ipaddr = strdup(value); +} + +static inline void +assign_channel_address(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) + return; + + if (args->serial.address) + free(args->serial.address); + args->serial.address = strdup(value); +} + + +static inline void +assign_port(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + char *p; + int ret; + + if (!value) + return; + + ret = strtol(value, &p, 0); + if (ret <= 0 || ret >= 65536 || *p != '\0') { + printf("Invalid port: '%s'\n", value); + args->flags |= F_ERR; + } else + args->net.port = ret; +} + +static inline void +assign_cid(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + char *p; + unsigned long ret; + + if (!value) { + args->net.cid = 2; + return; + } + + ret = strtoul(value, &p, 0); + if (!p || *p != '\0' || ret < 2 || ret >= 0xffffffff) { + printf("Invalid CID: '%s'\n", value); + args->flags |= F_ERR; + } else + args->net.cid = ret; +} + +static inline void +assign_interface(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + int ret; + + if (!value) + return; + + ret = if_nametoindex(value); + if (ret <= 0) { + printf("Invalid interface: %s: %s\n", value, strerror(errno)); + args->net.ifindex = 0; + } + + args->net.ifindex = ret; +} + + +static inline void +assign_retrans(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + char *p; + int ret; + + if (!value) + return; + + ret = strtol(value, &p, 0); + if (ret <= 0 || *p != '\0') { + printf("Invalid retransmit time: '%s'\n", value); + args->flags |= F_ERR; + } else + args->retr_time = ret; +} + +static inline void +assign_hash(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) + return; + + if (!strcasecmp(value, "none")) { + args->net.hash = HASH_NONE; + } else if (!strcasecmp(value, "sha1")) { + args->net.hash = HASH_SHA1; + } else if (!strcasecmp(value, "sha256")) { + args->net.hash = HASH_SHA256; + } else if (!strcasecmp(value, "sha512")) { + args->net.hash = HASH_SHA512; + } else { + printf("Unsupported hash: %s\n", value); + args->flags |= F_ERR; + } +} + + +static inline void +assign_auth(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) + return; + + if (!strcasecmp(value, "none")) { + args->net.auth = AUTH_NONE; + } else if (!strcasecmp(value, "sha1")) { + args->net.auth = AUTH_SHA1; + } else if (!strcasecmp(value, "sha256")) { + args->net.auth = AUTH_SHA256; + } else if (!strcasecmp(value, "sha512")) { + args->net.auth = AUTH_SHA512; + } else { + printf("Unsupported auth type: %s\n", value); + args->flags |= F_ERR; + } +} + +static inline void +assign_key(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + struct stat st; + + if (!value) + return; + + if (args->net.key_file) + free(args->net.key_file); + args->net.key_file = strdup(value); + + if (stat(value, &st) == -1) { + printf("Invalid key file: '%s' (%s)\n", value, + strerror(errno)); + args->flags |= F_ERR; + } +} + + +static inline void +assign_op(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) + return; + + if (!strcasecmp(value, "null")) { + args->op = FENCE_NULL; + } else if (!strcasecmp(value, "on")) { + args->op = FENCE_ON; + } else if (!strcasecmp(value, "off")) { + args->op = FENCE_OFF; + } else if (!strcasecmp(value, "reboot")) { + args->op = FENCE_REBOOT; + } else if (!strcasecmp(value, "status")) { + args->op = FENCE_STATUS; + } else if (!strcasecmp(value, "monitor")) { + args->op = FENCE_DEVSTATUS; + } else if (!strcasecmp(value, "list") || !strcasecmp(value, "list-status")) { + args->op = FENCE_HOSTLIST; + } else if (!strcasecmp(value, "metadata")) { + args->op = FENCE_METADATA; + } else if (!strcasecmp(value, "validate-all")) { + args->op = FENCE_VALIDATEALL; + } else { + printf("Unsupported operation: %s\n", value); + args->flags |= F_ERR; + } +} + + +static inline void +assign_device(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) + return; + + args->serial.device = strdup(value); +} + + +static inline void +assign_params(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) + return; + + args->serial.speed = strdup(value); +} + + +static inline void +assign_domain(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (args->domain) { + printf("Domain/UUID may not be specified more than once\n"); + args->flags |= F_ERR; + return; + } + + if (!value) + return; + + args->domain = strdup(value); + + if (strlen(value) <= 0) { + printf("Invalid domain name\n"); + args->flags |= F_ERR; + } + + if (strlen(value) >= MAX_DOMAINNAME_LENGTH) { + errno = ENAMETOOLONG; + printf("Invalid domain name: '%s' (%s)\n", + value, strerror(errno)); + args->flags |= F_ERR; + } +} + + +static inline void +assign_uuid_lookup(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + if (!value) { + /* GNU getopt sets optarg to NULL for options w/o a param + We rely on this here... */ + args->flags |= F_USE_UUID; + return; + } + + args->flags |= ( !!atoi(value) ? F_USE_UUID : 0); +} + + +static inline void +assign_timeout(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + char *p; + int ret; + + if (!value) + return; + + ret = strtol(value, &p, 0); + if (ret <= 0 || *p != '\0') { + printf("Invalid timeout: '%s'\n", value); + args->flags |= F_ERR; + } else + args->timeout = ret; +} + +static inline void +assign_delay(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + char *p; + int ret; + + if (!value) + return; + + ret = strtol(value, &p, 0); + if (ret < 0 || *p != '\0') { + printf("Invalid delay: '%s'\n", value); + args->flags |= F_ERR; + } else + args->delay = ret; +} + +static inline void +assign_help(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + args->flags |= F_HELP; +} + + +static inline void +assign_version(fence_virt_args_t *args, struct arg_info *arg, char *value) +{ + args->flags |= F_VERSION; +} + + +static void +print_desc_xml(const char *desc) +{ + const char *d; + + for (d = desc; *d; d++) { + switch (*d) { + case '<': + printf("<"); + break; + case '>': + printf(">"); + break; + default: + printf("%c", *d); + } + } +} + + +/** ALL valid command line and stdin arguments for this fencing agent */ +static struct arg_info _arg_info[] = { + { '\xff', NULL, "agent", + NULL, 0, 0, "string", NULL, + "Not user serviceable", + NULL }, + + { '\xff', NULL, "self", + NULL, 0, 0, "string", NULL, + "Not user serviceable", + NULL }, + + { '\xff', NULL, "nodename", + NULL, 0, 0, "string", NULL, + "Not user serviceable", + NULL }, + + { 'd', "-d", "debug", + NULL, 0, 0, "boolean", NULL, + "Specify (stdin) or increment (command line) debug level", + assign_debug }, + + { 'i', "-i <family>", "ip_family", + NULL, 0, 0, "string", "auto", + "IP Family ([auto], ipv4, ipv6)", + assign_family }, + + { 'a', "-a <address>", "multicast_address", + NULL, 0, 0, "string", NULL, + "Multicast address (default=" IPV4_MCAST_DEFAULT " / " IPV6_MCAST_DEFAULT ")", + assign_address }, + + { 'T', "-T <address>", "ipaddr", + NULL, 0, 0, "string", "127.0.0.1", + "IP address to connect to in TCP mode (default=" IPV4_TCP_ADDR_DEFAULT " / " IPV6_TCP_ADDR_DEFAULT ")", + assign_ip_address }, + + { 'S', "-S <cid>", "vsock", + NULL, 0, 0, "integer", "2", + "vm socket CID to connect to in vsock mode", + assign_cid }, + + { 'A', "-A <address>", "channel_address", + NULL, 0, 0, "string", "10.0.2.179", + "VM Channel IP address (default=" DEFAULT_CHANNEL_IP ")", + assign_channel_address }, + + { 'p', "-p <port>", "ipport", + NULL, 0, 0, "string", "1229", + "TCP, Multicast, VMChannel, or VM socket port (default=1229)", + assign_port }, + + { 'I', "-I <interface>", "interface", + NULL, 0, 0, "string", NULL, + "Network interface name to listen on", + assign_interface }, + + { 'r', "-r <retrans>", "retrans", + NULL, 0, 0, "string", "20", + "Multicast retransmit time (in 1/10sec; default=20)", + assign_retrans }, + + { 'c', "-c <hash>", "hash", + NULL, 0, 0, "string", "sha256", + "Packet hash strength (none, sha1, [sha256], sha512)", + assign_hash }, + + { 'C', "-C <auth>", "auth", + NULL, 0, 0, "string", "sha256", + "Authentication (none, sha1, [sha256], sha512)", + assign_auth }, + + { 'k', "-k <file>", "key_file", + NULL, 0, 0, "string", DEFAULT_KEY_FILE, + "Shared key file (default=" DEFAULT_KEY_FILE ")", + assign_key }, + + { 'D', "-D <device>", "serial_device", + NULL, 0, 0, "string", DEFAULT_SERIAL_DEVICE, + "Serial device (default=" DEFAULT_SERIAL_DEVICE ")", + assign_device }, + + { 'P', "-P <param>", "serial_params", + NULL, 0, 0, "string", DEFAULT_SERIAL_SPEED, + "Serial Parameters (default=" DEFAULT_SERIAL_SPEED ")", + assign_params }, + + { '\xff', NULL, "option", + /* Deprecated */ + NULL, 0, 0, "string", "reboot", + "Fencing option (null, off, on, [reboot], status, list, list-status, monitor, validate-all, metadata)", + assign_op }, + + { 'o', "-o <operation>", "action", + NULL, 0, 0, "string", "reboot", + "Fencing action (null, off, on, [reboot], status, list, list-status, monitor, validate-all, metadata)", + assign_op }, + + { 'n', "-n <domain>", "plug", + "port", 0, 0, "string", NULL, + "Virtual Machine (domain name) to fence", + assign_domain }, + + { 'H', "-H <domain>", "port", + NULL, 1, 0, "string", NULL, + "Virtual Machine (domain name) to fence", + assign_domain }, + + { SCHEMA_COMPAT, NULL, "domain", + NULL, 0, 0, "string", NULL, + "Virtual Machine (domain name) to fence (deprecated; use port)", + assign_domain }, + + { 'u', "-u", "use_uuid", + NULL, 0, 0, "string", "0", + "Treat [domain] as UUID instead of domain name. This is provided for compatibility with older fence_xvmd installations.", + assign_uuid_lookup }, + + { 't', "-t <timeout>", "timeout", + NULL, 0, 0, "string", "30", + "Fencing timeout (in seconds; default=30)", + assign_timeout }, + + { 'h', "-h", NULL, + NULL, 0, 0, "boolean", "0", + "Help", + assign_help }, + + { '?', "-?", NULL, + NULL, 0, 0, "boolean", "0", + "Help (alternate)", + assign_help }, + + { 'w', "-w <delay>", "delay", + NULL, 0, 0, "string", "0", + "Fencing delay (in seconds; default=0)", + assign_delay }, + + { 'V', "-V", NULL, + NULL, 0, 0, "boolean", "0", + "Display version and exit", + assign_version }, + + /* Terminator */ + { 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL } +}; + + +static struct arg_info * +find_arg_by_char(char arg) +{ + int x = 0; + + for (x = 0; _arg_info[x].opt != 0; x++) { + if (_arg_info[x].opt == arg) + return &_arg_info[x]; + } + + return NULL; +} + + +static struct arg_info * +find_arg_by_string(char *arg) +{ + int x = 0; + + for (x = 0; _arg_info[x].opt != 0; x++) { + if (!_arg_info[x].stdin_opt) + continue; + if (!strcasecmp(_arg_info[x].stdin_opt, arg)) + return &_arg_info[x]; + } + + return NULL; +} + + +/* ============================================================= */ + +/** + Initialize an args structure. + + @param args Pointer to args structure to initialize. + */ +void +args_init(fence_virt_args_t *args) +{ + args->domain = NULL; + //args->uri = NULL; + args->op = FENCE_REBOOT; + args->net.key_file = strdup(DEFAULT_KEY_FILE); + args->net.hash = DEFAULT_HASH; + args->net.auth = DEFAULT_AUTH; + args->net.addr = NULL; + args->net.ipaddr = NULL; + args->net.cid = 0; + args->net.port = DEFAULT_MCAST_PORT; + args->net.ifindex = 0; + args->net.family = 0; /* auto */ + args->serial.device = NULL; + args->serial.speed = strdup(DEFAULT_SERIAL_SPEED); + args->serial.address = strdup(DEFAULT_CHANNEL_IP); + args->timeout = 30; + args->retr_time = 20; + args->flags = 0; + args->debug = 0; + args->delay = 0; +} + + +#define _pr_int(piece) printf(" %s = %d\n", #piece, piece) +#define _pr_str(piece) printf(" %s = %s\n", #piece, piece) + + +/** + Prints out the contents of an args structure for debugging. + + @param args Pointer to args structure to print out. + */ +void +args_print(fence_virt_args_t *args) +{ + printf("-- args @ %p --\n", args); + _pr_str(args->domain); + _pr_int(args->op); + _pr_int(args->mode); + _pr_int(args->debug); + _pr_int(args->timeout); + _pr_int(args->delay); + _pr_int(args->retr_time); + _pr_int(args->flags); + + _pr_str(args->net.addr); + _pr_str(args->net.ipaddr); + _pr_int(args->net.cid); + _pr_str(args->net.key_file); + _pr_int(args->net.port); + _pr_int(args->net.hash); + _pr_int(args->net.auth); + _pr_int(args->net.family); + _pr_int(args->net.ifindex); + + _pr_str(args->serial.device); + _pr_str(args->serial.speed); + _pr_str(args->serial.address); + printf("-- end args --\n"); +} + + +/** + Print out arguments and help information based on what is allowed in + the getopt string optstr. + + @param progname Program name. + @param optstr Getopt(3) style options string + @param print_stdin 0 = print command line options + description, + 1 = print fence-style stdin args + description + */ +static char * +find_rev(const char *start, char *curr, char c) +{ + + while (curr > start) { + if (*curr == c) + return curr; + --curr; + } + + return NULL; +} + + +static void +output_help_text(int arg_width, int help_width, const char *arg, const char *desc) +{ + char out_buf[4096]; + char *p, *start; + const char *arg_print = arg; + int len; + + memset(out_buf, 0, sizeof(out_buf)); + strncpy(out_buf, desc, sizeof(out_buf) - 1); + start = out_buf; + + do { + p = NULL; + len = strlen(start); + if (len > help_width) { + p = start + help_width; + p = find_rev(start, p, ' '); + if (p) { + *p = 0; + p++; + } + } + printf(" %*.*s %*.*s\n", + -arg_width, arg_width, + arg_print, + -help_width, help_width, + start); + if (!p) + return; + if (arg == arg_print) + arg_print = " "; + start = p; + } while(1); +} + + +void +args_usage(char *progname, const char *optstr, int print_stdin) +{ + int x; + struct arg_info *arg; + + if (!print_stdin) { + if (progname) { + printf("usage: %s [args]\n\nNOTE: reboot-action does not power on nodes that are powered off.\n\n", progname); + } else { + printf("usage: fence_virt [args]\n\nNOTE: reboot-action does not power on nodes that are powered off.\n\n"); + } + } + + for (x = 0; x < strlen(optstr); x++) { + arg = find_arg_by_char(optstr[x]); + if (!arg || arg->deprecated) + continue; + + if (print_stdin) { + if (arg && arg->stdin_opt) + output_help_text(20, 55, arg->stdin_opt, arg->desc); + } else { + output_help_text(20, 55, arg->opt_desc, arg->desc); + } + } + + printf("\n"); +} + + +void +args_metadata(char *progname, const char *optstr) +{ + int x; + struct arg_info *arg; + + printf("<?xml version=\"1.0\" ?>\n"); + printf("<resource-agent name=\"%s\" shortdesc=\"Fence agent for virtual machines\">\n", basename(progname)); + printf("<longdesc>%s is an I/O Fencing agent which can be used with " + "virtual machines.\n\nNOTE: reboot-action does not power on nodes that are powered off." + "</longdesc>\n", basename(progname)); + printf("<vendor-url>https://libvirt.org</vendor-url>\n"); + printf("<parameters>\n"); + + for (x = 0; x < strlen(optstr); x++) { + arg = find_arg_by_char(optstr[x]); + if (!arg) + continue; + if (!arg->stdin_opt) + continue; + + if (arg->obsoletes) + printf("\t<parameter name=\"%s\" unique=\"0\" required=\"%d\" obsoletes=\"%s\">\n", arg->stdin_opt, (!strcmp(arg->content_type, "boolean") || arg->default_value) ? 0 : 1, arg->obsoletes); + else if (arg->deprecated) + printf("\t<parameter name=\"%s\" unique=\"0\" required=\"%d\" deprecated=\"%d\">\n", arg->stdin_opt, (!strcmp(arg->content_type, "boolean") || arg->default_value) ? 0 : 1, arg->deprecated); + else + printf("\t<parameter name=\"%s\" unique=\"0\" required=\"%d\">\n", arg->stdin_opt, (!strcmp(arg->content_type, "boolean") || arg->default_value || !strcmp(arg->stdin_opt, "multicast_address")) ? 0 : 1); + + printf("\t\t<getopt mixed=\"-%c\" />\n",arg->opt); + if (arg->default_value) { + printf("\t\t<content type=\"%s\" default=\"%s\" />\n", arg->content_type, arg->default_value); + } else { + printf("\t\t<content type=\"%s\" />\n", arg->content_type); + } + printf("\t\t<shortdesc lang=\"en\">"); + print_desc_xml(arg->desc); + printf("</shortdesc>\n"); + printf("\t</parameter>\n"); + } + + for (x = 0; _arg_info[x].opt != 0; x++) { + if (_arg_info[x].opt != SCHEMA_COMPAT) + continue; + + arg = &_arg_info[x]; + + printf("\t<parameter name=\"%s\" unique=\"0\" required=\"%d\" deprecated=\"1\">\n", arg->stdin_opt, + (!strcmp(arg->content_type, "boolean") || arg->default_value || !strcmp(arg->stdin_opt, "domain")) ? 0 : 1); + printf("\t\t<getopt mixed=\"\" />\n"); + if (arg->default_value) { + printf("\t\t<content type=\"%s\" default=\"%s\" />\n", arg->content_type, arg->default_value); + } else { + printf("\t\t<content type=\"%s\" />\n", arg->content_type); + } + printf("\t\t<shortdesc lang=\"en\">"); + print_desc_xml(arg->desc); + printf("</shortdesc>\n"); + printf("\t</parameter>\n"); + } + + printf("</parameters>\n"); + printf("<actions>\n"); + printf("\t<action name=\"null\" />\n"); + printf("\t<action name=\"on\" />\n"); + printf("\t<action name=\"off\" />\n"); + printf("\t<action name=\"reboot\" />\n"); + printf("\t<action name=\"metadata\" />\n"); + printf("\t<action name=\"status\" />\n"); + printf("\t<action name=\"monitor\" />\n"); + printf("\t<action name=\"list\" />\n"); + printf("\t<action name=\"list-status\" />\n"); + printf("\t<action name=\"validate-all\" />\n"); + printf("</actions>\n"); + printf("</resource-agent>\n"); +} + + +/** + Remove leading and trailing whitespace from a line of text. + + @param line Line to clean up + @param linelen Max size of line + @return 0 on success, -1 on failure + */ +static int +cleanup(char *line, size_t linelen) +{ + char *p; + int x; + + /* Remove leading whitespace. */ + p = line; + for (x = 0; x < linelen; x++) { + switch (line[x]) { + case '\t': + case ' ': + break; + case '\n': + case '\r': + return -1; + default: + goto eol; + } + } +eol: + /* Move the remainder down by as many whitespace chars as we + chewed up */ + if (x) + memmove(p, &line[x], linelen-x); + + /* Remove trailing whitespace. */ + for (x=0; x < linelen; x++) { + switch(line[x]) { + case '\t': + case ' ': + case '\r': + case '\n': + line[x] = 0; + case 0: + /* End of line */ + return 0; + } + } + + return -1; +} + + +/** + Parse args from stdin and assign to the specified args structure. + + @param optstr Command line option string in getopt(3) format + @param args Args structure to fill in. + */ +void +args_get_stdin(const char *optstr, fence_virt_args_t *args) +{ + char in[256]; + char *name, *val; + struct arg_info *arg; + + while (fgets(in, sizeof(in), stdin)) { + + if (in[0] == '#') + continue; + + if (cleanup(in, sizeof(in)) == -1) + continue; + + name = in; + if ((val = strchr(in, '='))) { + *val = 0; + ++val; + } + + arg = find_arg_by_string(name); + if (!arg || (arg->opt != '\xff' && + arg->opt != SCHEMA_COMPAT && + !strchr(optstr, arg->opt))) { + fprintf(stderr, + "Parse error: Ignoring unknown option '%s'\n", + name); + continue; + } + + if (arg->assign) + arg->assign(args, arg, val); + } +} + + +/** + Parse args from stdin and assign to the specified args structure. + + @param optstr Command line option string in getopt(3) format + @param args Args structure to fill in. + */ +void +args_get_getopt(int argc, char **argv, const char *optstr, fence_virt_args_t *args) +{ + int opt; + struct arg_info *arg; + + while ((opt = getopt(argc, argv, optstr)) != EOF) { + + arg = find_arg_by_char(opt); + + if (!arg) { + args->flags |= F_ERR; + continue; + } + + if (arg->assign) + arg->assign(args, arg, optarg); + } +} + + +void +args_finalize(fence_virt_args_t *args) +{ + char *addr = NULL; + + if (!args->net.addr) { + switch(args->net.family) { + case 0: + case PF_INET: + addr = (char *)IPV4_MCAST_DEFAULT; + break; + case PF_INET6: + addr = (char *)IPV6_MCAST_DEFAULT; + break; + default: + args->flags |= F_ERR; + break; + } + } + + if (!args->net.addr) + args->net.addr = addr; + + if (!args->net.addr) { + printf("No multicast address available\n"); + args->flags |= F_ERR; + } + + if (!args->net.addr) + return; + if (args->net.family) + return; + + /* Set family */ + if (strchr(args->net.addr, ':')) + args->net.family = PF_INET6; + if (strchr(args->net.addr, '.')) + args->net.family = PF_INET; + if (!args->net.family) { + printf("Could not determine address family\n"); + args->flags |= F_ERR; + } +} diff --git a/agents/virt/client/serial.c b/agents/virt/client/serial.c new file mode 100644 index 0000000..238ef4a --- /dev/null +++ b/agents/virt/client/serial.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2002-2003, 2009 Red Hat, Inc. + * + * License: GPLv2+ + * + * Written by Lon Hohberger <lhh@redhat.com> + * + * Serial client for fence_virt (incomplete, but + * a good start) + * + * Based on: + * Ubersimpledumbterminal "ser" version 1.0.3 + */ + +#include "config.h" + +#include <stdio.h> +#include <termios.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/select.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <arpa/inet.h> + +#include "fdops.h" +#include "xvm.h" +#include "options.h" +#include "client.h" +#include "tcp.h" + + +static int +char_to_speed(const char *speed) +{ + if (!speed || !strlen(speed)) + return B9600; + if (!strcmp(speed,"2400")) + return B2400; + if (!strcmp(speed,"9600")) + return B9600; + if (!strcmp(speed,"19200")) + return B19200; + if (!strcmp(speed,"38400")) + return B38400; + if (!strcmp(speed,"57600")) + return B57600; + if (!strcmp(speed,"115200")) + return B115200; + return -1; +} + + +static int +char_to_flags(const char *param) +{ + int db_f = CS8, par_f = 0, sb_f = 0, x; + + if (!param || !strlen(param)) + return (db_f | par_f | sb_f); + + if (strlen(param) < 3) { + errno = EINVAL; + return -1; + } + + for (x = 0; x < 3; x++) { + switch (param[x]) { + case '5': + db_f = CS5; + break; + case '6': + db_f = CS6; + break; + case '7': + db_f = CS7; + break; + case '8': + db_f = CS8; + break; + case 'n': + case 'N': + par_f = 0; + break; + case 'e': + case 'E': + par_f = PARENB; + break; + case 'o': + case 'O': + par_f = PARENB | PARODD; + break; + case '1': + sb_f = 0; + break; + case '2': + sb_f = CSTOPB; + break; + default: + printf("Fail: %c\n", param[x]); + errno = EINVAL; + return -1; + } + } + + return (db_f | par_f | sb_f); +} + + +static int +open_port(char *file, char *cspeed, char *cparam) +{ + struct termios ti; + int fd, speed = B115200, flags = 0; + struct flock lock; + + if ((speed = char_to_speed(cspeed)) == -1) { + errno = EINVAL; + return -1; + } + + if ((flags = char_to_flags(cparam)) == -1) { + errno = EINVAL; + return -1; + } + + if ((fd = open(file, O_RDWR | O_EXCL)) == -1) { + perror("open"); + return -1; + } + + memset(&lock,0,sizeof(lock)); + lock.l_type = F_WRLCK; + if (fcntl(fd, F_SETLK, &lock) == -1) { + perror("Failed to lock serial port"); + close(fd); + return -1; + } + + memset(&ti, 0, sizeof(ti)); + ti.c_cflag = (speed | CLOCAL | CRTSCTS | CREAD | flags); + + if (tcsetattr(fd, TCSANOW, &ti) < 0) { + perror("tcsetattr"); + close(fd); + return -1; + } + + (void) tcflush(fd, TCIOFLUSH); + + return fd; +} + + +static void +hangup(int fd, int delay) +{ + unsigned int bits; + + if (ioctl(fd, TIOCMGET, &bits)) { + perror("ioctl1"); + return; + } + + bits &= ~(TIOCM_DTR | TIOCM_CTS | TIOCM_RTS | TIOCM_DSR | TIOCM_CD); + + if (ioctl(fd, TIOCMSET, &bits)) { + perror("ioctl2"); + return; + } + + usleep(delay); + + bits |= (TIOCM_DTR | TIOCM_CTS | TIOCM_RTS | TIOCM_DSR | TIOCM_CD); + + if (ioctl(fd, TIOCMSET, &bits)) { + perror("ioctl3"); + return; + } +} + +static int +wait_for(int fd, const char *pattern, size_t size, struct timeval *tout) +{ + char *pos = (char *)pattern; + char c; + int n; + struct timeval tv; + size_t remain = size; + + if (tout) { + memcpy(&tv, tout, sizeof(tv)); + tout = &tv; + } + + while (remain) { + n = _read_retry(fd, &c, 1, &tv); + if (n < 1) + return -1; + + if (c == *pos) { + ++pos; + --remain; + } else { + pos = (char *)pattern; + remain = size; + } + } + + return 0; +} + +int +serial_fence_virt(fence_virt_args_t *args) +{ + struct in_addr ina; + struct in6_addr in6a; + serial_req_t req; + int fd, ret; + char speed[32], *flags = NULL; + struct timeval tv; + serial_resp_t resp; + + if (args->serial.device) { + strncpy(speed, args->serial.speed, sizeof(speed) - 1); + + //printf("Port: %s Speed: %s\n", args->serial.device, speed); + + if ((flags = strchr(speed, ','))) { + *flags = 0; + flags++; + } + + fd = open_port(args->serial.device, speed, flags); + if (fd == -1) { + perror("open_port"); + return -1; + } + + hangup(fd, 300000); + } else { + fd = -1; + if (inet_pton(PF_INET, args->serial.address, &ina)) { + fd = ipv4_connect(&ina, args->net.port, 3); + } else if (inet_pton(PF_INET6, args->serial.address, &in6a)) { + fd = ipv6_connect(&in6a, args->net.port, 3); + } + + if (fd < 0) { + perror("vmchannel connect"); + printf("Failed to connect to %s:%d\n", args->serial.address, + args->net.port); + return -1; + } + } + + + memset(&req, 0, sizeof(req)); + req.magic = SERIAL_MAGIC; + req.request = (uint8_t)args->op; + gettimeofday(&tv, NULL); + req.seqno = (int)tv.tv_usec; + + if (args->domain) + strncpy((char *)req.domain, args->domain, sizeof(req.domain) - 1); + + tv.tv_sec = 3; + tv.tv_usec = 0; + swab_serial_req_t(&req); + ret = _write_retry(fd, &req, sizeof(req), &tv); + if (ret < sizeof(req)) { + if (ret < 0) { + close(fd); + return ret; + } + printf("Failed to send request\n"); + } + + tv.tv_sec = args->timeout; + tv.tv_usec = 0; + resp.magic = SERIAL_MAGIC; + do { + if (wait_for(fd, (const char *)&resp.magic, + sizeof(resp.magic), &tv) == 0) { + ret = _read_retry(fd, &resp.response, sizeof(resp.response), &tv); + } else { + /* The other end died or closed the connection */ + close(fd); + return -1; + } + + swab_serial_resp_t(&resp); + } while(resp.magic != SERIAL_MAGIC && (tv.tv_sec || tv.tv_usec)); + + if (resp.magic != SERIAL_MAGIC) { + close(fd); + return -1; + } + ret = resp.response; + if (resp.response == RESP_HOSTLIST) /* hostlist */ { + /* ok read hostlist */ + do_read_hostlist(fd, args->timeout); + ret = 0; + } + + close(fd); + return ret; +} diff --git a/agents/virt/client/tcp.c b/agents/virt/client/tcp.c new file mode 100644 index 0000000..986fdd9 --- /dev/null +++ b/agents/virt/client/tcp.c @@ -0,0 +1,171 @@ +/* + Copyright Red Hat, Inc. 2006-2012 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <errno.h> +#include <nss.h> + +/* Local includes */ +#include "xvm.h" +#include "simple_auth.h" +#include "options.h" +#include "tcp.h" +#include "debug.h" +#include "fdops.h" +#include "client.h" + +static int +tcp_exchange(int fd, fence_auth_type_t auth, void *key, + size_t key_len, int timeout) +{ + fd_set rfds; + struct timeval tv; + char ret = 1; + + /* Ok, we're connected */ + dbg_printf(3, "Issuing TCP challenge\n"); + if (sock_challenge(fd, auth, key, key_len, timeout) <= 0) { + /* Challenge failed */ + printf("Invalid response to challenge\n"); + return 1; + } + + /* Now they'll send us one, so we need to respond here */ + dbg_printf(3, "Responding to TCP challenge\n"); + if (sock_response(fd, auth, key, key_len, timeout) <= 0) { + printf("Invalid response to challenge\n"); + return 1; + } + + dbg_printf(2, "TCP Exchange + Authentication done... \n"); + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = timeout; + tv.tv_usec = 0; + + ret = 1; + dbg_printf(3, "Waiting for return value from fence_virtd host\n"); + if (_select_retry(fd + 1, &rfds, NULL, NULL, &tv) <= 0) + return -1; + + /* Read return code */ + if (_read_retry(fd, &ret, 1, &tv) < 0) + ret = 1; + + if (ret == (char)RESP_HOSTLIST) /* hostlist */ { + do_read_hostlist(fd, timeout); + ret = 0; + } + + return ret; +} + +int +tcp_fence_virt(fence_virt_args_t *args) +{ + char key[MAX_KEY_LEN]; + struct timeval tv; + int key_len = 0, fd = -1; + int ret; + struct in_addr ina; + struct in6_addr in6a; + fence_req_t freq; + + /* Initialize NSS; required to do hashing, as silly as that + sounds... */ + if (NSS_NoDB_Init(NULL) != SECSuccess) { + printf("Could not initialize NSS\n"); + return 1; + } + + if (args->net.auth != AUTH_NONE || args->net.hash != HASH_NONE) { + key_len = read_key_file(args->net.key_file, key, sizeof(key)); + if (key_len < 0) { + printf("Could not read %s; trying without " + "authentication\n", args->net.key_file); + args->net.auth = AUTH_NONE; + args->net.hash = HASH_NONE; + key_len = 0; + } + } + + /* Same wire protocol as fence_xvm */ + memset(&freq, 0, sizeof(freq)); + if (args->domain && strlen((char *)args->domain)) + strncpy((char *)freq.domain, args->domain, sizeof(freq.domain) - 1); + freq.request = args->op; + freq.hashtype = args->net.hash; + freq.flags = 0; + if (args->flags & F_USE_UUID) + freq.flags |= RF_UUID; + gettimeofday(&tv, NULL); + freq.seqno = (uint32_t) tv.tv_usec; + sign_request(&freq, key, key_len); + + /* XXX fixme */ + if (inet_pton(PF_INET, args->net.ipaddr, &ina)) { + fd = ipv4_connect(&ina, args->net.port, 3); + } else if (inet_pton(PF_INET6, args->net.ipaddr, &in6a)) { + fd = ipv6_connect(&in6a, args->net.port, 3); + } + + if (fd < 0) { + printf("Unable to connect to fence_virtd host %s:%d %s\n", + args->net.ipaddr, args->net.port, strerror(errno)); + return 1; + } + + ret = _write_retry(fd, &freq, sizeof(freq), NULL); + if (ret != sizeof(freq)) { + perror("write"); + close(fd); + return 1; + } + + switch (args->net.auth) { + case AUTH_NONE: + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + ret = tcp_exchange(fd, args->net.auth, key, key_len, + args->timeout); + break; + /* case AUTH_X509: + return ssl_exchange(...); */ + default: + dbg_printf(3, "Unknown auth type: %d\n", args->net.auth); + ret = 1; + break; + } + + close(fd); + return ret; +} diff --git a/agents/virt/client/vsock.c b/agents/virt/client/vsock.c new file mode 100644 index 0000000..7557c54 --- /dev/null +++ b/agents/virt/client/vsock.c @@ -0,0 +1,176 @@ +/* + Copyright Red Hat, Inc. 2017 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <errno.h> +#include <nss.h> +#include <sys/socket.h> +#include <linux/vm_sockets.h> + +/* Local includes */ +#include "xvm.h" +#include "simple_auth.h" +#include "options.h" +#include "debug.h" +#include "fdops.h" +#include "client.h" + +static int +sock_exchange(int fd, fence_auth_type_t auth, void *key, + size_t key_len, int timeout) +{ + fd_set rfds; + struct timeval tv; + char ret = 1; + + /* Ok, we're connected */ + dbg_printf(3, "Issuing challenge\n"); + if (sock_challenge(fd, auth, key, key_len, timeout) <= 0) { + /* Challenge failed */ + printf("Invalid response to challenge\n"); + return 1; + } + + /* Now they'll send us one, so we need to respond here */ + dbg_printf(3, "Responding to challenge\n"); + if (sock_response(fd, auth, key, key_len, timeout) <= 0) { + printf("Invalid response to challenge\n"); + return 1; + } + + dbg_printf(2, "vsock Exchange + Authentication done... \n"); + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = timeout; + tv.tv_usec = 0; + + ret = 1; + dbg_printf(3, "Waiting for return value from fence_virtd host\n"); + if (_select_retry(fd + 1, &rfds, NULL, NULL, &tv) <= 0) + return -1; + + /* Read return code */ + if (_read_retry(fd, &ret, 1, &tv) < 0) + ret = 1; + + if (ret == (char)RESP_HOSTLIST) /* hostlist */ { + do_read_hostlist(fd, timeout); + ret = 0; + } + + return ret; +} + +int +vsock_fence_virt(fence_virt_args_t *args) +{ + char key[MAX_KEY_LEN]; + struct timeval tv; + int key_len = 0, fd = -1; + int ret; + struct sockaddr_vm svm; + fence_req_t freq; + + /* Initialize NSS; required to do hashing, as silly as that + sounds... */ + if (NSS_NoDB_Init(NULL) != SECSuccess) { + printf("Could not initialize NSS\n"); + return 1; + } + + if (args->net.auth != AUTH_NONE || args->net.hash != HASH_NONE) { + key_len = read_key_file(args->net.key_file, key, sizeof(key)); + if (key_len < 0) { + printf("Could not read %s; trying without " + "authentication\n", args->net.key_file); + args->net.auth = AUTH_NONE; + args->net.hash = HASH_NONE; + key_len = 0; + } + } + + /* Same wire protocol as fence_xvm */ + memset(&freq, 0, sizeof(freq)); + if (args->domain && strlen((char *)args->domain)) + strncpy((char *)freq.domain, args->domain, sizeof(freq.domain) - 1); + freq.request = args->op; + freq.hashtype = args->net.hash; + freq.flags = 0; + if (args->flags & F_USE_UUID) + freq.flags |= RF_UUID; + gettimeofday(&tv, NULL); + freq.seqno = (uint32_t) tv.tv_usec; + sign_request(&freq, key, key_len); + + fd = socket(PF_VSOCK, SOCK_STREAM, 0); + if (fd < 0) { + printf("Unable to create vsock: %s", strerror(errno)); + return 1; + } + + memset(&svm, 0, sizeof(svm)); + svm.svm_family = AF_VSOCK; + svm.svm_cid = args->net.cid; + svm.svm_port = args->net.port; + + if (connect(fd, (struct sockaddr *) &svm, sizeof(svm)) < 0) { + printf("Unable to connect to fence_virtd host %d:%d %s\n", + args->net.cid, args->net.port, strerror(errno)); + close(fd); + return 1; + } + + ret = _write_retry(fd, &freq, sizeof(freq), NULL); + if (ret != sizeof(freq)) { + perror("write"); + close(fd); + return 1; + } + + switch (args->net.auth) { + case AUTH_NONE: + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + ret = sock_exchange(fd, args->net.auth, key, key_len, + args->timeout); + break; + /* case AUTH_X509: + return ssl_exchange(...); */ + default: + dbg_printf(3, "Unknown auth type: %d\n", args->net.auth); + ret = 1; + break; + } + + close(fd); + return ret; +} diff --git a/agents/virt/common/Makefile.am b/agents/virt/common/Makefile.am new file mode 100644 index 0000000..d5e4314 --- /dev/null +++ b/agents/virt/common/Makefile.am @@ -0,0 +1,24 @@ +############################################################################### +############################################################################### +## +## Copyright (C) 2009-2019 Red Hat, Inc. +## +## This copyrighted material is made available to anyone wishing to use, +## modify, copy, or redistribute it subject to the terms and conditions +## of the GNU General Public License v.2. +## +############################################################################### +############################################################################### + +MAINTAINERCLEANFILES = Makefile.in + +noinst_LTLIBRARIES = libfence_virt.la + +libfence_virt_la_SOURCES = mcast.c ip_lookup.c simple_auth.c tcp.c \ + debug.c fdops.c log.c + +libfence_virt_la_CFLAGS = $(VIRT_AM_CFLAGS) $(nss_CFLAGS) $(AM_CFLAGS) -Wno-cast-align + +libfence_virt_la_LDFLAGS = $(VIRT_AM_LDFLAGS) $(VIRT_COMMON_LDFLAGS) + +libfence_virt_la_LIBADD = $(nss_LIBS) diff --git a/agents/virt/common/bcast.c b/agents/virt/common/bcast.c new file mode 100644 index 0000000..2b498b7 --- /dev/null +++ b/agents/virt/common/bcast.c @@ -0,0 +1,347 @@ +/* + * Author: Lon Hohberger <lhh at redhat.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/time.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> + +/* Local includes */ +#include "bcast.h" +#include "debug.h" + +LOGSYS_DECLARE_SUBSYS ("XVM", SYSLOGLEVEL); + +/** + Sets up a multicast receive socket + */ +int +ipv4_bcast_recv_sk(char *addr, int port) +{ + int sock, val; + struct sockaddr_in sin; + + /* Store broadcast address */ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = PF_INET; + sin.sin_port = htons(port); + if (inet_pton(PF_INET, addr, + (void *)&sin.sin_addr.s_addr) < 0) { + log_printf(LOG_ERR, "Invalid broadcast address: %s\n", addr); + return -1; + } + + dbg_printf(4, "Setting up ipv4 broadcast receive (%s:%d)\n", addr, port); + sock = socket(PF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + log_printf(LOG_ERR, "socket: %s\n", strerror(errno)); + close(sock); + sock = -1; + return 1; + } + + val = 1; + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, 1, sizeof(val)) < 0) { + log_printf(LOG_ERR, "setsockopt: %s\n", strerror(errno)); + close(sock); + return 1; + } + + /* + * Bind broadcast address + */ + if (bind(sock, (struct sockaddr *) &sin, + sizeof(struct sockaddr_in)) < 0) { + printf("bind failed: %s\n", strerror(errno)); + close(sock); + return -1; + } + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} + + +/** + Set up multicast send socket + */ +int +ipv4_bcast_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt, + socklen_t tgt_len, int ttl) +{ + int val; + struct ip_mreq mreq; + struct sockaddr_in mcast; + struct sockaddr_in src; + int sock; + + if (tgt_len < sizeof(struct sockaddr_in)) { + errno = EINVAL; + return -1; + } + + /* Store multicast address */ + mcast.sin_family = PF_INET; + mcast.sin_port = htons(port); + if (inet_pton(PF_INET, addr, + (void *)&mcast.sin_addr.s_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + mreq.imr_multiaddr.s_addr = mcast.sin_addr.s_addr; + + /* Store sending address */ + src.sin_family = PF_INET; + src.sin_port = htons(port); + if (inet_pton(PF_INET, send_addr, + (void *)&src.sin_addr.s_addr) < 0) { + printf("Invalid source address: %s\n", send_addr); + return -1; + } + mreq.imr_interface.s_addr = src.sin_addr.s_addr; + + + /************************* + * SET UP MULTICAST SEND * + *************************/ + dbg_printf(4, "Setting up ipv4 multicast send (%s:%d)\n", addr, port); + sock = socket(PF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return -1; + } + + /* + * Join Multicast group. + */ + dbg_printf(4, "Joining IP Multicast group (pass 1)\n"); + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == -1) { + printf("Failed to add multicast membership to transmit " + "socket %s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + + /* + * Join Multicast group. + */ + dbg_printf(4, "Joining IP Multicast group (pass 2)\n"); + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &src.sin_addr, + sizeof(src.sin_addr)) == -1) { + printf("Failed to bind multicast transmit socket to " + "%s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + + /* + * set time to live to 2 hops. + */ + dbg_printf(4, "Setting TTL to %d for fd%d\n", ttl, sock); + val = ttl; + if (setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &val, + sizeof(val))) + printf("warning: setting TTL failed %s\n", strerror(errno)); + + memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in)); + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} + + + +/** + Sets up a multicast receive (ipv6) socket + */ +int +ipv6_recv_sk(char *addr, int port) +{ + int sock, val; + struct ipv6_mreq mreq; + struct sockaddr_in6 sin; + + memset(&mreq, 0, sizeof(mreq)); + memset(&sin, 0, sizeof(sin)); + sin.sin6_family = PF_INET6; + sin.sin6_port = htons(port); + if (inet_pton(PF_INET6, addr, + (void *)&sin.sin6_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + + memcpy(&mreq.ipv6mr_multiaddr, &sin.sin6_addr, + sizeof(struct in6_addr)); + + + /******************************** + * SET UP MULTICAST RECV SOCKET * + ********************************/ + dbg_printf(4, "Setting up ipv6 multicast receive (%s:%d)\n", addr, port); + sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + printf("socket: %s\n", strerror(errno)); + close(sock); + sock = -1; + return 1; + } + + /* + * When using Multicast, bind to the LOCAL address, not the MULTICAST + * address. + */ + memset(&sin, 0, sizeof(sin)); + sin.sin6_family = PF_INET6; + sin.sin6_port = htons(port); + sin.sin6_addr = in6addr_any; + if (bind(sock, (struct sockaddr *) &sin, + sizeof(struct sockaddr_in6)) < 0) { + printf("bind failed: %s\n", strerror(errno)); + close(sock); + return -1; + } + + dbg_printf(4, "Disabling IP Multicast loopback\n"); + val = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, + sizeof(val)) != 0) { + printf("Failed to disable multicast loopback\n"); + close(sock); + return -1; + } + + /* + * Join multicast group + */ + dbg_printf(4, "Joining IP Multicast group\n"); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == -1) { + printf("Failed to add multicast to socket %s: %s\n", + addr, strerror(errno)); + close(sock); + return -1; + } + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} + + +/** + Set up ipv6 multicast send socket + */ +int +ipv6_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt, + socklen_t tgt_len, int ttl) +{ + int val; + struct ipv6_mreq mreq; + struct sockaddr_in6 mcast; + struct sockaddr_in6 src; + int sock; + + if (tgt_len < sizeof(struct sockaddr_in6)) { + errno = EINVAL; + return -1; + } + + memset(&mreq, 0, sizeof(mreq)); + + /* Store multicast address */ + mcast.sin6_family = PF_INET6; + mcast.sin6_port = htons(port); + if (inet_pton(PF_INET6, addr, + (void *)&mcast.sin6_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + + memcpy(&mreq.ipv6mr_multiaddr, &mcast.sin6_addr, + sizeof(struct in6_addr)); + + /* Store sending address */ + src.sin6_family = PF_INET6; + src.sin6_port = htons(port); + if (inet_pton(PF_INET6, send_addr, + (void *)&src.sin6_addr) < 0) { + printf("Invalid source address: %s\n", send_addr); + return -1; + } + + /************************* + * SET UP MULTICAST SEND * + *************************/ + dbg_printf(4, "Setting up ipv6 multicast send (%s:%d)\n", addr, port); + sock = socket(PF_INET6, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return -1; + } + + dbg_printf(4, "Disabling IP Multicast loopback\n"); + val = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, + sizeof(val)) != 0) { + printf("Failed to disable multicast loopback\n"); + close(sock); + return -1; + } + + /* + * Join Multicast group. + */ + dbg_printf(4, "Joining IP Multicast group\n"); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == -1) { + printf("Failed to add multicast membership to transmit " + "socket %s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + + /* + * Join Multicast group (part 2) + */ + /* + if (setsockopt(sock, IPPROTO_IPV6, IP_MULTICAST_IF, &src.sin6_addr, + sizeof(src.sin6_addr)) == -1) { + printf("Failed to bind multicast transmit socket to " + "%s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + */ + + /* + * set time to live to 2 hops. + */ + val = ttl; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, + sizeof(val))) + printf("warning: setting TTL failed %s\n", strerror(errno)); + + memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in6)); + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} diff --git a/agents/virt/common/debug.c b/agents/virt/common/debug.c new file mode 100644 index 0000000..5cf5359 --- /dev/null +++ b/agents/virt/common/debug.c @@ -0,0 +1,38 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ + +#include "config.h" + +#include <stdio.h> +#include "debug.h" + +static int _debug = 0; + +void +dset(int threshold) +{ + _debug = threshold; + dbg_printf(3, "Debugging threshold is now %d\n", threshold); +} + +int +dget(void) +{ + return _debug; +} diff --git a/agents/virt/common/fdops.c b/agents/virt/common/fdops.c new file mode 100644 index 0000000..329e9b7 --- /dev/null +++ b/agents/virt/common/fdops.c @@ -0,0 +1,202 @@ +/* + Copyright Red Hat, Inc. 2002-2003 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +/** @file + * Wrapper functions around read/write/select to retry in the event + * of interrupts. + */ + +#include "config.h" + +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <errno.h> + +#include "fdops.h" + +/** + * This is a wrapper around select which will retry in the case we receive + * EINTR. This is necessary for _read_retry, since it wouldn't make sense + * to have _read_retry terminate if and only if two EINTRs were received + * in a row - one during the read() call, one during the select call... + * + * See select(2) for description of parameters. + */ +int +_select_retry(int fdmax, fd_set * rfds, fd_set * wfds, fd_set * xfds, + struct timeval *timeout) +{ + int rv; + + while (1) { + rv = select(fdmax, rfds, wfds, xfds, timeout); + if (rv == -1) { + /* return on EBADF/EINVAL/ENOMEM; continue on EINTR/EAGAIN/ENOMEM */ + if (errno == EINTR || errno == EAGAIN || errno == ENOMEM) + continue; + } + return rv; + } +} + +/** + * Retries a write in the event of a non-blocked interrupt signal. + * + * @param fd File descriptor to which we are writing. + * @param buf Data buffer to send. + * @param count Number of bytes in buf to send. + * @param timeout (struct timeval) telling us how long we should retry. + * @return The number of bytes written to the file descriptor, + * or -1 on error (with errno set appropriately). + */ +ssize_t +_write_retry(int fd, void *buf, int count, struct timeval * timeout) +{ + int n, total = 0, remain = count, rv = 0; + fd_set wfds, xfds; + char *tmp_buf = (char *)buf; + + while (total < count) { + + /* Create the write FD set of 1... */ + FD_ZERO(&wfds); + FD_SET(fd, &wfds); + FD_ZERO(&xfds); + FD_SET(fd, &xfds); + + /* wait for the fd to be available for writing */ + rv = _select_retry(fd + 1, NULL, &wfds, &xfds, timeout); + if (rv == -1) + return -1; + else if (rv == 0) { + errno = ETIMEDOUT; + return -1; + } + + if (FD_ISSET(fd, &xfds)) { + errno = EPIPE; + return -1; + } + + /* + * Attempt to write to fd + */ + n = write(fd, tmp_buf + total, remain); + + /* + * When we know our fd was select()ed and we receive 0 bytes + * when we write, the fd was closed. + */ + if ((n == 0) && (rv == 1)) { + errno = EPIPE; + return -1; + } + + if (n == -1) { + if ((errno == EAGAIN) || (errno == EINTR)) { + /* + * Not ready? + */ + continue; + } + + /* Other errors: EIO, EINVAL, etc */ + return -1; + } + + total += n; + remain -= n; + } + + return total; +} + +/** + * Retry reads until we (a) time out or (b) get our data. Of course, if + * timeout is NULL, it'll wait forever. + * + * @param sockfd File descriptor we want to read from. + * @param buf Preallocated buffer into which we will read data. + * @param count Number of bytes to read. + * @param timeout (struct timeval) describing how long we should retry. + * @return The number of bytes read on success, or -1 on failure. + Note that we will always return (count) or (-1). + */ +ssize_t +_read_retry(int sockfd, void *buf, int count, struct timeval * timeout) +{ + int n, total = 0, remain = count, rv = 0; + fd_set rfds, xfds; + char *tmp_buf = (char *)buf; + + while (total < count) { + FD_ZERO(&rfds); + FD_SET(sockfd, &rfds); + FD_ZERO(&xfds); + FD_SET(sockfd, &xfds); + + /* + * Select on the socket, in case it closes while we're not + * looking... + */ + rv = _select_retry(sockfd + 1, &rfds, NULL, &xfds, timeout); + if (rv == -1) + return -1; + else if (rv == 0) { + errno = ETIMEDOUT; + return -1; + } + + if (FD_ISSET(sockfd, &xfds)) { + errno = EPIPE; + return -1; + } + + /* + * Attempt to read off the socket + */ + n = read(sockfd, tmp_buf + total, remain); + + /* + * When we know our socket was select()ed and we receive 0 bytes + * when we read, the socket was closed. + */ + if ((n == 0) && (rv == 1)) { + errno = EPIPE; + return -1; + } + + if (n == -1) { + if ((errno == EAGAIN) || (errno == EINTR)) { + /* + * Not ready? Wait for data to become available + */ + continue; + } + + /* Other errors: EPIPE, EINVAL, etc */ + return -1; + } + + total += n; + remain -= n; + } + + return total; +} diff --git a/agents/virt/common/ip_lookup.c b/agents/virt/common/ip_lookup.c new file mode 100644 index 0000000..aded8ea --- /dev/null +++ b/agents/virt/common/ip_lookup.c @@ -0,0 +1,326 @@ +/* + Copyright Red Hat, Inc. 2004, 2006 + + The Magma Cluster API Library is free software; you can redistribute + it and/or modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either version + 2.1 of the License, or (at your option) any later version. + + The Magma Cluster API Library is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. + */ +/** @file + * Build lists of IPs on the system, excepting loopback ipv6 link-local + */ + +#include "config.h" + +#include <asm/types.h> +#include <sys/types.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <netdb.h> + +/* Local includes */ +#include "ip_lookup.h" +#include "debug.h" + +static int +send_addr_dump(int fd, int family) +{ + struct nlmsghdr *nh; + struct rtgenmsg *g; + char buf[256]; + struct sockaddr_nl addr; + + memset(&addr,0,sizeof(addr)); + addr.nl_family = PF_NETLINK; + + memset(buf, 0, sizeof(buf)); + nh = (struct nlmsghdr *)buf; + g = (struct rtgenmsg *)(buf + sizeof(struct nlmsghdr)); + + nh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + nh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; + nh->nlmsg_type = RTM_GETADDR; + g->rtgen_family = family; + + return sendto(fd, buf, nh->nlmsg_len, 0, (struct sockaddr *)&addr, + sizeof(addr)); +} + + +static int +add_ip(ip_list_t *ipl, char *ipaddr, char family) +{ + ip_addr_t *ipa; + + if (family == PF_INET6) { + /* Avoid loopback */ + if (!strcmp(ipaddr, "::1")) + return -1; + + /* Avoid link-local addresses */ + if (!strncmp(ipaddr, "fe80", 4)) + return -1; + if (!strncmp(ipaddr, "fe90", 4)) + return -1; + if (!strncmp(ipaddr, "fea0", 4)) + return -1; + if (!strncmp(ipaddr, "feb0", 4)) + return -1; + } + + ipa = calloc(1, sizeof(*ipa)); + if (!ipa) + return -1; + ipa->ipa_family = family; + ipa->ipa_address = strdup(ipaddr); + + dbg_printf(4, "Adding IP %s to list (family %d)\n", ipaddr, family); + TAILQ_INSERT_TAIL(ipl, ipa, ipa_entries); + + return 0; +} + + +static int +add_ip_addresses(int family, ip_list_t *ipl) +{ + /* List ipv4 addresses */ + struct nlmsghdr *nh; + struct ifaddrmsg *ifa; + struct rtattr *rta, *nrta; + struct nlmsgerr *err; + char buf[10240]; + char outbuf[256]; + char label[256]; + int x, fd, len; + + dbg_printf(5, "Connecting to Netlink...\n"); + fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (fd < 0) { + perror("socket"); + exit(1); + } + + dbg_printf(5, "Sending address dump request\n"); + if (send_addr_dump(fd, family) < 0) { + perror("sendto"); + close(fd); + return -1; + } + memset(buf, 0, sizeof(buf)); + + dbg_printf(5, "Waiting for response\n"); + x = recvfrom(fd, buf, sizeof(buf), 0, NULL, 0); + if (x < 0) { + perror("recvfrom"); + close(fd); + return -1; + } + + dbg_printf(5, "Received %d bytes\n", x); + + nh = (struct nlmsghdr *)buf; + while (NLMSG_OK(nh, x)) { + + switch(nh->nlmsg_type) { + case NLMSG_DONE: + close(fd); + return 0; + + case NLMSG_ERROR: + err = (struct nlmsgerr*)NLMSG_DATA(nh); + if (nh->nlmsg_len < + NLMSG_LENGTH(sizeof(struct nlmsgerr))) { + fprintf(stderr, "ERROR truncated"); + } else { + errno = -err->error; + perror("RTNETLINK answers"); + } + close(fd); + return -1; + + case RTM_NEWADDR: + break; + + default: + nh = NLMSG_NEXT(nh, x); + continue; + } + + /* RTM_NEWADDR */ + len = NLMSG_PAYLOAD(nh,0); + ifa = NLMSG_DATA(nh); + + /* Make sure we got the type we expect back */ + if (ifa->ifa_family != family) { + nh = NLMSG_NEXT(nh, x); + continue; + } + + rta = IFA_RTA(ifa); + len -= sizeof(struct ifaddrmsg); + do { + /* Make sure we've got a valid rtaddr field */ + if (!RTA_OK(rta, len)) { + dbg_printf(5, "!RTA_OK(rta, len)\n"); + break; + } + + if (rta->rta_type == IFA_ADDRESS) { + inet_ntop(family, RTA_DATA(rta), outbuf, + sizeof(outbuf) ); + add_ip(ipl, outbuf, family); + } + + if (rta->rta_type == IFA_LABEL) { + memset(label, 0, sizeof(label)); + strncpy(label, (char *)RTA_DATA(rta), sizeof(label) - 1); + dbg_printf(5, "Skipping label: %s\n", + label); + } + + nrta = RTA_NEXT(rta, len); + len -= (nrta - rta); + rta = nrta; + } while (RTA_OK(rta, len)); + + nh = NLMSG_NEXT(nh, x); + } + + dbg_printf(5, "Closing Netlink connection\n"); + close(fd); + return 0; +} + + +int +ip_search(ip_list_t *ipl, char *ip_name) +{ + ip_addr_t *ipa; + + dbg_printf(5, "Looking for IP address %s in IP list %p...", ip_name, ipl); + ipa = ipl->tqh_first; + for (ipa = ipl->tqh_first; ipa; ipa = ipa->ipa_entries.tqe_next) { + if (!strcmp(ip_name, ipa->ipa_address)) { + dbg_printf(4,"Found\n"); + return 0; + } + } + dbg_printf(5, "Not found\n"); + return 1; +} + + +int +ip_free_list(ip_list_t *ipl) +{ + ip_addr_t *ipa; + + dbg_printf(5, "Tearing down IP list @ %p\n", ipl); + while ((ipa = ipl->tqh_first)) { + TAILQ_REMOVE(ipl, ipa, ipa_entries); + free(ipa->ipa_address); + free(ipa); + } + return 0; +} + + +int +ip_build_list(ip_list_t *ipl) +{ + dbg_printf(5, "Build IP address list\n"); + TAILQ_INIT(ipl); + if (add_ip_addresses(PF_INET6, ipl) < 0) { + ip_free_list(ipl); + return -1; + } + if (add_ip_addresses(PF_INET, ipl) < 0) { + ip_free_list(ipl); + return -1; + } + return 0; +} + + +/** + Look up the interface name which corresponds to the given hostname and + return the list of matching attrinfo structures. We do this by looking + up all the possible physical and virtual network interfaces on the machine + and checking the hostname/IP mappings for each active IP address incurred. + + @param nodename Interface name + @param ret_ai Structure pointer to allocate & return. + @return -1 on failure or 0 on success. + */ +int +ip_lookup(char *nodename, struct addrinfo **ret_ai) +{ + char ip_name[256]; + struct addrinfo *ai = NULL; + struct addrinfo *n; + void *p; + ip_list_t ipl; + int ret = -1; + + dbg_printf(5, "Looking for IP matching %s\n", nodename); + /* Build list of IP addresses configured locally */ + if (ip_build_list(&ipl) < 0) + return -1; + + /* Get list of addresses for the host-name/ip */ + if (getaddrinfo(nodename, NULL, NULL, &ai) != 0) + return -1; + + + /* Traverse list of addresses for given host-name/ip */ + for (n = ai; n; n = n->ai_next) { + if (n->ai_family != PF_INET && n->ai_family != PF_INET6) + continue; + + if (n->ai_family == PF_INET) + p = &(((struct sockaddr_in *)n->ai_addr)->sin_addr); + else + p = &(((struct sockaddr_in6 *)n->ai_addr)->sin6_addr); + + if (!inet_ntop(n->ai_family, p, ip_name, + sizeof(ip_name))) + continue; + + /* Search local interfaces for this IP address */ + if (ip_search(&ipl, ip_name) != 0) + continue; + + /* Found it */ + ret = 0; + break; + } + + /* Clean up */ + if (!ret_ai) + freeaddrinfo(ai); + else + *ret_ai = ai; + + ip_free_list(&ipl); + + return ret; +} + diff --git a/agents/virt/common/log.c b/agents/virt/common/log.c new file mode 100644 index 0000000..61018ed --- /dev/null +++ b/agents/virt/common/log.c @@ -0,0 +1,204 @@ +/** + * Syslog wrapper that does not block + * + * Lon Hohberger, 2009 + */ + +#include "config.h" + +#include <pthread.h> +#include <unistd.h> +#include <sys/syslog.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/time.h> +#include <errno.h> + +#include "list.h" + +struct log_entry { + list_head(); + char *message; + int sev; + int bufsz; +}; + +#define MAX_QUEUE_LENGTH 10 +#define LOGLEN 256 + +static struct log_entry *_log_entries = NULL; +static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t log_cond = PTHREAD_COND_INITIALIZER; +static int log_size = 0; +static int dropped = 0; +static pthread_t thread_id = 0; + +void __real_syslog(int severity, const char *fmt, ...); +void __wrap_syslog(int severity, const char *fmt, ...); +void __wrap_closelog(void); + +static void * +_log_thread(void *arg) +{ + struct timeval tv; + struct timespec ts; + struct log_entry *entry; + + do { + gettimeofday(&tv, NULL); + ts.tv_sec = tv.tv_sec + 10; + ts.tv_nsec = tv.tv_usec; + + pthread_mutex_lock(&log_mutex); + + while (!(entry = _log_entries)) { + if (pthread_cond_timedwait(&log_cond, + &log_mutex, + &ts) == ETIMEDOUT) + goto out; + } + + list_remove(&_log_entries, entry); + --log_size; + if (log_size < 0) + raise(SIGSEGV); + pthread_mutex_unlock(&log_mutex); + + __real_syslog(entry->sev, entry->message); + free(entry->message); + free(entry); + } while (1); + +out: + thread_id = (pthread_t)0; + pthread_mutex_unlock(&log_mutex); + return NULL; +} + + +static int +insert_entry(int sev, char *buf, int bufsz) +{ + struct log_entry *lent; + pthread_attr_t attrs; + + lent = malloc(sizeof(*lent)); + if (!lent) + return -1; + lent->sev = sev; + lent->message = buf; + lent->bufsz = bufsz; + + pthread_mutex_lock(&log_mutex); + if (log_size >= MAX_QUEUE_LENGTH) { + free(lent->message); + free(lent); + + ++dropped; + lent = (struct log_entry *)(le(_log_entries)->le_prev); + + lent->sev = LOG_WARNING; + snprintf(lent->message, lent->bufsz, + "%d message(s) lost due to syslog load\n", + dropped + 1); + /* Dropped +1 because we overwrote a message to + * give the 'dropped' message */ + } else { + ++log_size; + dropped = 0; + list_insert(&_log_entries, lent); + } + + if (!thread_id) { + pthread_attr_init(&attrs); + pthread_attr_setinheritsched(&attrs, PTHREAD_INHERIT_SCHED); + + if (pthread_create(&thread_id, &attrs, _log_thread, NULL) < 0) + thread_id = 0; + pthread_mutex_unlock(&log_mutex); + } else { + pthread_mutex_unlock(&log_mutex); + pthread_cond_signal(&log_cond); + } + + return 0; +} + + +__attribute__((__format__ (__printf__, 2, 0))) +void +__wrap_syslog(int severity, const char *fmt, ...) +{ + va_list args; + char *logmsg; + + logmsg = malloc(LOGLEN); + if (!logmsg) + return; + memset(logmsg, 0, LOGLEN); + + va_start(args, fmt); + vsnprintf(logmsg + strlen(logmsg), LOGLEN - strlen(logmsg), + fmt, args); + va_end(args); + + insert_entry(severity, logmsg, LOGLEN); + + return; +} + + +void __real_closelog(void); + +void +__wrap_closelog(void) +{ + struct log_entry *lent; +#ifdef DEBUG + int lost = 0; +#endif + + if (thread_id != 0) { + pthread_cancel(thread_id); + pthread_join(thread_id, NULL); + thread_id = 0; + } + __real_closelog(); + while (_log_entries) { +#ifdef DEBUG + ++lost; +#endif + lent = _log_entries; + list_remove(&_log_entries, lent); + free(lent->message); + free(lent); + } + +#ifdef DEBUG + printf("%d lost\n", lost); +#endif +} + + +#ifdef STANDALONE +int +main(int argc, char**argv) +{ + int x; + + for (x = 0; x < 100; x++) { + syslog(1, "Yo %d\n", x); + } + sleep(1); + + closelog(); + + return 0; +} + +#endif diff --git a/agents/virt/common/mcast.c b/agents/virt/common/mcast.c new file mode 100644 index 0000000..cc79c64 --- /dev/null +++ b/agents/virt/common/mcast.c @@ -0,0 +1,388 @@ +/* + Copyright Red Hat, Inc. 2003, 2004, 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +/* + * Author: Lon Hohberger <lhh at redhat.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/time.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> + +/* Local includes */ +#include "mcast.h" +#include "debug.h" + +/** + Sets up a multicast receive socket + */ +int +ipv4_recv_sk(char *addr, int port, unsigned int ifindex) +{ + int sock; + struct ip_mreqn mreq; + struct sockaddr_in sin; + + memset(&mreq, 0, sizeof(mreq)); + memset(&sin, 0, sizeof(sin)); + + /* Store multicast address */ + if (inet_pton(PF_INET, addr, + (void *)&mreq.imr_multiaddr.s_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + + /******************************** + * SET UP MULTICAST RECV SOCKET * + ********************************/ + dbg_printf(4, "Setting up ipv4 multicast receive (%s:%d)\n", addr, port); + sock = socket(PF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + printf("socket: %s\n", strerror(errno)); + sock = -1; + return 1; + } + + /* + * When using Multicast, bind to the LOCAL address, not the MULTICAST + * address. + */ + sin.sin_family = PF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(sock, (struct sockaddr *) &sin, + sizeof(struct sockaddr_in)) < 0) { + printf("bind failed: %s\n", strerror(errno)); + close(sock); + return -1; + } + + /* + * Join multicast group + */ + /* mreq.imr_multiaddr.s_addr is set above */ + if (ifindex == 0) { + dbg_printf(4, "Setting mcast addr to INADDR_ANY due to ifindex of 0\n"); + mreq.imr_address.s_addr = htonl(INADDR_ANY); + } else { + mreq.imr_ifindex = ifindex; + } + dbg_printf(4, "Joining multicast group\n"); + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)) == -1) { + printf("Failed to bind multicast receive socket to " + "%s: %s\n", addr, strerror(errno)); + printf("Check network configuration.\n"); + close(sock); + return -1; + } + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} + + +/** + Set up multicast send socket + */ +int +ipv4_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt, + socklen_t tgt_len) +{ + int val; + struct ip_mreq mreq; + struct sockaddr_in mcast; + struct sockaddr_in src; + int sock; + + if (tgt_len < sizeof(struct sockaddr_in)) { + errno = EINVAL; + return -1; + } + + memset(&mcast, 0, sizeof(mcast)); + memset(&src, 0, sizeof(src)); + + /* Store multicast address */ + mcast.sin_family = PF_INET; + mcast.sin_port = htons(port); + if (inet_pton(PF_INET, addr, + (void *)&mcast.sin_addr.s_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + mreq.imr_multiaddr.s_addr = mcast.sin_addr.s_addr; + + /* Store sending address */ + src.sin_family = PF_INET; + src.sin_port = htons(port); + if (inet_pton(PF_INET, send_addr, + (void *)&src.sin_addr.s_addr) < 0) { + printf("Invalid source address: %s\n", send_addr); + return -1; + } + mreq.imr_interface.s_addr = src.sin_addr.s_addr; + + + /************************* + * SET UP MULTICAST SEND * + *************************/ + dbg_printf(4, "Setting up ipv4 multicast send (%s:%d)\n", addr, port); + sock = socket(PF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return -1; + } + + /* + * Join Multicast group. + */ + dbg_printf(4, "Joining IP Multicast group (pass 1)\n"); + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == -1) { + printf("Failed to add multicast membership to transmit " + "socket %s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + + /* + * Join Multicast group. + */ + dbg_printf(4, "Joining IP Multicast group (pass 2)\n"); + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &src.sin_addr, + sizeof(src.sin_addr)) == -1) { + printf("Failed to bind multicast transmit socket to " + "%s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + + /* + * set time to live to 2 hops. + */ + dbg_printf(4, "Setting TTL to 2 for fd%d\n", sock); + val = 2; + if (setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &val, + sizeof(val))) + printf("warning: setting TTL failed %s\n", strerror(errno)); + + memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in)); + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} + + + +/** + Sets up a multicast receive (ipv6) socket + */ +int +ipv6_recv_sk(char *addr, int port, unsigned int ifindex) +{ + int sock, val; + struct ipv6_mreq mreq; + struct sockaddr_in6 sin; + + memset(&mreq, 0, sizeof(mreq)); + memset(&sin, 0, sizeof(sin)); + sin.sin6_family = PF_INET6; + sin.sin6_port = htons(port); + if (inet_pton(PF_INET6, addr, + (void *)&sin.sin6_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + + memcpy(&mreq.ipv6mr_multiaddr, &sin.sin6_addr, + sizeof(struct in6_addr)); + + mreq.ipv6mr_interface = ifindex; + + /******************************** + * SET UP MULTICAST RECV SOCKET * + ********************************/ + dbg_printf(4, "Setting up ipv6 multicast receive (%s:%d)\n", addr, port); + sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + printf("socket: %s\n", strerror(errno)); + sock = -1; + return 1; + } + + /* + * When using Multicast, bind to the LOCAL address, not the MULTICAST + * address. + */ + memset(&sin, 0, sizeof(sin)); + sin.sin6_family = PF_INET6; + sin.sin6_port = htons(port); + sin.sin6_addr = in6addr_any; + if (bind(sock, (struct sockaddr *) &sin, + sizeof(struct sockaddr_in6)) < 0) { + printf("bind failed: %s\n", strerror(errno)); + close(sock); + return -1; + } + + dbg_printf(4, "Disabling IP Multicast loopback\n"); + val = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, + sizeof(val)) != 0) { + printf("Failed to disable multicast loopback\n"); + close(sock); + return -1; + } + + /* + * Join multicast group + */ + dbg_printf(4, "Joining IP Multicast group\n"); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == -1) { + printf("Failed to add multicast to socket %s: %s\n", + addr, strerror(errno)); + close(sock); + return -1; + } + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} + + +/** + Set up ipv6 multicast send socket + */ +int +ipv6_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt, + socklen_t tgt_len) +{ + int val; + struct ipv6_mreq mreq; + struct sockaddr_in6 mcast; + struct sockaddr_in6 src; + int sock; + + if (tgt_len < sizeof(struct sockaddr_in6)) { + errno = EINVAL; + return -1; + } + + memset(&mcast, 0, sizeof(mcast)); + memset(&src, 0, sizeof(src)); + memset(&mreq, 0, sizeof(mreq)); + + /* Store multicast address */ + mcast.sin6_family = PF_INET6; + mcast.sin6_port = htons(port); + if (inet_pton(PF_INET6, addr, + (void *)&mcast.sin6_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + + memcpy(&mreq.ipv6mr_multiaddr, &mcast.sin6_addr, + sizeof(struct in6_addr)); + + /* Store sending address */ + src.sin6_family = PF_INET6; + src.sin6_port = htons(port); + if (inet_pton(PF_INET6, send_addr, + (void *)&src.sin6_addr) < 0) { + printf("Invalid source address: %s\n", send_addr); + return -1; + } + + /************************* + * SET UP MULTICAST SEND * + *************************/ + dbg_printf(4, "Setting up ipv6 multicast send (%s:%d)\n", addr, port); + sock = socket(PF_INET6, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return -1; + } + + dbg_printf(4, "Disabling IP Multicast loopback\n"); + val = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, + sizeof(val)) != 0) { + printf("Failed to disable multicast loopback\n"); + close(sock); + return -1; + } + + /* + * Join Multicast group. + */ + dbg_printf(4, "Joining IP Multicast group\n"); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == -1) { + printf("Failed to add multicast membership to transmit " + "socket %s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + + /* + * Join Multicast group (part 2) + */ + /* + if (setsockopt(sock, IPPROTO_IPV6, IP_MULTICAST_IF, &src.sin6_addr, + sizeof(src.sin6_addr)) == -1) { + printf("Failed to bind multicast transmit socket to " + "%s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + */ + + /* + * set time to live to 2 hops. + */ + val = 2; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, + sizeof(val))) + printf("warning: setting TTL failed %s\n", strerror(errno)); + + memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in6)); + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} diff --git a/agents/virt/common/simple_auth.c b/agents/virt/common/simple_auth.c new file mode 100644 index 0000000..9f694c4 --- /dev/null +++ b/agents/virt/common/simple_auth.c @@ -0,0 +1,466 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ + +#include "config.h" + +#include <sys/types.h> +#include <string.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sechash.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> + +/* Local includes */ +#include "xvm.h" +#include "fdops.h" +#include "simple_auth.h" +#include "debug.h" + + +static void +print_hash(unsigned char *hash, size_t hashlen) +{ + int x; + + for (x = 0; x < hashlen; x++) + printf("%02x", (hash[x]&0xff)); +} + + +static int +sha_sign(fence_req_t *req, void *key, size_t key_len) +{ + unsigned char hash[SHA512_LENGTH]; + HASHContext *h; + HASH_HashType ht; + unsigned int rlen; + int devrand; + int ret; + + switch(req->hashtype) { + case HASH_SHA1: + ht = HASH_AlgSHA1; + break; + case HASH_SHA256: + ht = HASH_AlgSHA256; + break; + case HASH_SHA512: + ht = HASH_AlgSHA512; + break; + default: + dbg_printf(1, "Unknown hash type: %d\n", req->hashtype); + return -1; + } + + dbg_printf(4, "Opening /dev/urandom\n"); + devrand = open("/dev/urandom", O_RDONLY); + if (devrand < 0) { + dbg_printf(1, "Error: open: /dev/urandom: %s", strerror(errno)); + return -1; + } + + ret = _read_retry(devrand, req->random, sizeof(req->random), NULL); + if (ret <= 0) { + dbg_printf(1, "Error: read: /dev/urandom: %s", strerror(errno)); + close(devrand); + return -1; + } + close(devrand); + + memset(hash, 0, sizeof(hash)); + h = HASH_Create(ht); + if (!h) + return -1; + + HASH_Begin(h); + HASH_Update(h, key, key_len); + HASH_Update(h, (void *)req, sizeof(*req)); + HASH_End(h, hash, &rlen, sizeof(hash)); + HASH_Destroy(h); + + memcpy(req->hash, hash, sizeof(req->hash)); + return 0; +} + + +static int +sha_verify(fence_req_t *req, void *key, size_t key_len) +{ + unsigned char hash[SHA512_LENGTH]; + unsigned char pkt_hash[SHA512_LENGTH]; + HASHContext *h = NULL; + HASH_HashType ht; + unsigned int rlen; + int ret; + + switch(req->hashtype) { + case HASH_SHA1: + ht = HASH_AlgSHA1; + break; + case HASH_SHA256: + ht = HASH_AlgSHA256; + break; + case HASH_SHA512: + ht = HASH_AlgSHA512; + break; + default: + dbg_printf(3, "%s: no-op (HASH_NONE)\n", __FUNCTION__); + return 0; + } + + if (!key || !key_len) { + dbg_printf(3, "%s: Hashing requested when we have no key data\n", + __FUNCTION__); + return 0; + } + + memset(hash, 0, sizeof(hash)); + h = HASH_Create(ht); + if (!h) + return 0; + + memcpy(pkt_hash, req->hash, sizeof(pkt_hash)); + memset(req->hash, 0, sizeof(req->hash)); + + HASH_Begin(h); + HASH_Update(h, key, key_len); + HASH_Update(h, (void *)req, sizeof(*req)); + HASH_End(h, hash, &rlen, sizeof(hash)); + HASH_Destroy(h); + + memcpy(req->hash, pkt_hash, sizeof(req->hash)); + + ret = !memcmp(hash, pkt_hash, sizeof(hash)); + if (!ret) { + printf("Hash mismatch:\nPKT = "); + print_hash(pkt_hash, sizeof(pkt_hash)); + printf("\nEXP = "); + print_hash(hash, sizeof(hash)); + printf("\n"); + } + + return ret; +} + + +int +sign_request(fence_req_t *req, void *key, size_t key_len) +{ + memset(req->hash, 0, sizeof(req->hash)); + switch(req->hashtype) { + case HASH_NONE: + dbg_printf(3, "%s: no-op (HASH_NONE)\n", __FUNCTION__); + return 0; + case HASH_SHA1: + case HASH_SHA256: + case HASH_SHA512: + return sha_sign(req, key, key_len); + default: + break; + } + return -1; +} + + +int +verify_request(fence_req_t *req, fence_hash_t min, + void *key, size_t key_len) +{ + if (req->hashtype < min) { + printf("Hash type not strong enough (%d < %d)\n", + req->hashtype, min); + return 0; + } + switch(req->hashtype) { + case HASH_NONE: + return 1; + case HASH_SHA1: + case HASH_SHA256: + case HASH_SHA512: + return sha_verify(req, key, key_len); + default: + break; + } + return 0; +} + + +static int +sha_challenge(int fd, fence_auth_type_t auth, void *key, + size_t key_len, int timeout) +{ + fd_set rfds; + struct timeval tv; + unsigned char hash[MAX_HASH_LENGTH]; + unsigned char challenge[MAX_HASH_LENGTH]; + unsigned char response[MAX_HASH_LENGTH]; + int devrand; + int ret; + HASHContext *h; + HASH_HashType ht; + unsigned int rlen; + + devrand = open("/dev/urandom", O_RDONLY); + if (devrand < 0) { + dbg_printf(1, "Error: open /dev/urandom: %s", strerror(errno)); + return 0; + } + + tv.tv_sec = timeout; + tv.tv_usec = 0; + ret = _read_retry(devrand, challenge, sizeof(challenge), &tv); + if (ret < 0) { + dbg_printf(1, "Error: read: /dev/urandom: %s", strerror(errno)); + close(devrand); + return 0; + } + close(devrand); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + ret = _write_retry(fd, challenge, sizeof(challenge), &tv); + if (ret < 0) { + dbg_printf(2, "Error: write: %s", strerror(errno)); + return 0; + } + + switch(auth) { + case HASH_SHA1: + ht = HASH_AlgSHA1; + break; + case HASH_SHA256: + ht = HASH_AlgSHA256; + break; + case HASH_SHA512: + ht = HASH_AlgSHA512; + break; + default: + return 0; + } + + memset(hash, 0, sizeof(hash)); + h = HASH_Create(ht); + if (!h) + return 0; + + HASH_Begin(h); + HASH_Update(h, key, key_len); + HASH_Update(h, challenge, sizeof(challenge)); + HASH_End(h, hash, &rlen, sizeof(hash)); + HASH_Destroy(h); + + memset(response, 0, sizeof(response)); + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + if (_select_retry(fd + 1, &rfds, NULL, NULL, &tv) <= 0) { + dbg_printf(0, "Error: select: %s\n", strerror(errno)); + return 0; + } + + tv.tv_sec = timeout; + tv.tv_usec = 0; + ret = _read_retry(fd, response, sizeof(response), &tv); + if (ret < 0) { + dbg_printf(0, "Error reading challenge response: %s", strerror(errno)); + return 0; + } else if (ret < sizeof(response)) { + dbg_printf(0, + "read data from socket is too short(actual: %d, expected: %zu)\n", + ret, sizeof(response)); + return 0; + } + + ret = !memcmp(response, hash, sizeof(response)); + if (!ret) { + printf("Hash mismatch:\nC = "); + print_hash(challenge, sizeof(challenge)); + printf("\nH = "); + print_hash(hash, sizeof(hash)); + printf("\nR = "); + print_hash(response, sizeof(response)); + printf("\n"); + } + + return ret; +} + + +static int +sha_response(int fd, fence_auth_type_t auth, void *key, + size_t key_len, int timeout) +{ + fd_set rfds; + struct timeval tv; + unsigned char challenge[MAX_HASH_LENGTH]; + unsigned char hash[MAX_HASH_LENGTH]; + HASHContext *h; + HASH_HashType ht; + unsigned int rlen; + int ret; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + if (_select_retry(fd + 1, &rfds, NULL, NULL, &tv) <= 0) { + dbg_printf(2, "Error: select: %s\n", strerror(errno)); + return 0; + } + + tv.tv_sec = timeout; + tv.tv_usec = 0; + if (_read_retry(fd, challenge, sizeof(challenge), &tv) < 0) { + dbg_printf(2, "Error reading challenge hash: %s\n", strerror(errno)); + return 0; + } + + switch(auth) { + case AUTH_SHA1: + ht = HASH_AlgSHA1; + break; + case AUTH_SHA256: + ht = HASH_AlgSHA256; + break; + case AUTH_SHA512: + ht = HASH_AlgSHA512; + break; + default: + dbg_printf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__); + return 0; + } + + memset(hash, 0, sizeof(hash)); + h = HASH_Create(ht); /* */ + if (!h) + return 0; + + HASH_Begin(h); + HASH_Update(h, key, key_len); + HASH_Update(h, challenge, sizeof(challenge)); + HASH_End(h, hash, &rlen, sizeof(hash)); + HASH_Destroy(h); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + ret = _write_retry(fd, hash, sizeof(hash), &tv); + if (ret < 0) { + perror("write"); + return 0; + } else if (ret < sizeof(hash)) { + dbg_printf(2, + "Only part of hash is written(actual: %d, expected: %zu)\n", + ret, + sizeof(hash)); + return 0; + } + + return 1; +} + + +int +sock_challenge(int fd, fence_auth_type_t auth, void *key, size_t key_len, + int timeout) +{ + switch(auth) { + case AUTH_NONE: + dbg_printf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__); + return 1; + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + return sha_challenge(fd, auth, key, key_len, timeout); + default: + break; + } + return -1; +} + + +int +sock_response(int fd, fence_auth_type_t auth, void *key, size_t key_len, + int timeout) +{ + switch(auth) { + case AUTH_NONE: + dbg_printf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__); + return 1; + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + return sha_response(fd, auth, key, key_len, timeout); + default: + break; + } + return -1; +} + + +int +read_key_file(char *file, char *key, size_t max_len) +{ + int fd; + int nread, remain = max_len; + char *p; + + dbg_printf(3, "Reading in key file %s into %p (%d max size)\n", + file, key, (int)max_len); + fd = open(file, O_RDONLY); + if (fd < 0) { + dbg_printf(2, "Error opening key file: %s\n", strerror(errno)); + return -1; + } + + memset(key, 0, max_len); + p = key; + remain = max_len; + + while (remain) { + nread = read(fd, p, remain); + if (nread < 0) { + if (errno == EINTR) + continue; + dbg_printf(2, "Error from read: %s\n", strerror(errno)); + close(fd); + return -1; + } + + if (nread == 0) { + dbg_printf(3, "Stopped reading @ %d bytes\n", + (int)max_len-remain); + break; + } + + p += nread; + remain -= nread; + } + + close(fd); + dbg_printf(3, "Actual key length = %d bytes\n", (int)max_len-remain); + + return (int)(max_len - remain); +} diff --git a/agents/virt/common/tcp.c b/agents/virt/common/tcp.c new file mode 100644 index 0000000..5796770 --- /dev/null +++ b/agents/virt/common/tcp.c @@ -0,0 +1,386 @@ +/* + Copyright Red Hat, Inc. 2002-2004, 2006 + Copyright Mission Critical Linux, 2000 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +/** @file + * + * @author Lon H. Hohberger <lhh at redhat.com> + * @author Jeff Moyer <jmoyer at redhat.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include "tcp.h" +#include "debug.h" + +static int connect_nb(int fd, struct sockaddr *dest, socklen_t len, int timeout); +static int get_addr(const char *hostname, int family, struct sockaddr_storage *addr); + +/** + Set close-on-exec bit option for a socket. + + @param fd Socket to set CLOEXEC flag + @return 0 on success, -1 on failure + @see fcntl + */ +static int +set_cloexec(int fd) +{ + int flags = fcntl(fd, F_GETFD, 0); + flags |= FD_CLOEXEC; + return fcntl(fd, F_SETFD, flags); +} + + +/** + Bind to a port on the local IPv6 stack + + @param addr_str Address to listen on, NULL for inaddr6_any + @param port Port to bind to + @param backlog same as backlog for listen(2) + @return 0 on success, -1 on failure + @see ipv4_bind + */ +int +ipv6_listen(const char *addr_str, uint16_t port, int backlog) +{ + struct sockaddr_in6 _sin6; + int fd, opt=1; + + dbg_printf(4, "%s: Setting up ipv6 listen socket for %s:%d\n", + __FUNCTION__, addr_str, port); + + memset(&_sin6, 0, sizeof(_sin6)); + _sin6.sin6_family = PF_INET6; + _sin6.sin6_port = htons(port); + _sin6.sin6_flowinfo = 0; + + if (addr_str == NULL) { + _sin6.sin6_addr = in6addr_any; + } else { + struct sockaddr_storage ss; + + if (get_addr(addr_str, AF_INET6, &ss) == -1) { + dbg_printf(4, "%s: Can't get addr for %s\n", + __FUNCTION__, addr_str); + return -1; + } + + memcpy(&_sin6.sin6_addr, + &((struct sockaddr_in6 *)&ss)->sin6_addr, sizeof(_sin6.sin6_addr)); + } + + fd = socket(PF_INET6, SOCK_STREAM, 0); + if (fd < 0) + return -1; + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof (opt)) < 0) { + close(fd); + return -1; + } + + if (set_cloexec(fd) < 0) { + close(fd); + return -1; + } + + if (bind(fd, (struct sockaddr *)&_sin6, sizeof(_sin6)) < 0) { + close(fd); + return -1; + } + + if (listen(fd, backlog) < 0){ + close(fd); + return -1; + } + + dbg_printf(4, "%s: Success; fd = %d\n", __FUNCTION__, fd); + return fd; +} + + +/** + Bind to a port on the local IPv4 stack + + @param addr_str Address to listen on, NULL for inaddr_any + @param port Port to bind to + @param backlog same as backlog for listen(2) + @return 0 on success, -1 on failure + @see ipv6_bind + */ +int +ipv4_listen(const char *addr_str, uint16_t port, int backlog) +{ + struct sockaddr_in _sin; + int fd, opt=1; + + dbg_printf(4, "%s: Setting up ipv4 listen socket for %s:%d\n", + __FUNCTION__, addr_str, port); + + _sin.sin_family = PF_INET; + _sin.sin_port = htons(port); + + if (addr_str == NULL) { + _sin.sin_addr.s_addr = htonl(INADDR_ANY); + } else { + struct sockaddr_storage ss; + + if (get_addr(addr_str, AF_INET, &ss) == -1) { + dbg_printf(4, "%s: Can't get addr for %s\n", + __FUNCTION__, addr_str); + return -1; + } + + memcpy(&_sin.sin_addr, + &((struct sockaddr_in *)&ss)->sin_addr, sizeof(_sin.sin_addr)); + } + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + return -1; + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof (opt)) < 0) { + close(fd); + return -1; + } + + if (set_cloexec(fd) < 0) { + close(fd); + return -1; + } + + if (bind(fd, (struct sockaddr *)&_sin, sizeof(_sin)) < 0) { + close(fd); + return -1; + } + + if (listen(fd, backlog) < 0) { + close(fd); + return -1; + } + + dbg_printf(4, "%s: Success; fd = %d\n", __FUNCTION__, fd); + return fd; +} + + + +/** + Connect via ipv6 socket to a given IP address and port. + + @param in6_addr IPv6 address to connect to + @param port Port to connect to + @param timeout Timeout, in seconds, to wait for a completed + connection + @return 0 on success, -1 on failure + @see connect_nb, ipv4_connect + */ +int +ipv6_connect(struct in6_addr *in6_addr, uint16_t port, int timeout) +{ + struct sockaddr_in6 _sin6; + int fd, ret; + + dbg_printf(4, "%s: Connecting to client\n", __FUNCTION__); + fd = socket(PF_INET6, SOCK_STREAM, 0); + if (fd < 0) + return -1; + + memset(&_sin6, 0, sizeof(_sin6)); + _sin6.sin6_family = PF_INET6; + _sin6.sin6_port = htons(port); + _sin6.sin6_flowinfo = 0; + memcpy(&_sin6.sin6_addr, in6_addr, sizeof(_sin6.sin6_addr)); + + ret = connect_nb(fd, (struct sockaddr *)&_sin6, sizeof(_sin6), timeout); + if (ret < 0) { + close(fd); + return -1; + } + dbg_printf(4, "%s: Success; fd = %d\n", __FUNCTION__, fd); + return fd; +} + + +/** + Connect via ipv4 socket to a given IP address and port. + + @param in_addr IPv4 address to connect to + @param port Port to connect to + @param timeout Timeout, in seconds, to wait for a completed + connection + @return 0 on success, -1 on failure + @see connect_nb, ipv6_connect + */ +int +ipv4_connect(struct in_addr *in_addr, uint16_t port, int timeout) +{ + struct sockaddr_in _sin; + int fd, ret; + + dbg_printf(4, "%s: Connecting to client\n", __FUNCTION__); + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + return -1; + + _sin.sin_family = PF_INET; + _sin.sin_port = htons(port); + memcpy(&_sin.sin_addr, in_addr, sizeof(_sin.sin_addr)); + + ret = connect_nb(fd, (struct sockaddr *)&_sin, sizeof(_sin), timeout); + if (ret < 0) { + close(fd); + return -1; + } + + dbg_printf(4, "%s: Success; fd = %d\n", __FUNCTION__, fd); + return fd; +} + + +/** + Connect in a non-blocking fashion to the designated address. + + @param fd File descriptor to connect + @param dest sockaddr (ipv4 or ipv6) to connect to. + @param len Length of dest + @param timeout Timeout, in seconds, to wait for a completed + connection. + @return 0 on success, -1 on failure. + */ +static int +connect_nb(int fd, struct sockaddr *dest, socklen_t len, int timeout) +{ + int ret, flags = 1, err; + unsigned l; + fd_set rfds, wfds; + struct timeval tv; + + /* + * Use TCP Keepalive + */ + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, + sizeof(flags))<0) { + return -1; + } + + /* + Set up non-blocking connect + */ + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) { + return -1; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + return -1; + } + + ret = connect(fd, dest, len); + + if ((ret < 0) && (errno != EINPROGRESS)) + return -1; + + if (ret != 0) { + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + FD_ZERO(&wfds); + FD_SET(fd, &wfds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + if (select(fd + 1, &rfds, &wfds, NULL, &tv) == 0) { + errno = ETIMEDOUT; + return -1; + } + /* XXX check for -1 from select */ + + if (FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds)) { + l = sizeof(err); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, + (void *)&err, &l) < 0) { + close(fd); + return -1; + } + + if (err != 0) { + close(fd); + errno = err; + return -1; + } + + if (fcntl(fd, F_SETFL, flags) < 0) { + close(fd); + return -1; + } + return 0; + } + } + + errno = EIO; + return -1; +} + +static int +get_addr(const char *hostname, int family, struct sockaddr_storage *addr) +{ + struct addrinfo *res; + size_t len; + struct addrinfo ai; + + memset(&ai, 0, sizeof(ai)); + ai.ai_family = family; + + if (getaddrinfo(hostname, NULL, &ai, &res) != 0) + return -1; + + switch (res->ai_addr->sa_family) { + case AF_INET: + len = sizeof(struct sockaddr_in); + break; + case AF_INET6: + len = sizeof(struct sockaddr_in6); + break; + default: + goto out_fail; + } + + if (len < (size_t) res->ai_addrlen) + goto out_fail; + + memcpy(addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + + return 0; + +out_fail: + freeaddrinfo(res); + return -1; +} diff --git a/agents/virt/config/Makefile.am b/agents/virt/config/Makefile.am new file mode 100644 index 0000000..19d9742 --- /dev/null +++ b/agents/virt/config/Makefile.am @@ -0,0 +1,44 @@ +############################################################################### +############################################################################### +## +## Copyright (C) 2009-2019 Red Hat, Inc. +## +## This copyrighted material is made available to anyone wishing to use, +## modify, copy, or redistribute it subject to the terms and conditions +## of the GNU General Public License v.2. +## +############################################################################### +############################################################################### + +MAINTAINERCLEANFILES = Makefile.in + +EXTRA_DIST = config.l config.y fence_virt.conf + +noinst_LIBRARIES = libsimpleconfig.a + +libsimpleconfig_a_SOURCES = \ + simpleconfig.c + +nodist_libsimpleconfig_a_SOURCES = \ + y.tab.c \ + config.c + +libsimpleconfig_a_CFLAGS = $(VIRT_AM_CFLAGS) $(AM_CFLAGS) -Wno-unused + +noinst_HEADERS = config-stack.h + + +sysconf_DATA = fence_virt.conf + +# local rules +y.tab.c: config.y + $(YACC) -d $^ + +config.c: y.tab.c config.l + $(LEX) -oconfig.c $(srcdir)/config.l + +install-exec-hook: + chmod 600 $(DESTDIR)$(sysconfdir)/fence_virt.conf + +clean-local: + rm -f config.tab.c config.tab.h config.c y.tab.c y.tab.h diff --git a/agents/virt/config/config-stack.h b/agents/virt/config/config-stack.h new file mode 100644 index 0000000..1eb3cfa --- /dev/null +++ b/agents/virt/config/config-stack.h @@ -0,0 +1,38 @@ +#ifndef _CONFIG_STACK_H +#define _CONFIG_STACK_H + +int yyparse (void); +extern FILE *yyin; + +struct value { + char *id; + char *val; + struct value *next; +}; + + +struct node { + char *id; + char *val; + struct node *nodes; + struct value *values; + struct node *next; +}; + + +struct parser_context { + struct value *val_list; + struct node *node_list; + struct parser_context *next; +}; + +extern struct value *val_list; +extern struct node *node_list; +extern struct parser_context *context_stack; + +int _sc_value_add(char *id, char *val, struct value **list); +int _sc_node_add(char *id, char *val, struct value *vallist, + struct node *nodelist, struct node **list); + + +#endif diff --git a/agents/virt/config/config.l b/agents/virt/config/config.l new file mode 100644 index 0000000..78462f3 --- /dev/null +++ b/agents/virt/config/config.l @@ -0,0 +1,106 @@ +%{ +#include "config.h" +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include "config-stack.h" +#include "y.tab.h" +#include "simpleconfig.h" + +/* Some distributions can't use the output from flex without help */ +#define ECHO if(fwrite( yytext, yyleng, 1, yyout )) + +struct value *val_list = NULL; +struct node *node_list = NULL; +struct parser_context *context_stack = NULL; + +int _line_count = 1; + +%} +%% +[\n] { + ++_line_count; +} + +[ \t]* {} + +\#[^\n]* {} + +"{" { + struct parser_context *c = NULL; + //printf("obrace\n"); + + c = malloc(sizeof(*c)); + assert(c); + + c->next = context_stack; + c->val_list = val_list; + c->node_list = node_list; + + context_stack = c; + val_list = NULL; + node_list = NULL; + + return T_OBRACE; +} + +"}" { + return T_CBRACE; +} + +";" { + return T_SEMI; +} + +"=" { + return T_EQ; +} + +[^ \t{};=\"\n]+ { + yylval.sval = strdup(yytext); + return T_ID; +} + +\"[^\"]+\" { + yylval.sval = strdup(yytext+1); + yylval.sval[strlen(yytext)-2] = 0; + return T_VAL; +} + +%% +int +yywrap(void) +{ + return 1; +} + + +#ifdef STANDALONE +int +main(int argc, char *argv[]) +{ + char value[80]; + config_object_t *c = NULL; + + yyout = fopen("/dev/null","w"); + + c = sc_init(); + sc_parse(c, NULL); + sc_dump(c, stdout); + if (argc == 2) { + if (sc_get(c, argv[1], value, sizeof(value)) == 0) + printf("%s = %s\n", argv[1], value); + else + printf("Not found\n"); + } else if (argc == 3) { + printf("---------\n"); + if (sc_set(c, argv[1], argv[2]) == 0) + sc_dump(c, stdout); + } + + sc_release(c); + + return 0; +} +#endif diff --git a/agents/virt/config/config.y b/agents/virt/config/config.y new file mode 100644 index 0000000..2ae0380 --- /dev/null +++ b/agents/virt/config/config.y @@ -0,0 +1,140 @@ +%{ +#include "config.h" +#include <stdio.h> +#include <malloc.h> +#include <string.h> +#include <assert.h> +#include "config-stack.h" + +extern int yylex (void); +int yyerror(const char *foo); + +int +_sc_value_add(char *id, char *val, struct value **list) +{ + struct value *v; + + v = malloc(sizeof(*v)); + assert(v); + + memset(v, 0, sizeof(*v)); + v->id = id; + v->val = val; + //snprintf(v->id, sizeof(v->id), "%s", id); + //snprintf(v->val, sizeof(v->val), "%s", val); + //printf("add %s %s on to %p\n", id, val, *list); + + v->next = *list; + *list = v; + + //printf("new list %p\n", *list); + return 0; +} + + +int +_sc_node_add(char *id, char *val, struct value *vallist, + struct node *nodelist, struct node **list) +{ + struct node *n; + + n = malloc(sizeof(*n)); + assert(n); + + //printf("nodes %p values %p\n", nodelist, vallist); + + memset(n, 0, sizeof(*n)); + //snprintf(n->id, sizeof(n->id), "%s", id); + n->id = id; /* malloc'd during parsing */ + n->val = val; /* malloc'd during parsing */ + n->values = vallist; + n->nodes = nodelist; + n->next = *list; + *list = n; + + return 0; +} + +%} + +%token <sval> T_ID +%token <sval> T_VAL +%token T_OBRACE T_CBRACE T_EQ T_SEMI + +%start stuff + +%union { + char *sval; + int ival; +} + +%% +node: + T_ID T_OBRACE stuff T_CBRACE { + struct parser_context *c = NULL; + + c = context_stack; + _sc_node_add($1, NULL, val_list, node_list, &c->node_list); + val_list = c->val_list; + node_list = c->node_list; + context_stack = c->next; + + free(c); + } + | + T_ID T_EQ T_VAL T_OBRACE stuff T_CBRACE { + struct parser_context *c = NULL; + + c = context_stack; + _sc_node_add($1, $3, val_list, node_list, &c->node_list); + val_list = c->val_list; + node_list = c->node_list; + context_stack = c->next; + + free(c); + } + | + T_ID T_OBRACE T_CBRACE { + struct parser_context *c = NULL; + + c = context_stack; + _sc_node_add($1, NULL, val_list, node_list, &c->node_list); + val_list = c->val_list; + node_list = c->node_list; + context_stack = c->next; + + free(c); + } + | + T_ID T_EQ T_VAL T_OBRACE T_CBRACE { + struct parser_context *c = NULL; + + c = context_stack; + _sc_node_add($1, $3, val_list, node_list, &c->node_list); + val_list = c->val_list; + node_list = c->node_list; + context_stack = c->next; + + free(c); + } + ; + +stuff: + node stuff | assign stuff | node | assign + ; + +assign: + T_ID T_EQ T_VAL T_SEMI { + _sc_value_add($1, $3, &val_list); + } + ; +%% + +extern int _line_count; + +int +yyerror(const char *foo) +{ + printf("%s on line %d\n", foo, _line_count); + return 0; +} diff --git a/agents/virt/config/fence_virt.conf b/agents/virt/config/fence_virt.conf new file mode 100644 index 0000000..03e2c58 --- /dev/null +++ b/agents/virt/config/fence_virt.conf @@ -0,0 +1,20 @@ +fence_virtd { + listener = "multicast"; + backend = "libvirt"; +} + +listeners { + multicast { + key_file = "/etc/cluster/fence_xvm.key"; + address = "225.0.0.12"; + # Needed on Fedora systems + interface = "virbr0"; + } +} + +backends { + libvirt { + uri = "qemu:///system"; + } +} + diff --git a/agents/virt/config/simpleconfig.c b/agents/virt/config/simpleconfig.c new file mode 100644 index 0000000..3315b32 --- /dev/null +++ b/agents/virt/config/simpleconfig.c @@ -0,0 +1,494 @@ +#include "config.h" + +#include <stdio.h> +#include <pthread.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <assert.h> + +#include "simpleconfig.h" +#include "config-stack.h" +#include "static_map.h" + + +static pthread_mutex_t parser_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int +print_value(struct value *v, int depth, FILE *fp) +{ + int x; + + if (v->val == NULL) + return 0; + + for (x = 0; x < depth; x++) + fprintf(fp, "\t"); + fprintf(fp, "%s = \"%s\";\n", v->id, v->val); + + return 0; +} + + +static void +_sc_dump_d(struct node *node, int depth, FILE *fp) +{ + struct node *n; + struct value *v; + int x; + + if (!node) { + //printf("Empty node\n"); + return; + } + + for (x = 0; x < depth; x++) + fprintf(fp, "\t"); + + if (node->val) { + fprintf(fp, "%s = \"%s\" {\n", node->id, node->val); + } else { + fprintf(fp, "%s {\n", node->id); + } + + for (n = node->nodes; n; n = n->next) { + _sc_dump_d(n, depth+1, fp); + } + + for (v = node->values; v; v = v->next) { + print_value(v, depth+1, fp); + } + + for (x = 0; x < depth; x++) + fprintf(fp, "\t"); + fprintf(fp, "}\n\n"); +} + + +static void +_sc_dump(void *config, FILE *fp) +{ + struct node *n, *node; + struct value *v, *values; + + if (!config) + return; + + values = ((struct parser_context *)config)->val_list; + node = ((struct parser_context *)config)->node_list; + + for (n = node; n; n = n->next) { + _sc_dump_d(n, 0, fp); + } + + for (v = values; v; v = v->next) { + print_value(v, 0, fp); + } +} + + +static int +free_value(struct value *v) +{ + if (v) { + free(v->id); + free(v->val); + free(v); + } + + return 0; +} + + +static void +_sc_free_node(struct node *node) +{ + struct node *n; + struct value *v; + + if (!node) + return; + + while (node->nodes) { + n = node->nodes; + if (n) { + node->nodes = node->nodes->next; + _sc_free_node(n); + } + } + + while (node->values) { + v = node->values; + node->values = node->values->next; + free_value(v); + } + + free(node->id); + free(node); +} + + +static int +_sc_free(void *config) +{ + struct node *n, *nlist; + struct value *v, *vlist; + + if (!config) + return -1; + + vlist = ((struct parser_context *)config)->val_list; + nlist = ((struct parser_context *)config)->node_list; + + while (nlist) { + n = nlist; + nlist = nlist->next; + _sc_free_node(n); + } + + ((struct parser_context *)config)->node_list = NULL; + + while (vlist) { + v = vlist; + vlist = vlist->next; + free_value(v); + } + + ((struct parser_context *)config)->val_list = NULL; + + free(config); + + return 0; +} + + +static int +_sc_get(void *config, const char *key, char *value, size_t valuesz) +{ + char buf[1024]; + struct node *n, *node; + struct value *v, *values; + char *ptr; + char *slash; + char *bracket; + char *id; + int req_index = 0; + int curr_index = 0; + int found; + + if (!config) + return -1; + + node = ((struct parser_context *)config)->node_list; + values = ((struct parser_context *)config)->val_list; + + assert(strlen(key) < sizeof(buf)); + + ptr = (char *)key; + + while ((slash = strchr(ptr, '/'))) { + memset(buf, 0, sizeof(buf)); + strncpy(buf, ptr, (slash - ptr)); + ptr = ++slash; + + id = NULL; + bracket = strchr(buf, '['); + if (bracket) { + *bracket = 0; + ++bracket; + + id = bracket; + + bracket = strchr(bracket, ']'); + if (!bracket) + return 1; + *bracket = 0; + + if (id[0] == '@') { + ++id; + if (!strlen(id)) { + return 1; + } + } else { + req_index = atoi(id); + if (req_index <= 0) + return 1; + id = NULL; + } + } + + found = 0; + curr_index = 0; + + for (n = node; n; n = n->next) { + + if (strcasecmp(n->id, buf)) + continue; + + ++curr_index; + + if (req_index && (curr_index != req_index)) { + continue; + } else if (id && strcasecmp(n->val, id)) { + continue; + } + + node = n->nodes; + values = n->values; + found = 1; + break; + } + + if (!found) + return 1; + } + + if (ptr[0] != '@') { + + strncpy(buf, ptr, sizeof(buf) - 1); + id = NULL; + bracket = strchr(buf, '['); + if (bracket) { + *bracket = 0; + ++bracket; + + id = bracket; + + bracket = strchr(bracket, ']'); + if (!bracket) + return 1; + *bracket = 0; + + if (id[0] == '@') { + ++id; + if (!strlen(id)) { + return 1; + } + } else { + req_index = atoi(id); + if (req_index <= 0) + return 1; + id = NULL; + } + } + + found = 0; + curr_index = 0; + + for (n = node; n; n = n->next) { + + if (strcasecmp(n->id, buf)) + continue; + + ++curr_index; + + if (req_index && (curr_index != req_index)) { + continue; + } else if (id && strcasecmp(n->val, id)) { + continue; + } + if (node->val) { + strncpy(value, node->val, valuesz); + return 0; + } + return 1; + } + } + + ++ptr; + found = 0; + id = NULL; + + strncpy(buf, ptr, sizeof(buf) - 1); + bracket = strchr(buf, '['); + + req_index = 0; + curr_index = 0; + + if (bracket) { + *bracket = 0; + ++bracket; + + id = bracket; + + bracket = strchr(bracket, ']'); + if (!bracket) + return 1; + *bracket = 0; + + req_index = atoi(id); + if (req_index <= 0) + return 1; + id = NULL; + } + + for (v = values; v; v = v->next) { + + if (strcasecmp(v->id, buf)) + continue; + + ++curr_index; + if (req_index && (curr_index != req_index)) + continue; + snprintf(value, valuesz, "%s", v->val); + return 0; + } + + return 1; +} + + +static int +_sc_set(void *config, const char *key, const char *value) +{ + char buf[1024]; + struct node *n, **nodes = &((struct parser_context *)config)->node_list; + struct value *v, **values = &((struct parser_context *)config)->val_list; + char *ptr; + char *slash; + char *id_dup, *val_dup; + int found = 0; + + ptr = (char *)key; + while ((slash = strchr(ptr, '/'))) { + memset(buf, 0, sizeof(buf)); + strncpy(buf, ptr, (slash - ptr)); + ptr = ++slash; + found = 0; + + for (n = *nodes; n; n = n->next) { + if (strcasecmp(n->id, buf)) + continue; + + nodes = &n->nodes; + values = &n->values; + found = 1; + break; + } + + if (!found) { + id_dup = strdup(buf); + if (!id_dup) + return -1; + _sc_node_add(id_dup, NULL, NULL, NULL, nodes); + n = *nodes; + nodes = &n->nodes; + values = &n->values; + } + } + + if (ptr[0] != '@') + return 1; + ++ptr; + + for (v = *values; v; v = v->next) { + if (strcasecmp(v->id, ptr)) + continue; + + ptr = v->val; + if (value) { + v->val = strdup(value); + if (!v->val) { + v->val = ptr; + return -1; + } + } else { + v->val = NULL; + } + free(ptr); + + return 0; + } + + if (!value) + return 0; + + id_dup = strdup(ptr); + if (!id_dup) + return -1; + + val_dup = strdup(value); + if (!val_dup) { + free(id_dup); + return -1; + } + _sc_value_add(id_dup, val_dup, values); + + return 0; +} + + +static int +_sc_parse(const char *filename, void **config) +{ + struct parser_context *c; + FILE *fp = NULL; + int ret = 0; + + if (!config) + return -1; + + pthread_mutex_lock(&parser_mutex); + if (filename) { + fp = fopen(filename, "r"); + yyin = fp; + if (fp) + ret = yyparse(); + else + ret = 1; + } else { + ret = 1; + } + + c = malloc(sizeof(*c)); + if (!c) { + ret = -1; + goto out_unlock; + } + c->node_list = node_list; + c->val_list = val_list; + c->next = NULL; + val_list = NULL; + node_list = NULL; + *config = (void *)c; + + if (fp) + fclose(fp); + +out_unlock: + pthread_mutex_unlock(&parser_mutex); + return ret; +} + + +static const config_object_t sc_object = { + .get = _sc_get, + .set = _sc_set, + .parse = _sc_parse, + .free = _sc_free, + .dump = _sc_dump, + .info = NULL +}; + + +config_object_t * +sc_init(void) +{ + config_object_t *o; + + o = malloc(sizeof(*o)); + if (!o) + return NULL; + memset(o, 0, sizeof(*o)); + memcpy(o, &sc_object, sizeof(*o)); + + return o; +} + + +void +sc_release(config_object_t *c) +{ + sc_free(c); + free(c); +} diff --git a/agents/virt/docs/README b/agents/virt/docs/README new file mode 100644 index 0000000..e2b19bc --- /dev/null +++ b/agents/virt/docs/README @@ -0,0 +1,125 @@ +TODO: update + +I. Fence_xvm - Virtual machine fencing agent + +Fence_xvm is an agent which establishes a communications link between +a cluster of virtual machines (VC) and a cluster of domain0/physical +nodes which are hosting the virtual cluster. Its operations are +fairly simple. + + (a) Start a listener service. + (b) Send a multicast packet requesting that a VM be fenced. + (c) Authenticate client. + (e) Read response. + (f) Exit with success/failure, depending on the response received. + +If any of the above steps fail, the fencing agent exits with a failure +code and fencing is retried by the virtual cluster at a later time. +Because of the simplicty of fence_xvm, it is not necessary that +fence_xvm be run from within a virtualized guest - all it needs is +libnspr and libnss and a shared private key (for authentication; we +would hate to receive a false positive response from a node not in the +cluster!). + + +II. Fence_virtd - Virtual machine fencing host + +Fence_virtd is a daemon which runs on physical hosts (e.g. in domain0) +of the cluster hosting the virtual cluster. It listens on a port +for multicast traffic from virtual cluster(s), and takes actions. +Multiple disjoint virtual clusters can coexist on a single physical +host cluster, but this requires multiple instances of fence_virtd. + +NOTE: fence_virtd *MUST* be run on ALL nodes in a given cluster which +will be hosting virtual machines if fence_xvm is to be used for +fencing! + +There are a couple of ways the multicast packet is handled, +depending on the state of the host OS. It might be hosting the VM, +or it might not. Furthermore, the VM might "reside" on a host which +has failed. + +In order to be able to guarantee safe fencing of a VM even if the +last- known host is down, we must store the last-known locations of +each virtual machine in some sort of cluster-wide way. For this, we +use the corosync CPG API. Every few seconds, fence_virtd queries the +hypervisor via libvirt and stores any local VM states and sends those +states over CPG to all other members. In the event of a physical node +failure (which consequently causes the failure of one or more guests), +we can then read the stored VM state corresponding to the guest we need +to fence to find out the previous owner. With that information, we can +infer if the known host node has been fenced. If so, then the VM is clean +as well. The physical cluster must, therefore, have fencing in order for +fence_virtd to work. + +Operation of a node hosting a VM which needs to be fenced: + + (a) Receive multicast packet + (b) Authenticate multicast packet + (c) Open connection to host contained within multicast + packet. + (d) Authenticate server. + (e) Carry out fencing operation (e.g. call libvirt to destroy or + reboot the VM; there is no "on" method at this point). + (f) If operation succeeds, send success response. + +Operation of high-node-ID: + + (a) Receive multicast packet + (b) Authenticate multicast packet + (c) Read VM state from stored CPG messages + (d) Check liveliness of nodeID hosting VM (if alive, do nothing) + (e) Open connection to host contained within multicast + packet. + (f) Check with CMAN to see if last-known host has been fenced. + (g) If last-known host has been fenced, send success response. + (h) Authenticate server & send response. + +NOTE: There is always a possibility that a VM is started again +before the fencing operation and CPG update for that VM +occurs. If the VM has booted and rejoined the cluster, fencing will +not be necessary. If it is in the process of booting, but has not +yet joined the cluster, fencing will also not be necessary - because +it will not be using cluster resources yet. + + +III. Security considerations + +While fencing is generally expected to run on a more or less trusted +network, there are cases where it may not be. + +* The multicast packet is subject to replay attacks, but because no +fencing action is taken based solely on the information contained +within the packet, this should not allow an attacker to maliciously +fence a VM from outside the cluster, though it may be possible to +cause a DoS of fence_virtd if enough multicast packets are sent. + +* The only currently supported authentication mechanisms are simple +challenge-response based on a shared private key and pseudorandom +number generation. + +* An attacker with access to the shared key(s) can easily fence any +known VM, even if they are not on a cluster node. + +* Different shared keys should be used for different virtual +clusters on the same subnet (whether in the same physical cluster +or not). Additionally, multiple fence_virtd instances must be run +(each listening on a different multicast IP + port combination). + +IV. Configuration + +Generate a random key file. An example of how to generate it is: + + dd if=/dev/urandom of=/etc/cluster/fence_xvm.key bs=4096 count=1 + +Distribute the generated key file to all domUs in a cluster as well +as all dom0s which will be hosting that particular cluster of domUs. +The key should not be placed on shared file systems (because shared +file systems require the cluster, which requires fencing...). + +Start fence_virtd on all hosts + +Configure fence_xvm on the domU cluster... + +rest...tbd + diff --git a/agents/virt/docs/TODO b/agents/virt/docs/TODO new file mode 100644 index 0000000..17456cf --- /dev/null +++ b/agents/virt/docs/TODO @@ -0,0 +1,7 @@ +High Priority / Blockers for v1.0; + +* endian-clean / 64-bit clean data structure analysis + +Future Stuff: + +* clean up development bits so third parties can develop plugins diff --git a/agents/virt/docs/architecture.txt b/agents/virt/docs/architecture.txt new file mode 100644 index 0000000..54fda11 --- /dev/null +++ b/agents/virt/docs/architecture.txt @@ -0,0 +1,16 @@ +The actual architecture of fence_virtd is very simple. We have a set +of listener plugins which listens for fencing requests for virtual +machines. + +These plugins are assigned callbacks which are entry functions in to +the backend plugins. The backend plugins perform the actual fencing +request. + +In the middle, we have only enough code to provide basic integration +functions between the listener and backend plugins. This includes a +very simple confiugration plugin which we pass to each of the plugins. + +Because we are passing function pointers in to the plugins themselves +for configuration (rather than having the plugins call an API directly, +for example), we are able to swap out the configuration subsystem for +other, more full-featured configuration systems, such as libccs. diff --git a/agents/virt/docs/fence_virt.txt b/agents/virt/docs/fence_virt.txt new file mode 100644 index 0000000..e554ce4 --- /dev/null +++ b/agents/virt/docs/fence_virt.txt @@ -0,0 +1,127 @@ +We need a fencing agent which can work in a variety of guest cluster +configurations and host configurations. + +Requirements + +1. Nonrequirement of guest to host networking. Virtual machines + may be configured to run using a nework unknown to the host + operating system. Therefore, the ability to run without network + communication between the guest and the hsot is required. + +2. Ease of configuration. The absolute minimum possible configuration + must be available. + +3. Nonrequirement of host clustering software. Multiple layers of + configuration sucks. While I fundamentally disagree with the general + idea that running CMAN on the host constitutes a "heavyweight + cluster", perception is important. + +4. Ability to support RHEV-M, oVirt server, and other virtual machine + management technologies. This is beneficial from a security standpoint + since it is assumed the management server will be aware of what VMs + are allowed to fence what other VMs. + +5. Upgrade compatibility with fence_xvm from a configuration standpoint. + This may be provided by a symlink over fence_xvm. If this feature + can not be provided as a matter of design, a method to convert an + existing fence_xvm/fence_xvmd configuration to fence_virt must be + present. + + +Guest to Host Interaction +------------------------- + +The proposal is to use various communications media plugins in order +to facilitate flexibility with respect to how virtual machine +environments are configured. + +There are at least 3 simple plugins for guest/client to host/server +communications: + + * Direct serial. The guest sends fencing requests out via /dev/ttySX + in the guest. The host is listening on a Unix domain socket[1], + and forwards fencing requests accordingly. + + This satisifies most of the requirements, but adds a conundrum + when configuring guest clusters, as /dev/ttySX may be /dev/ttySY + on another guest. So, either we must account for this per-guest + configuration discrepancy or we must make it an administrative + requirement to provide the same serial device on each host + + * Multicast. This violates the networking requirement, but this is + okay since this method of operation is optional. This operational + mode provides for one of the simpler configurations: all that is + needed is the guest's name or UUID. The guest to host + communications operates in the same manner as fence_xvm/fence_xvmd, + except that there is an implied requirement on restricting the + multicast packets accepted to be from the local guests. + + * VM Channel over Serial. This works like direct serial, but + instead of owning the whole device, the device may be shared between + multiple applications. The server subscribes to a channel and + listens for fencing requests on the channel; the client in the + guest OS connects to the channel and issues fencing requests across + it. One interesting thing is that it may be possible to provide + unprivileged users the ability to fence using this method (I + do not claim to know if this is useful or not). + + +Host to Hypervisor interaction +------------------------------ + +Similar to the way we have plugins for guest to host interaction, +we also have plugins which actually do the real work. These plugins +are responsible for all of the actual real work performed, including +tracking VMs if required, forwarding requests to the appropriate hosts +or management services, and handling the responses. + +We propose at 5 plugins in this case: + + * Libvirt (local-only). There is no intracommunication and no + migration support is provided + + * Cluster CPG (+ libvirt). This the way fence_xvmd + operates today. This setup has the most requirements on the + infrastructure, as it requires guest to host networking _and_ + host-to-host clustering in order to keep track of virtual + machines. The benefit is that it is self-contained and requires + no external management nodes. VM states are stored so that other + CPG group members know the locations of other VMs and can make + some decisions about whether a VM is dead based on whether a host + is dead (i.e. if fencing is in use or can be performed on the + host). + + * Libvirt-QMF ... ??? Subscription to the appropriate cluster + specific AMQP channel is required on the host side, but this + handles routing the message very easily. The fencing request + is forwarded to the other listeners on the channel, the VM owner + takes the action requested and returns a value. When new VMs + are created, the event is broadcast out via the AMQP channel so + other hosts know the locations of other VMs and can make some + decisions about whether a VM is dead based on whether a host + is dead (i.e. if fencing is in use or can be performed on the + host). + + * oVirt Manager. The request is forwarded to the oVirt Manager + and the oVirt manager is responsible for taking the appropriate + action and responding to the request. + + * RHEV-M. The request is forwarded to the RHEV-M node, which is + responsible for taking the appropriate action and responding to + the request. + + +These plugins have no requirements on which guest to host communication +plugin is used (you could, if you wanted, use 'direct serial' with +'cluster cpg', or 'multicast' with 'RHEV-H' for example). + +These plugins must also be able to discover where appropriate. For +example, the cpg plugin can only be used if corosync/openais +is running. A defined plugin preference order should be specified/documented +so that the host daemon behaves in a predictable manner in absence of +host-side configuration data (about which plugin to use). + + +[1] TCP was also explored, however, the security is much better + using a Unix domain socket, despite the additional complexity + of listening for VM creation events. diff --git a/agents/virt/fence_virtd.service.in b/agents/virt/fence_virtd.service.in new file mode 100644 index 0000000..9d2836f --- /dev/null +++ b/agents/virt/fence_virtd.service.in @@ -0,0 +1,23 @@ +[Unit] +Description=Fence-Virt system host daemon +Documentation=man:fence_virtd(8) +Documentation=man:fence_virt.conf(5) + +After=basic.target +After=network.target +After=syslog.target +After=libvirtd.service +After=corosync.service + +Requires=basic.target +Requires=network.target + +[Install] +WantedBy=multi-user.target + +[Service] +Type=forking +Restart=on-failure +Environment="FENCE_VIRTD_ARGS=-w" + +# Autogenerated below here diff --git a/agents/virt/include/bcast.h b/agents/virt/include/bcast.h new file mode 100644 index 0000000..5113f04 --- /dev/null +++ b/agents/virt/include/bcast.h @@ -0,0 +1,16 @@ +#ifndef _XVM_MCAST_H +#define _XVM_MCAST_H + +#define IPV4_MCAST_DEFAULT "225.0.0.12" +#define IPV6_MCAST_DEFAULT "ff05::3:1" + +int ipv4_recv_sk(char *addr, int port); +int ipv4_send_sk(char *src_addr, char *addr, int port, + struct sockaddr *src, socklen_t slen, + int ttl); +int ipv6_recv_sk(char *addr, int port); +int ipv6_send_sk(char *src_addr, char *addr, int port, + struct sockaddr *src, socklen_t slen, + int ttl); + +#endif diff --git a/agents/virt/include/client.h b/agents/virt/include/client.h new file mode 100644 index 0000000..48b92c3 --- /dev/null +++ b/agents/virt/include/client.h @@ -0,0 +1,9 @@ +#ifndef _CLIENT_H +#define _CLIENT_H + +int tcp_fence_virt(fence_virt_args_t *args); +int serial_fence_virt(fence_virt_args_t *args); +int mcast_fence_virt(fence_virt_args_t *args); +int vsock_fence_virt(fence_virt_args_t *args); +void do_read_hostlist(int fd, int timeout); +#endif diff --git a/agents/virt/include/debug.h b/agents/virt/include/debug.h new file mode 100644 index 0000000..d6a5416 --- /dev/null +++ b/agents/virt/include/debug.h @@ -0,0 +1,31 @@ +/* + Copyright Red Hat, Inc. 2007 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +#ifndef _DBG_H +#define _DBG_H + +void dset(int); +int dget(void); + +#define dbg_printf(level, fmt, args...) \ +do { \ + if (dget()>=level) \ + printf(fmt, ##args); \ +} while(0) + +#endif diff --git a/agents/virt/include/fdops.h b/agents/virt/include/fdops.h new file mode 100644 index 0000000..f3194de --- /dev/null +++ b/agents/virt/include/fdops.h @@ -0,0 +1,14 @@ +#ifndef _FDOPS_H +#define _FDOPS_H +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <errno.h> + +int _select_retry(int fdmax, fd_set * rfds, fd_set * wfds, fd_set * xfds, + struct timeval *timeout); +ssize_t _write_retry(int fd, void *buf, int count, struct timeval * timeout); +ssize_t _read_retry(int sockfd, void *buf, int count, + struct timeval * timeout); + +#endif diff --git a/agents/virt/include/history.h b/agents/virt/include/history.h new file mode 100644 index 0000000..3d28518 --- /dev/null +++ b/agents/virt/include/history.h @@ -0,0 +1,25 @@ +#ifndef _HISTORY_H +#define _HISTORY_H + +typedef struct _history_node { + list_head(); + void *data; + time_t when; +} history_node; + +typedef int (*history_compare_fn)(void *, void *); + +typedef struct _history_info { + history_node *hist; + history_compare_fn compare_func; + time_t timeout; + size_t element_size; +} history_info_t; + +history_info_t *history_init(history_compare_fn func, + time_t expiration, size_t element_size); +int history_check(history_info_t *hinfo, void *stuff); +int history_record(history_info_t *hinfo, void *data); +int history_wipe(history_info_t *hinfo); + +#endif diff --git a/agents/virt/include/ip_lookup.h b/agents/virt/include/ip_lookup.h new file mode 100644 index 0000000..3386c71 --- /dev/null +++ b/agents/virt/include/ip_lookup.h @@ -0,0 +1,40 @@ +/* + Copyright Red Hat, Inc. 2004,2006 + + The Magma Cluster API Library is free software; you can redistribute + it and/or modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either version + 2.1 of the License, or (at your option) any later version. + + The Magma Cluster API Library is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +*/ +/** @file + * Header for ip_lookup.c + */ +#ifndef _IP_LOOKUP_H +#define _IP_LOOKUP_H + +#include <sys/queue.h> + +typedef struct _ip_address { + TAILQ_ENTRY(_ip_address) ipa_entries; + char ipa_family; + char *ipa_address; +} ip_addr_t; + +typedef TAILQ_HEAD(_ip_list, _ip_address) ip_list_t; + +int ip_search(ip_list_t *ipl, char *ip_name); +int ip_free_list(ip_list_t *ipl); +int ip_build_list(ip_list_t *ipl); +int ip_lookup(char *, struct addrinfo **); + +#endif diff --git a/agents/virt/include/list.h b/agents/virt/include/list.h new file mode 100644 index 0000000..01340d6 --- /dev/null +++ b/agents/virt/include/list.h @@ -0,0 +1,84 @@ +#ifndef _LIST_H +#define _LIST_H + +/** + Simple list handlig macros. + Needs rewrite or inclusion of /usr/include/linux/list.h as a replacement. + */ + +/* Must be first if structure is going to use it. */ +struct list_entry { + struct list_entry *le_next, *le_prev; +}; + +#define list_head() struct list_entry _list_head + +#define le(p) (&((*p)._list_head)) + +#define list_insert(list, newnode) \ +do { \ + if (!(*list)) { \ + le(newnode)->le_next = \ + le(newnode)->le_prev = le(newnode); \ + *list = (void *)le(newnode); \ + } else { \ + le(*list)->le_prev->le_next = le(newnode); \ + le(newnode)->le_next = le(*list); \ + le(newnode)->le_prev = le(*list)->le_prev; \ + le(*list)->le_prev = le(newnode); \ + } \ +} while (0) + + +#define list_prepend(list, newnode) \ +do { \ + list_insert(list, newnode); \ + *list = newnode; \ +} while (0) + + +#define list_remove(list, oldnode) \ +do { \ + if (le(oldnode) == le(*list)) { \ + *list = (void *)le(*list)->le_next; \ + } \ + if (le(oldnode) == le(*list)) { \ + le(oldnode)->le_next = NULL; \ + le(oldnode)->le_prev = NULL; \ + *list = NULL; \ + } else { \ + le(oldnode)->le_next->le_prev = le(oldnode)->le_prev; \ + le(oldnode)->le_prev->le_next = le(oldnode)->le_next; \ + le(oldnode)->le_prev = NULL; \ + le(oldnode)->le_next = NULL; \ + } \ +} while (0) + + +/* + * list_for(list, tmp, counter) { + * stuff; + * } + * + * counter = # of items in list when done. + * * sets cnt to 0 before even checking list; + * * checks for valid list + * * traverses list, incrementing counter. If we get to the for loop, + * there must be at least one item in the list + * * cnt ends up being the number of items in the list. + */ +#define list_for(list, curr, cnt) \ + if ((!(cnt=0)) && (*list != NULL)) \ + for (curr = *list; \ + (cnt == 0) || (curr != *list); \ + curr = (void*)le(curr)->le_next, \ + cnt++) + +#define list_for_rev(list, curr, cnt) \ + if ((!(cnt=0)) && (*list != NULL)) \ + for (curr = (void *)(le(*list)->le_prev); \ + (cnt == 0) || ((void *)curr != le(*list)->le_prev); \ + curr = (void*)(le(curr)->le_prev), \ + cnt++) + +#endif diff --git a/agents/virt/include/mcast.h b/agents/virt/include/mcast.h new file mode 100644 index 0000000..f86ad96 --- /dev/null +++ b/agents/virt/include/mcast.h @@ -0,0 +1,32 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +#ifndef _XVM_MCAST_H +#define _XVM_MCAST_H + +#define IPV4_MCAST_DEFAULT "225.0.0.12" +#define IPV6_MCAST_DEFAULT "ff05::3:1" + +int ipv4_recv_sk(char *addr, int port, unsigned int ifindex); +int ipv4_send_sk(char *src_addr, char *addr, int port, + struct sockaddr *src, socklen_t slen); +int ipv6_recv_sk(char *addr, int port, unsigned int ifindex); +int ipv6_send_sk(char *src_addr, char *addr, int port, + struct sockaddr *src, socklen_t slen); + +#endif diff --git a/agents/virt/include/options.h b/agents/virt/include/options.h new file mode 100644 index 0000000..6e2c1c1 --- /dev/null +++ b/agents/virt/include/options.h @@ -0,0 +1,99 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +#ifndef _XVM_OPTIONS_H +#define _XVM_OPTIONS_H + +typedef enum { + F_FOREGROUND = 0x1, + F_NOCCS = 0x2, + F_ERR = 0x4, + F_HELP = 0x8, + F_USE_UUID = 0x10, + F_VERSION = 0x20, + F_CCSERR = 0x40, + F_CCSFAIL = 0x80, + F_NOCLUSTER = 0x100 +} arg_flags_t; + +typedef enum { + MODE_MULTICAST = 0, + /*MODE_BROADCAST = 1,*/ + MODE_SERIAL = 2, + MODE_VMCHANNEL = 3, + MODE_TCP = 4, + MODE_VSOCK = 5 +} client_mode_t; + +typedef struct { + char *domain; + fence_cmd_t op; + client_mode_t mode; + int debug; + int timeout; + int delay; + int retr_time; + arg_flags_t flags; + + struct network_args { + char *addr; + char *ipaddr; + char *key_file; + uint32_t cid; + int port; + fence_hash_t hash; + fence_auth_type_t auth; + int family; + unsigned int ifindex; + } net; + + struct serial_args { + char *device; /* Serial device */ + char *speed; + char *address; /* vmchannel IP */ + } serial; +} fence_virt_args_t; + +/* Private structure for commandline / stdin fencing args */ +struct arg_info { + const char opt; + const char *opt_desc; + const char *stdin_opt; + const char *obsoletes; + int deprecated; + int eh; + const char *content_type; + const char *default_value; + const char *desc; + void (*assign)(fence_virt_args_t *, struct arg_info *, char *); +}; + + +/* Get options */ +void args_init(fence_virt_args_t *args); +void args_finalize(fence_virt_args_t *args); + +void args_get_getopt(int argc, char **argv, const char *optstr, + fence_virt_args_t *args); +void args_get_stdin(const char *optstr, fence_virt_args_t *args); +void args_get_ccs(const char *optstr, fence_virt_args_t *args); +void args_usage(char *progname, const char *optstr, int print_stdin); +void args_print(fence_virt_args_t *args); +void args_metadata(char *progname, const char *optstr); + +#endif diff --git a/agents/virt/include/server_plugin.h b/agents/virt/include/server_plugin.h new file mode 100644 index 0000000..04ceae0 --- /dev/null +++ b/agents/virt/include/server_plugin.h @@ -0,0 +1,130 @@ +/* */ + +#ifndef _SERVER_PLUGIN_H +#define _SERVER_PLUGIN_H + +#include "config.h" + +#define PLUGIN_VERSION_LISTENER ((double)0.3) +#define PLUGIN_VERSION_BACKEND ((double)0.2) + +typedef void * listener_context_t; +typedef void * backend_context_t; + +/* These callbacks hand requests off to the + appropriate backend. */ + +/* Do nothing. Returns 1 (failure) to caller */ +typedef int (*fence_null_callback)(const char *vm_name, + void *priv); + +/* Turn the VM 'off'. Returns 0 to caller if successful or + nonzero if unsuccessful. */ +typedef int (*fence_off_callback)(const char *vm_name, const char *src, + uint32_t seqno, void *priv); + +/* Turn the VM 'on'. Returns 0 to caller if successful or + nonzero if unsuccessful. */ +typedef int (*fence_on_callback)(const char *vm_name, const char *src, + uint32_t seqno, void *priv); + +/* Reboot a VM. Returns 0 to caller if successful or + nonzero if unsuccessful. */ +typedef int (*fence_reboot_callback)(const char *vm_name, const char *src, + uint32_t seqno, void *priv); + +/* Get status of a VM. Returns 0 to caller if VM is alive or + nonzero if VM is not alive. */ +typedef int (*fence_status_callback)(const char *vm_name, + void *priv); + +/* Get status of backend. Returns 0 to caller if backend + is responding to requests. */ +typedef int (*fence_devstatus_callback)(void *priv); + + +/* VMs available to fence. Returns 0 to caller if backend + is responding to requests and a host list can be produced */ +typedef int (*hostlist_callback)(const char *vm_name, const char *uuid, + int state, void *arg); +typedef int (*fence_hostlist_callback)(hostlist_callback cb, + void *arg, void *priv); + +typedef int (*backend_init_fn)(backend_context_t *c, + config_object_t *config); +typedef int (*backend_cleanup_fn)(backend_context_t c); + +typedef struct _fence_callbacks { + fence_null_callback null; + fence_off_callback off; + fence_on_callback on; + fence_reboot_callback reboot; + fence_status_callback status; + fence_devstatus_callback devstatus; + fence_hostlist_callback hostlist; +} fence_callbacks_t; + +typedef struct backend_plugin { + const char *name; + const char *version; + const fence_callbacks_t *callbacks; + backend_init_fn init; + backend_cleanup_fn cleanup; +} backend_plugin_t; + +double backend_plugin_version(void); +const backend_plugin_t * backend_plugin_info(void); + +#define BACKEND_VER_SYM backend_plugin_version +#define BACKEND_INFO_SYM backend_plugin_info +#define BACKEND_VER_STR "backend_plugin_version" +#define BACKEND_INFO_STR "backend_plugin_info" + +typedef int (*listener_init_fn)(listener_context_t *c, + const fence_callbacks_t *cb, + config_object_t *config, + map_object_t *map, + void *priv); +typedef int (*listener_dispatch_fn)(listener_context_t c, + struct timeval *timeout); +typedef int (*listener_cleanup_fn)(listener_context_t c); + + +typedef struct listener_plugin { + const char *name; + const char *version; + listener_init_fn init; + listener_dispatch_fn dispatch; + listener_cleanup_fn cleanup; +} listener_plugin_t; + +double listener_plugin_version(void); +const listener_plugin_t * listener_plugin_info(void); + +#define LISTENER_VER_SYM listener_plugin_version +#define LISTENER_INFO_SYM listener_plugin_info +#define LISTENER_VER_STR "listener_plugin_version" +#define LISTENER_INFO_STR "listener_plugin_info" + +typedef enum { + PLUGIN_NONE = 0, + PLUGIN_LISTENER = 1, + PLUGIN_BACKEND = 2 +} plugin_type_t; + +#ifdef __cplusplus +extern "C" { +#endif + +const backend_plugin_t *plugin_find_backend(const char *name); +const listener_plugin_t *plugin_find_listener(const char *name); + +void plugin_dump(void); +int plugin_load(const char *filename); +void plugin_unload(void); +int plugin_search(const char *pathname); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/agents/virt/include/simple_auth.h b/agents/virt/include/simple_auth.h new file mode 100644 index 0000000..4cd57ed --- /dev/null +++ b/agents/virt/include/simple_auth.h @@ -0,0 +1,35 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +#ifndef _XVM_SIMPLE_AUTH_H +#define _XVM_SIMPLE_AUTH_H + +#include <sys/types.h> + +/* 2-way challenge/response simple auth */ +#define DEFAULT_KEY_FILE "/etc/cluster/fence_xvm.key" + +int read_key_file(char *, char *, size_t); +int sock_challenge(int, fence_auth_type_t, void *, size_t, int); +int sock_response(int, fence_auth_type_t, void *, size_t, int); +int sign_request(fence_req_t *, void *, size_t); +int verify_request(fence_req_t *, fence_hash_t, void *, size_t); + +/* SSL certificate-based authentication TBD */ + +#endif diff --git a/agents/virt/include/simpleconfig.h b/agents/virt/include/simpleconfig.h new file mode 100644 index 0000000..6aba85f --- /dev/null +++ b/agents/virt/include/simpleconfig.h @@ -0,0 +1,56 @@ +#ifndef _SIMPLECONFIG_H +#define _SIMPLECONFIG_H + +typedef int (*config_get_t)(void *config, const char *key, + char *value, size_t valuesz); +typedef int (*config_set_t)(void *config, const char *key, + const char *value); +typedef int (*config_parse_t)(const char *filename, void **config); +typedef int (*config_free_t)(void *config); +typedef void (*config_dump_t)(void *config, FILE *fp); + +/* + * We use an abstract object here so we do not have to link loadable + * modules against the configuration library. + */ + +typedef struct { + config_get_t get; + config_set_t set; + config_parse_t parse; + config_free_t free; + config_dump_t dump; + void *info; +} config_object_t; + +/* + * These macros may be called from within a loadable module + */ +#define sc_get(obj, key, value, valuesz) \ + obj->get(obj->info, key, value, valuesz) +#define sc_set(obj, key, value) \ + obj->set(obj->info, key, value) +#define sc_parse(obj, filename) \ + obj->parse(filename, &obj->info) +#define sc_free(obj) \ + obj->free(obj->info) +#define sc_dump(obj, fp) \ + obj->dump(obj->info, fp) + +/* + * Do not call the below functions from loadable modules. Doing so + * requires linking the configuration library in to the modules, which + * is what we want to avoid. + */ + +/* Returns a copy of our simple config object */ +config_object_t *sc_init(void); + +/* Frees a previously-allocated copy of our simple config object */ +void sc_release(config_object_t *c); + +int check_file_permissions(const char *fname); + +int do_configure(config_object_t *config, const char *filename); + +#endif diff --git a/agents/virt/include/static_map.h b/agents/virt/include/static_map.h new file mode 100644 index 0000000..736e823 --- /dev/null +++ b/agents/virt/include/static_map.h @@ -0,0 +1,34 @@ +#ifndef _STATIC_MAP_H +#define _STATIC_MAP_H + +typedef int (*map_load_t)(void *config, void **perm_info); +typedef int (*map_check_t)(void *info, const char *src, const char *tgt_uuid, const char *tgt_name); +typedef void (*map_cleanup_t)(void **info); + +typedef struct { + map_load_t load; + map_check_t check; + map_cleanup_t cleanup; + void *info; +} map_object_t; + +/* + * These macros may be called from within a loadable module + */ +#define map_load(obj, config) \ + obj->load(config, &obj->info) +#define map_check(obj, src, tgt_uuid) \ + obj->check(obj->info, src, tgt_uuid, NULL) +#define map_check2(obj, src, tgt_uuid, tgt_name) \ + obj->check(obj->info, src, tgt_uuid, tgt_name) +#define map_free(obj) \ + obj->cleanup(obj->info) + +/* Returns a copy of our simple config object */ +void *map_init(void); + +/* Frees a previously-allocated copy of our simple config object */ +void map_release(void *c); + + +#endif diff --git a/agents/virt/include/tcp.h b/agents/virt/include/tcp.h new file mode 100644 index 0000000..609f3e9 --- /dev/null +++ b/agents/virt/include/tcp.h @@ -0,0 +1,27 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +#ifndef _XVM_TCP_H +#define _XVM_TCP_H + +int ipv4_connect(struct in_addr *in_addr, uint16_t port, int timeout); +int ipv6_connect(struct in6_addr *in6_addr, uint16_t port, int timeout); +int ipv4_listen(const char *addr_str, uint16_t port, int backlog); +int ipv6_listen(const char *addr_str, uint16_t port, int backlog); + +#endif diff --git a/agents/virt/include/tcp_listener.h b/agents/virt/include/tcp_listener.h new file mode 100644 index 0000000..75dec93 --- /dev/null +++ b/agents/virt/include/tcp_listener.h @@ -0,0 +1,7 @@ +#ifndef __TCP_LISTENER_H +#define __TCP_LISTENER_H + +#define IPV4_TCP_ADDR_DEFAULT "127.0.0.1" +#define IPV6_TCP_ADDR_DEFAULT "::1" + +#endif diff --git a/agents/virt/include/xvm.h b/agents/virt/include/xvm.h new file mode 100644 index 0000000..bcd7db2 --- /dev/null +++ b/agents/virt/include/xvm.h @@ -0,0 +1,158 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +#ifndef _XVM_H +#define _XVM_H + +#include <stdint.h> +#include <sechash.h> +#include <netinet/in.h> +#include <byteswap.h> +#include <endian.h> + +#define XVM_VERSION "1.9.0" + +#define MAX_DOMAINNAME_LENGTH 64 /* XXX MAXHOSTNAMELEN */ +#define MAX_ADDR_LEN sizeof(struct sockaddr_in6) +#define DOMAIN0NAME "Domain-0" +#define DOMAIN0UUID "00000000-0000-0000-0000-000000000000" + +typedef enum { + HASH_NONE = 0x0, /* No packet signing */ + HASH_SHA1 = 0x1, /* SHA1 signing */ + HASH_SHA256 = 0x2, /* SHA256 signing */ + HASH_SHA512 = 0x3 /* SHA512 signing */ +} fence_hash_t; + +#define DEFAULT_HASH HASH_SHA256 + +typedef enum { + AUTH_NONE = 0x0, /* Plain TCP */ + AUTH_SHA1 = 0x1, /* Challenge-response (SHA1) */ + AUTH_SHA256 = 0x2, /* Challenge-response (SHA256) */ + AUTH_SHA512 = 0x3 /* Challenge-response (SHA512) */ + /* AUTH_SSL_X509 = 0x10 SSL X509 certificates */ +} fence_auth_type_t; + +#define DEFAULT_AUTH AUTH_SHA256 + +typedef enum { + FENCE_NULL = 0x0, + FENCE_OFF = 0x1, /* Turn the VM off */ + FENCE_REBOOT = 0x2, /* Hit the reset button */ + FENCE_ON = 0x3, /* Turn the VM on */ + FENCE_STATUS = 0x4, /* virtual machine status (off/on) */ + FENCE_DEVSTATUS = 0x5, /* Status of the fencing device */ + FENCE_HOSTLIST = 0x6, /* List VMs controllable */ + FENCE_METADATA = 0x7, /* Print fence agent metadata */ + FENCE_VALIDATEALL = 0x8 /* Validate command-line or stdin arguments and exit */ +} fence_cmd_t; + +#define DEFAULT_TTL 4 + +#ifndef DEFAULT_HYPERVISOR_URI +#define DEFAULT_HYPERVISOR_URI "qemu:///system" +#endif + +#define MAX_HASH_LENGTH SHA512_LENGTH +#define MAX_KEY_LEN 4096 + +typedef struct __attribute__ ((packed)) _fence_req { + uint8_t request; /* Fence request */ + uint8_t hashtype; /* Hash type used */ + uint8_t addrlen; /* Length of address */ + uint8_t flags; /* Special flags */ +#define RF_UUID 0x1 /* Flag specifying UUID */ + uint8_t domain[MAX_DOMAINNAME_LENGTH]; /* Domain to fence*/ + uint8_t address[MAX_ADDR_LEN]; /* We're this IP */ +#define DEFAULT_MCAST_PORT 1229 + uint16_t port; /* Port we bound to */ + uint8_t random[6]; /* Random Data */ + uint32_t seqno; /* Request identifier; can be random */ + uint32_t family; /* Address family */ + uint8_t hash[MAX_HASH_LENGTH]; /* Binary hash */ +} fence_req_t; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define swab_fence_req_t(req) \ +do { \ + (req)->seqno = bswap_32((req)->seqno); \ + (req)->family = bswap_32((req)->family); \ + (req)->port = bswap_32((req)->port); \ +} while(0) +#else +#define swab_fence_req_t(req) +#endif + + +/* for host list */ +typedef struct __attribute__ ((packed)) _host_info { + uint8_t domain[MAX_DOMAINNAME_LENGTH]; + uint8_t uuid[MAX_DOMAINNAME_LENGTH]; + uint8_t state; + uint8_t pad; +} host_state_t; + + +#define DEFAULT_SERIAL_DEVICE "/dev/ttyS1" +#define DEFAULT_SERIAL_SPEED "115200,8N1" +#define DEFAULT_CHANNEL_IP "10.0.2.179" +#define SERIAL_MAGIC 0x61626261 /* endian doesn't matter */ + +typedef struct __attribute__((packed)) _serial_fence_req { + uint32_t magic; + uint8_t request; + uint8_t flags; + uint8_t domain[MAX_DOMAINNAME_LENGTH]; + uint32_t seqno; +} serial_req_t; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define swab_serial_req_t(req) \ +do { \ + (req)->magic = bswap_32((req)->magic); \ + (req)->seqno = bswap_32((req)->seqno); \ +} while(0) +#else +#define swab_serial_req_t(req) +#endif + + +typedef struct __attribute__((packed)) _serial_fense_resp { + uint32_t magic; + uint8_t response; +} serial_resp_t; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define swab_serial_resp_t(req) \ +do { \ + (req)->magic = bswap_32((req)->magic); \ +} while(0) +#else +#define swab_serial_resp_t(req) +#endif + + +#define RESP_SUCCESS 0 +#define RESP_FAIL 1 +#define RESP_OFF 2 +#define RESP_PERM 3 +#define RESP_HOSTLIST 253 + + +#endif diff --git a/agents/virt/man/.gitignore b/agents/virt/man/.gitignore new file mode 100644 index 0000000..4a80f6e --- /dev/null +++ b/agents/virt/man/.gitignore @@ -0,0 +1,2 @@ +fence_virt.8 +fence_virt.wiki diff --git a/agents/virt/man/Makefile.am b/agents/virt/man/Makefile.am new file mode 100644 index 0000000..5b8ae36 --- /dev/null +++ b/agents/virt/man/Makefile.am @@ -0,0 +1,28 @@ +############################################################################### +############################################################################### +## +## Copyright (C) 2009-2021 Red Hat, Inc. +## +## This copyrighted material is made available to anyone wishing to use, +## modify, copy, or redistribute it subject to the terms and conditions +## of the GNU General Public License v.2. +## +############################################################################### +############################################################################### + +MAINTAINERCLEANFILES = Makefile.in + +dist_man8_MANS = fence_xvm.8 fence_virtd.8 +dist_man5_MANS = fence_virt.conf.5 +man8_MANS = fence_virt.8 + +fence_virt.8: $(top_builddir)/agents/virt/client/fence_virt $(top_srcdir)/lib/fence2man.xsl + set -e && \ + ../client/$(@:%.8=%) -o metadata > .$(@F).tmp && \ + xmllint --noout --relaxng $(top_srcdir)/lib/metadata.rng .$(@F).tmp && \ + xsltproc $(top_srcdir)/lib/fence2man.xsl .$(@F).tmp > $@ + xsltproc $(top_srcdir)/lib/fence2wiki.xsl .$(@F).tmp | grep -v '<?xml' > $(@F:%.8=%.wiki) + + +clean-local: + rm -f fence_virt.8* .*.8.tmp *.wiki diff --git a/agents/virt/man/fence_virt.conf.5 b/agents/virt/man/fence_virt.conf.5 new file mode 100644 index 0000000..f920a66 --- /dev/null +++ b/agents/virt/man/fence_virt.conf.5 @@ -0,0 +1,335 @@ +.TH fence_virt.conf 5 + +.SH NAME +fence_virt.conf - configuration file for fence_virtd + +.SH DESCRIPTION + +The fence_virt.conf file contains configuration information for fence_virtd, +a fencing request routing daemon for clusters of virtual machines. + +The file is tree-structured. There are parent/child relationships and sibling +relationships between the nodes. + + foo { + bar { + baz = "1"; + } + } + +There are three primary sections of fence_virt.conf. + +.SH SECTIONS +.SS fence_virtd + +This section contains global information about how fence_virtd is to operate. +The most important pieces of information are as follows: + +.TP +.B listener +. +the listener plugin for receiving fencing requests from clients + +.TP +.B backend +. +the plugin to be used to carry out fencing requests + +.TP +.B foreground +. +do not fork into the background. + +.TP +.B wait_for_init +. +wait for the frontend and backends to become available rather than giving up immediately. +This replaces wait_for_backend in 0.2.x. + +.TP +.B module_path +. +the module path to search for plugins + +.SS listeners + +This section contains listener-specific configuration information; see the +section about listeners below. + +.SS backends + +This section contains listener-specific configuration information; see the +section about listeners below. + +.SS groups + +This section contains static maps of which virtual machines +may fence which other virtual machines; see the section +about groups below. + + +.SH LISTENERS + +There are various listeners available for fence_virtd, each one handles +decoding and authentication of a given fencing request. The following +configuration blocks belong in the \fBlisteners\fP section of fence_virt.conf + +.SS multicast +.TP +.B key_file +. +the shared key file to use (default: /etc/cluster/fence_xvm.key). + +.TP +.B hash +. +the weakest hashing algorithm allowed for client requests. Clients may send packets with stronger hashes than the one specified, but not weaker ones. (default: sha256, but could +be sha1, sha512, or none) + +.TP +.B auth +. +the hashing algorithm to use for the simplistic challenge-response authentication +(default: sha256, but could be sha1, sha512, or none) + +.TP +.B family +. +the IP family to use (default: ipv4, but may be ipv6) + +.TP +.B address +. +the multicast address to listen on (default: 225.0.0.12) + +.TP +.B port +. +the multicast port to listen on (default: 1229) + +.TP +.B interface +. +interface to listen on. By default, fence_virtd listens on all interfaces. +However, this causes problems in some environments where the host computer +is used as a gateway. + +.SS serial + +The serial listener plugin utilizes libvirt's serial (or VMChannel) +mapping to listen for requests. When using the serial listener, it is +necessary to add a serial port (preferably pointing to /dev/ttyS1) or +a channel (preferably pointing to 10.0.2.179:1229) to the +libvirt domain description. Note that only type +.B unix +, mode +.B bind +serial ports and channels are supported and each VM should have a +separate unique socket. Example libvirt XML: + +.in 8 + <\fBserial\fP type='unix'> + <source mode='bind' path='/sandbox/guests/fence_socket_molly'/> + <target port='1'/> + </serial> + <\fBchannel\fP type='unix'> + <source mode='bind' path='/sandbox/guests/fence_molly_vmchannel'/> + <target type='guestfwd' address='10.0.2.179' port='1229'/> + </channel> +.in 0 + +.TP +.B uri +. +the URI to use when connecting to libvirt by the serial plugin (optional). + +.TP +.B path +. +The same directory that is defined for the domain serial port path (From example above: /sandbox/guests). Sockets must reside in this directory in order to be considered valid. This can be used to prevent fence_virtd from using the wrong sockets. + +.TP +.B mode +. +This selects the type of sockets to register. Valid values are "serial" +(default) and "vmchannel". + +.SS tcp +The tcp listener operates similarly to the multicast listener but uses TCP sockets for communication instead of using multicast packets. + +.TP +.B key_file +. +the shared key file to use (default: /etc/cluster/fence_xvm.key). + +.TP +.B hash +. +the hashing algorithm to use for packet signing (default: sha256, but could +be sha1, sha512, or none) + +.TP +.B auth +. +the hashing algorithm to use for the simplistic challenge-response authentication +(default: sha256, but could be sha1, sha512, or none) + +.TP +.B family +. +the IP family to use (default: ipv4, but may be ipv6) + +.TP +.B address +. +the IP address to listen on (default: 127.0.0.1 for IPv4, ::1 for IPv6) + +.TP +.B port +. +the TCP port to listen on (default: 1229) + +.SS vsock +The vsock listener operates similarly to the multicast listener but uses virtual machine sockets (AF_VSOCK) for communication instead of using multicast packets. + +.TP +.B key_file +. +the shared key file to use (default: /etc/cluster/fence_xvm.key). + +.TP +.B hash +. +the hashing algorithm to use for packet signing (default: sha256, but could +be sha1, sha512, or none) + +.TP +.B auth +. +the hashing algorithm to use for the simplistic challenge-response authentication +(default: sha256, but could be sha1, sha512, or none) + +.TP +.B port +. +the vsock port to listen on (default: 1229) + +.SH BACKENDS + +There are various backends available for fence_virtd, each one handles +routing a fencing request to a hypervisor or management tool. The following +configuration blocks belong in the \fBbackends\fP section of fence_virt.conf + +.SS libvirt + +The libvirt plugin is the simplest plugin. It is used in environments where +routing fencing requests between multiple hosts is not required, for example +by a user running a cluster of virtual machines on a single desktop computer. + +.TP +.B uri +. +the URI to use when connecting to libvirt. + +All libvirt URIs are accepted and passed as-is. + +See https://libvirt.org/uri.html#remote-uris for examples. + +NOTE: When VMs are run as non-root user the socket path must be set as part +of the URI. + +Example: qemu:///session?socket=/run/user/<UID>/libvirt/virtqemud-sock + +.SS cpg + +The cpg plugin uses corosync CPG and libvirt to track virtual +machines and route fencing requests to the appropriate computer. + +.TP +.B uri +. +the URI to use when connecting to libvirt by the cpg plugin. + +.TP +.B name_mode +. +The cpg plugin, in order to retain compatibility with fence_xvm, +stores virtual machines in a certain way. The +default was to use 'name' when using fence_xvm and fence_xvmd, and so this +is still the default. However, it is strongly recommended to use 'uuid' +instead of 'name' in all cluster environments involving more than one +physical host in order to avoid the potential for name collisions. + +.SH GROUPS + +Fence_virtd supports static maps which allow grouping of VMs. The +groups are arbitrary and are checked at fence time. Any member of +a group may fence any other member. Hosts may be assigned to multiple +groups if desired. + +.SS group + +This defines a group. + +.TP +.B name +. +Optionally define the name of the group. Useful only for configuration +readability and debugging of configuration parsing. + +.TP +.B uuid +. +Defines UUID as a member of a group. It can be used multiple times +to specify both node name and UUID values that can be fenced. +When using the serial listener, the vm uuid is required and it is +recommended to add also the vm name. + +.TP +.B ip +. +Defines an IP which is allowed to send fencing requests +for members of this group (e.g. for multicast). It can be used +multiple times to allow more than 1 IP to send fencing requests to +the group. It is highly recommended that this be used in conjunction +with a key file. +When using the vsock listener, ip should contain the CID value assigned +by libvirt to the vm. +When using the serial listener, ip value is not used and can be omitted. + + +.SH EXAMPLE + + fence_virtd { + listener = "multicast"; + backend = "cpg"; + } + + # this is the listeners section + + listeners { + multicast { + key_file = "/etc/cluster/fence_xvm.key"; + } + } + + backends { + libvirt { + uri = "qemu:///system"; + } + } + + groups { + group { + name = "cluster1"; + ip = "192.168.1.1"; + ip = "192.168.1.2"; + uuid = "44179d3f-6c63-474f-a212-20c8b4b25b16"; + uuid = "1ce02c4b-dfa1-42cb-b5b1-f0b1091ece60"; + uuid = "node1"; + uuid = "node2"; + } + } + +.SH SEE ALSO +fence_virtd(8), fence_virt(8), fence_xvm(8), fence(8) diff --git a/agents/virt/man/fence_virtd.8 b/agents/virt/man/fence_virtd.8 new file mode 100644 index 0000000..56f6938 --- /dev/null +++ b/agents/virt/man/fence_virtd.8 @@ -0,0 +1,53 @@ +.TH FENCE_AGENT 8 2010-01-05 "fence_virtd (Fence Agent)" +.SH NAME +fence_virtd - Fencing host for virtual machines + +.SH DESCRIPTION +.P +fence_virtd is a host daemon designed to route fencing requests for +virtual machines. + +Fence_virt and fence_xvm talk to fence_virtd, which supports multiple backend plugins, including: + - libvirt for single-node operation + - Corosync CPG and libvirt when using Linux-cluster release 3.0.0 or later + - libvirt-qpid for multi-node, non-cluster operation + +For compatibility, fence_xvm from linux-cluster release 2 may talk to fence_virtd. + +.P +fence_virtd accepts a few options on the command line, but most options +are read from fence_virt.conf. + +.SH PARAMETERS +.TP +.B -d +. +Specify debug level, e.g. "-d99" + +.TP +.B -c +. +Interactively prompt user for configuration information + +.TP +.B -f +. +Specify an alternate configuration file instead of /etc/fence_virt.conf + +.TP +.B -F +. +Do not fork into background after starting (overrides any setting in fence_virt.conf) + +.TP +.B -w +. +Wait for backend to be available (overrides any setting in fence_virt.conf) + +.TP +.B -p +. +Specify the full path to the pid file used to record the active process pid. + +.SH SEE ALSO +fence_virt(8), fence_xvm(8), fence(8), fence_virt.conf(5) diff --git a/agents/virt/man/fence_xvm.8 b/agents/virt/man/fence_xvm.8 new file mode 100644 index 0000000..5d0cfdd --- /dev/null +++ b/agents/virt/man/fence_xvm.8 @@ -0,0 +1 @@ +.so man8/fence_virt.8 diff --git a/agents/virt/server/Makefile.am b/agents/virt/server/Makefile.am new file mode 100644 index 0000000..fbca617 --- /dev/null +++ b/agents/virt/server/Makefile.am @@ -0,0 +1,79 @@ +############################################################################### +############################################################################### +## +## Copyright (C) 2009-2021 Red Hat, Inc. +## +## This copyrighted material is made available to anyone wishing to use, +## modify, copy, or redistribute it subject to the terms and conditions +## of the GNU General Public License v.2. +## +############################################################################### +############################################################################### + +MAINTAINERCLEANFILES = Makefile.in + +noinst_HEADERS = cpg.h serial.h uuid-test.h virt.h + +sbin_PROGRAMS = fence_virtd + +# +# daemon +# +fence_virtd_SOURCES = main.c plugin.c config.c static_map.c uuid-test.c \ + daemon_init.c + +fence_virtd_CFLAGS = $(VIRT_AM_CFLAGS) \ + $(nss_CFLAGS) $(xml2_CFLAGS) $(uuid_CFLAGS) $(PTHREAD_CFLAGS) \ + $(AM_CFLAGS) + +fence_virtd_LDADD = $(VIRT_CONFIG_LIBS) $(VIRT_COMMON_LIBS) \ + $(nss_LIBS) $(xml2_LIBS) $(uuid_LIBS) $(PTHREAD_LIBS) $(dl_LIBS) + +fence_virtd_LDFLAGS = $(VIRT_AM_LDFLAGS) $(VIRT_COMMON_LDFLAGS) + +virt_la_SOURCES = libvirt.c virt.c uuid-test.c +cpg_la_SOURCES = cpg-virt.c cpg.c virt.c uuid-test.c +multicast_la_SOURCES = mcast.c history.c +tcp_la_SOURCES = tcp.c history.c +vsock_la_SOURCES = vsock.c history.c +serial_la_SOURCES = virt-serial.c virt-sockets.c serial.c history.c + +fence_virtd_CFLAGS += -DMODULE_PATH=\"$(libdir)/fence-virt/\" + +fvlibdir = $(libdir)/fence-virt + +fvlib_LTLIBRARIES = + +MODULESCFLAGS = $(VIRT_AM_CFLAGS) $(AM_CFLAGS) +MODULESLDFLAGS = $(VIRT_AM_LDFLAGS) $(VIRT_COMMON_LIBS) $(VIRT_COMMON_LDFLAGS) -module -avoid-version -export-dynamic + +if modlibvirt +fvlib_LTLIBRARIES += virt.la +virt_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(virt_CFLAGS) +virt_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) $(virt_LIBS) +endif +if modcpg +fvlib_LTLIBRARIES += cpg.la +cpg_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(cpg_CFLAGS) $(virt_CFLAGS) +cpg_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) $(cpg_LIBS) $(virt_LIBS) +endif +if modmulticast +fvlib_LTLIBRARIES += multicast.la +multicast_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) +multicast_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) +endif +if modserial +fvlib_LTLIBRARIES += serial.la +serial_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(xml2_CFLAGS) $(virt_CFLAGS) +serial_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) $(xml2_LIBS) $(virt_LIBS) +endif +if modtcp +fvlib_LTLIBRARIES += tcp.la +tcp_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) +tcp_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) +endif +if modvsock +fvlib_LTLIBRARIES += vsock.la +vsock_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) +vsock_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) +endif diff --git a/agents/virt/server/config.c b/agents/virt/server/config.c new file mode 100644 index 0000000..fa9af97 --- /dev/null +++ b/agents/virt/server/config.c @@ -0,0 +1,698 @@ +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <errno.h> + +#include "simpleconfig.h" +#include "static_map.h" +#include "mcast.h" +#include "xvm.h" +#include "server_plugin.h" +#include "simple_auth.h" + + +static int +yesno(const char *prompt, int dfl) +{ + char result[10]; + + printf("%s [%c/%c]? ", prompt, dfl?'Y':'y', dfl?'n':'N'); + fflush(stdout); + + memset(result, 0, sizeof(result)); + if (fgets(result, 9, stdin) == NULL) + return dfl; + + if (result[0] == 'y' || result[0] == 'Y') + return 1; + if (result[0] == 'n' || result[0] == 'N') + return 0; + + return dfl; +} + + +static int +text_input(const char *prompt, const char *dfl, char *input, size_t len) +{ + const char *tmpdfl = dfl; + const char *nulldfl = ""; + + if (dfl == NULL) { + tmpdfl = nulldfl; + } + + printf("%s [%s]: ", prompt, tmpdfl); + fflush(stdout); + + memset(input, 0, len); + if (fgets(input, len, stdin) == NULL) { + strncpy(input, tmpdfl, len); + return 0; + } + if (input[strlen(input)-1] == '\n') + input[strlen(input)-1] = 0; + + if (strlen(input) == 0) { + strncpy(input, tmpdfl, len); + return 0; + } + + return 0; +} + + +static int +plugin_path_configure(config_object_t *config) +{ + char val[4096]; + char inp[4096]; + int done = 0; + + if (sc_get(config, "fence_virtd/@module_path", val, + sizeof(val))) { +#ifdef MODULE_PATH + snprintf(val, sizeof(val), MODULE_PATH); +#else + printf("Failed to determine module search path.\n"); +#endif + } + + do { + text_input("Module search path", val, inp, sizeof(inp)); + + printf("\n"); + done = plugin_search(inp); + if (done > 0) { + plugin_dump(); + done = 1; + } else { + done = 0; + printf("No modules found in %s!\n", inp); + if (yesno("Use this value anyway", 0) == 1) + done = 1; + } + } while (!done); + + sc_set(config, "fence_virtd/@module_path", inp); + + return 0; +} + + +static int +backend_config_libvirt(config_object_t *config) +{ + char val[4096]; + char inp[4096]; + + printf("\n"); + printf("The libvirt backend module is designed for single desktops or\n" + "servers. Do not use in environments where virtual machines\n" + "may be migrated between hosts.\n\n"); + + /* Default backend plugin */ + if (sc_get(config, "backends/libvirt/@uri", val, + sizeof(val))) { + strncpy(val, DEFAULT_HYPERVISOR_URI, sizeof(val)); + } + + text_input("Libvirt URI", val, inp, sizeof(inp)); + + sc_set(config, "backends/libvirt/@uri", inp); + + return 0; +} + + +static int +backend_config_cpg(config_object_t *config) +{ + char val[4096]; + char inp[4096]; + int done = 0; + + printf("\n"); + printf("The CPG backend module is designed for use in clusters\n" + "running corosync and libvirt. It utilizes the CPG API to \n" + "route fencing requests, finally utilizing libvirt to perform\n" + "fencing actions.\n\n"); + + if (sc_get(config, "backends/cpg/@uri", val, + sizeof(val))) { + strncpy(val, DEFAULT_HYPERVISOR_URI, sizeof(val)); + } + + text_input("Libvirt URI", val, inp, sizeof(inp)); + + sc_set(config, "backends/cpg/@uri", inp); + + printf("\n"); + printf("The name mode is how the cpg plugin stores and \n" + "references virtual machines. Since virtual machine names\n" + "are not guaranteed to be unique cluster-wide, use of UUIDs\n" + "is strongly recommended. However, for compatibility with \n" + "fence_xvmd, the use of 'name' mode is also supported.\n\n"); + + if (sc_get(config, "backends/cpg/@name_mode", val, + sizeof(val))) { + strncpy(val, "uuid", sizeof(val)); + } + + do { + text_input("VM naming/tracking mode (name or uuid)", + val, inp, sizeof(inp)); + if (!strcasecmp(inp, "uuid")) { + done = 1; + } else if (!strcasecmp(inp, "name")) { + done = 0; + printf("This can be dangerous if you do not take care to" + "ensure that\n" + "virtual machine names are unique " + "cluster-wide.\n"); + if (yesno("Use name mode anyway", 1) == 1) + done = 1; + } + } while (!done); + + sc_set(config, "backends/cpg/@name_mode", inp); + + return 0; +} + + +static int +listener_config_multicast(config_object_t *config) +{ + char val[4096]; + char inp[4096]; + const char *family = "ipv4"; + struct in_addr sin; + struct in6_addr sin6; + int done = 0; + + printf("\n"); + printf("The multicast listener module is designed for use environments\n" + "where the guests and hosts may communicate over a network using\n" + "multicast.\n\n"); + + + /* MULTICAST IP ADDRESS/FAMILY */ + printf("The multicast address is the address that a client will use to\n" + "send fencing requests to fence_virtd.\n\n"); + + if (sc_get(config, "listeners/multicast/@address", + val, sizeof(val)-1)) { + strncpy(val, IPV4_MCAST_DEFAULT, sizeof(val)); + } + + done = 0; + do { + text_input("Multicast IP Address", val, inp, sizeof(inp)); + + if (inet_pton(AF_INET, inp, &sin) == 1) { + printf("\nUsing ipv4 as family.\n\n"); + family = "ipv4"; + done = 1; + } else if (inet_pton(AF_INET6, inp, &sin6) == 1) { + printf("\nUsing ipv6 as family.\n\n"); + family = "ipv6"; + done = 1; + } else + printf("'%s' is not a valid IP address!\n", inp); + } while (!done); + + sc_set(config, "listeners/multicast/@family", family); + sc_set(config, "listeners/multicast/@address", inp); + + /* MULTICAST IP PORT */ + if (sc_get(config, "listeners/multicast/@port", + val, sizeof(val)-1)) { + snprintf(val, sizeof(val), "%d", DEFAULT_MCAST_PORT); + } + + done = 0; + do { + char *p; + int ret; + + text_input("Multicast IP Port", val, inp, sizeof(inp)); + ret = strtol(inp, &p, 0); + if (*p != '\0' || ret <= 0 || ret >= 65536) { + printf("Port value '%s' is out of range\n", val); + continue; + } else + done = 1; + } while (!done); + + sc_set(config, "listeners/multicast/@port", inp); + + /* MULTICAST INTERFACE */ + printf("\nSetting a preferred interface causes fence_virtd to listen only\n" + "on that interface. Normally, it listens on all interfaces.\n" + "In environments where the virtual machines are using the host\n" + "machine as a gateway, this *must* be set (typically to virbr0).\n" + "Set to 'none' for no interface.\n\n" + ); + + if (sc_get(config, "listeners/multicast/@interface", + val, sizeof(val)-1)) { + strncpy(val, "none", sizeof(val)); + } + + done = 0; + do { + text_input("Interface", val, inp, sizeof(inp)); + + if (!strcasecmp(inp, "none")) { + break; + } + + if (strlen(inp) > 0) { + int ret; + + ret = if_nametoindex(inp); + if (ret < 0) { + printf("Invalid interface: %s\n", inp); + if (yesno("Use anyway", 1) == 1) + done = 1; + } else + done = 1; + } else + printf("No interface given\n"); + } while (!done); + + if (!strcasecmp(inp, "none")) { + sc_set(config, "listeners/multicast/@interface", NULL); + } else { + sc_set(config, "listeners/multicast/@interface", inp); + } + + + /* KEY FILE */ + printf("\nThe key file is the shared key information which is used to\n" + "authenticate fencing requests. The contents of this file must\n" + "be distributed to each physical host and virtual machine within\n" + "a cluster.\n\n"); + + if (sc_get(config, "listeners/multicast/@key_file", + val, sizeof(val)-1)) { + strncpy(val, DEFAULT_KEY_FILE, sizeof(val)); + } + + done = 0; + do { + text_input("Key File", val, inp, sizeof(inp)); + + if (!strcasecmp(inp, "none")) { + break; + } + + if (strlen(inp) > 0) { + if (inp[0] != '/') { + printf("Invalid key file: %s\n", inp); + if (yesno("Use anyway", 1) == 1) + done = 1; + } else + done = 1; + } else + printf("No key file given\n"); + } while (!done); + + if (!strcasecmp(inp, "none")) { + sc_set(config, "listeners/multicast/@key_file", NULL); + } else { + sc_set(config, "listeners/multicast/@key_file", inp); + } + + return 0; +} + +static int +listener_config_tcp(config_object_t *config) +{ + char val[4096]; + char inp[4096]; + const char *family = "ipv4"; + struct in_addr sin; + struct in6_addr sin6; + int done = 0; + + printf("\n"); + printf("The TCP listener module is designed for use in environments\n" + "where the guests and hosts communicate over viosproxy.\n\n"); + + /* IP ADDRESS/FAMILY */ + printf("The IP address is the address that a client will use to\n" + "send fencing requests to fence_virtd.\n\n"); + + if (sc_get(config, "listeners/tcp/@address", + val, sizeof(val)-1)) { + strncpy(val, IPV4_MCAST_DEFAULT, sizeof(val)); + } + + done = 0; + do { + text_input("TCP Listen IP Address", val, inp, sizeof(inp)); + + if (inet_pton(AF_INET, inp, &sin) == 1) { + printf("\nUsing ipv4 as family.\n\n"); + family = "ipv4"; + done = 1; + } else if (inet_pton(AF_INET6, inp, &sin6) == 1) { + printf("\nUsing ipv6 as family.\n\n"); + family = "ipv6"; + done = 1; + } else { + printf("'%s' is not a valid IP address!\n", inp); + continue; + } + } while (!done); + + sc_set(config, "listeners/tcp/@family", family); + sc_set(config, "listeners/tcp/@address", inp); + + /* MULTICAST IP PORT */ + if (sc_get(config, "listeners/tcp/@port", + val, sizeof(val)-1)) { + snprintf(val, sizeof(val), "%d", DEFAULT_MCAST_PORT); + } + + done = 0; + do { + char *p; + int ret; + + text_input("TCP Listen Port", val, inp, sizeof(inp)); + + ret = strtol(inp, &p, 0); + if (*p != '\0' || ret <= 0 || ret >= 65536) { + printf("Port value '%s' is out of range\n", val); + continue; + } + done = 1; + } while (!done); + sc_set(config, "listeners/tcp/@port", inp); + + /* KEY FILE */ + printf("\nThe key file is the shared key information which is used to\n" + "authenticate fencing requests. The contents of this file must\n" + "be distributed to each physical host and virtual machine within\n" + "a cluster.\n\n"); + + if (sc_get(config, "listeners/tcp/@key_file", + val, sizeof(val)-1)) { + strncpy(val, DEFAULT_KEY_FILE, sizeof(val)); + } + + done = 0; + do { + text_input("Key File", val, inp, sizeof(inp)); + + if (!strcasecmp(inp, "none")) { + break; + } + + if (strlen(inp) > 0) { + if (inp[0] != '/') { + printf("Invalid key file: %s\n", inp); + if (yesno("Use anyway", 1) == 1) + done = 1; + } else + done = 1; + } else + printf("No key file given\n"); + } while (!done); + + if (!strcasecmp(inp, "none")) { + sc_set(config, "listeners/tcp/@key_file", NULL); + } else { + sc_set(config, "listeners/tcp/@key_file", inp); + } + + return 0; +} + +static int +listener_config_serial(config_object_t *config) +{ + char val[4096]; + char inp[4096]; + int done; + + printf("\n"); + printf("The serial plugin allows fence_virtd to communicate with\n" + "guests using serial or guest-forwarding VMChannel instead\n" + "of using TCP/IP networking.\n\n"); + printf("Special configuration of virtual machines is required. See\n" + "fence_virt.conf(5) for more details.\n\n"); + + if (sc_get(config, "listeners/serial/@uri", + val, sizeof(val)-1)) { + strncpy(val, DEFAULT_HYPERVISOR_URI, sizeof(val)); + } + + text_input("Libvirt URI", val, inp, sizeof(inp)); + + printf("\nSetting a socket path prevents fence_virtd from taking\n" + "hold of all Unix domain sockets created when the guest\n" + "is started. A value like /var/run/cluster/fence might\n" + "be a good value. Don't forget to create the directory!\n\n"); + + if (sc_get(config, "listeners/serial/@path", + val, sizeof(val)-1)) { + strncpy(val, "none", sizeof(val)); + } + + text_input("Socket directory", val, inp, sizeof(inp)); + if (!strcasecmp(inp, "none")) { + sc_set(config, "listeners/serial/@path", NULL); + } else { + sc_set(config, "listeners/serial/@path", inp); + } + + printf("\nThe serial plugin allows two types of guest to host\n" + "configurations. One is via a serial port; the other is\n" + "utilizing the newer VMChannel.\n\n"); + + if (sc_get(config, "listeners/serial/@mode", + val, sizeof(val)-1)) { + strncpy(val, "serial", sizeof(val)); + } + + if (!strcasecmp(inp, "none")) { + sc_set(config, "listeners/serial/@path", NULL); + } else { + sc_set(config, "listeners/serial/@path", inp); + } + + done = 0; + do { + text_input("Mode (serial or vmchannel)", val, inp, + sizeof(inp)); + + if (strcasecmp(inp, "serial") && strcasecmp(inp, "vmchannel")) { + printf("Invalid mode: %s\n", inp); + if (yesno("Use anyway", 1) == 1) + done = 1; + } else + done = 1; + } while (!done); + + sc_set(config, "listeners/serial/@mode", inp); + return 0; +} + + +static int +backend_configure(config_object_t *config) +{ + char val[4096]; + char inp[4096]; + int done; + + printf("\n"); + printf("Backend modules are responsible for routing requests to\n" + "the appropriate hypervisor or management layer.\n\n"); + + /* Default backend plugin */ + if (sc_get(config, "fence_virtd/@backend", val, + sizeof(val))) { + strncpy(val, "libvirt", sizeof(val)); + } + + done = 0; + do { + text_input("Backend module", val, inp, sizeof(inp)); + if (plugin_find_backend(inp) == NULL) { + printf("No backend module named %s found!\n", inp); + if (yesno("Use this value anyway", 0) == 1) + done = 1; + } else + done = 1; + } while (!done); + + sc_set(config, "fence_virtd/@backend", inp); + + if (!strcmp(inp, "libvirt")) { + backend_config_libvirt(config); + } else if (!strcmp(inp, "cpg")) { + backend_config_cpg(config); + } + + return 0; +} + + +static int +listener_configure(config_object_t *config) +{ + char val[4096]; + char inp[4096]; + int done; + + printf("\n"); + printf("Listener modules are responsible for accepting requests\n" + "from fencing clients.\n\n"); + + /* Default backend plugin */ + if (sc_get(config, "fence_virtd/@listener", val, + sizeof(val))) { + strncpy(val, "multicast", sizeof(val)); + } + + done = 0; + do { + text_input("Listener module", val, inp, sizeof(inp)); + if (plugin_find_listener(inp) == NULL) { + printf("No listener module named %s found!\n", inp); + if (yesno("Use this value anyway", 0) == 1) + done = 1; + } else + done = 1; + } while (!done); + + sc_set(config, "fence_virtd/@listener", inp); + if (!strcmp(inp, "multicast")) + listener_config_multicast(config); + else if (!strcmp(inp, "tcp")) + listener_config_tcp(config); + else if (!strcmp(inp, "serial")) + listener_config_serial(config); + else + printf("Unable to configure unknown listner module '%s'\n", inp); + + return 0; +} + + +int +check_file_permissions(const char *fname) +{ + struct stat st; + mode_t file_perms = 0600; + int ret; + + ret = stat(fname, &st); + if (ret != 0) { + printf("stat failed on file '%s': %s\n", + fname, strerror(errno)); + return 1; + } + + if ((st.st_mode & 0777) != file_perms) { + printf("Insecure permissions on file " + "'%s': changing from 0%o to 0%o.\n", fname, + (unsigned int)(st.st_mode & 0777), + (unsigned int)file_perms); + if (chmod(fname, file_perms) != 0) { + printf("Unable to change permissions for file '%s'", + fname); + return 1; + } + } + + return 0; +} + +int +do_configure(config_object_t *config, const char *config_file) +{ + FILE *fp = NULL; + char message[80]; + char tmp_filename[4096]; + int tmp_fd = -1; + mode_t old_umask; + + if (sc_parse(config, config_file) != 0) { + printf("Parsing of %s failed.\n", config_file); + if (yesno("Start from scratch", 0) == 0) { + return 1; + } + } + + plugin_path_configure(config); + listener_configure(config); + backend_configure(config); + + printf("\nConfiguration complete.\n\n"); + + printf("=== Begin Configuration ===\n"); + sc_dump(config, stdout); + printf("=== End Configuration ===\n"); + + snprintf(message, sizeof(message), "Replace %s with the above", + config_file); + if (yesno(message, 0) == 0) { + return 1; + } + + snprintf(tmp_filename, sizeof(tmp_filename), + "%s.XXXXXX", config_file); + + old_umask = umask(077); + tmp_fd = mkstemp(tmp_filename); + umask(old_umask); + + if (tmp_fd < 0) { + perror("fopen"); + printf("Failed to write configuration file!\n"); + return 1; + } + + fp = fdopen(tmp_fd, "w+"); + if (fp == NULL) + goto out_fail; + + sc_dump(config, fp); + + if (rename(tmp_filename, config_file) < 0) { + perror("rename"); + goto out_fail; + } + + fclose(fp); + close(tmp_fd); + + return 0; + +out_fail: + if (fp) + fclose(fp); + if (tmp_fd >= 0) + close(tmp_fd); + if (strlen(tmp_filename)) + unlink(tmp_filename); + printf("Failed to write configuration file!\n"); + return 1; +} diff --git a/agents/virt/server/cpg-virt.c b/agents/virt/server/cpg-virt.c new file mode 100644 index 0000000..304519c --- /dev/null +++ b/agents/virt/server/cpg-virt.c @@ -0,0 +1,643 @@ +/* + Copyright Red Hat, Inc. 2017 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +/* + * Author: Ryan McCabe <rmccabe@redhat.com> + */ +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <stdint.h> +#include <time.h> +#include <string.h> +#include <syslog.h> +#include <errno.h> +#include <unistd.h> +#include <pthread.h> +#include <corosync/cpg.h> + +#include "debug.h" +#include "virt.h" +#include "xvm.h" +#include "cpg.h" +#include "simpleconfig.h" +#include "static_map.h" +#include "server_plugin.h" + +#define NAME "cpg" +#define CPG_VERSION "0.1" + +#define MAGIC 0x38e93fc2 + +struct cpg_info { + int magic; + config_object_t *config; + int vp_count; + virConnectPtr *vp; +}; + +#define VALIDATE(arg) \ +do {\ + if (!arg || ((struct cpg_info *) arg)->magic != MAGIC) { \ + errno = EINVAL;\ + return -1; \ + } \ +} while(0) + +static struct cpg_info *cpg_virt_handle = NULL; +static int use_uuid = 0; +pthread_mutex_t local_vm_list_lock = PTHREAD_MUTEX_INITIALIZER; +static virt_list_t *local_vm_list = NULL; + +pthread_mutex_t remote_vm_list_lock = PTHREAD_MUTEX_INITIALIZER; +static virt_list_t *remote_vm_list = NULL; + +static void cpg_virt_init_libvirt(struct cpg_info *info); + +static int +virt_list_update(struct cpg_info *info, virt_list_t **vl, int my_id) +{ + virt_list_t *list = NULL; + + if (*vl) + vl_free(*vl); + + list = vl_get(info->vp, info->vp_count, my_id); + if (!list && (errno == EPIPE || errno == EINVAL)) { + do { + cpg_virt_init_libvirt(info); + } while (info->vp_count == 0); + list = vl_get(info->vp, info->vp_count, my_id); + } + + *vl = list; + if (!list) + return -1; + + return 0; +} + + +static void +store_domains(virt_list_t *vl) +{ + int i; + + if (!vl) + return; + + for (i = 0 ; i < vl->vm_count ; i++) { + int ret; + + if (!strcmp(DOMAIN0NAME, vl->vm_states[i].v_name)) + continue; + + ret = cpg_send_vm_state(&vl->vm_states[i]); + if (ret < 0) { + printf("Error storing VM state for %s|%s\n", + vl->vm_states[i].v_name, vl->vm_states[i].v_uuid); + } + } +} + + +static void +update_local_vms(struct cpg_info *info) +{ + uint32_t my_id = 0; + + if (!info) + return; + + cpg_get_ids(&my_id, NULL); + virt_list_update(info, &local_vm_list, my_id); + store_domains(local_vm_list); +} + + +static int +do_off(struct cpg_info *info, const char *vm_name) +{ + dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name); + return vm_off(info->vp, info->vp_count, vm_name); + +} + +static int +do_on(struct cpg_info *info, const char *vm_name) +{ + dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name); + return vm_on(info->vp, info->vp_count, vm_name); + +} + +static int +do_reboot(struct cpg_info *info, const char *vm_name) +{ + dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name); + return vm_reboot(info->vp, info->vp_count, vm_name); +} + +static void +cpg_join_cb(const struct cpg_address *join, size_t joinlen) { + struct cpg_info *info = cpg_virt_handle; + + pthread_mutex_lock(&local_vm_list_lock); + update_local_vms(info); + pthread_mutex_unlock(&local_vm_list_lock); +} + +static void +cpg_leave_cb(const struct cpg_address *left, size_t leftlen) { + struct cpg_info *info = cpg_virt_handle; + int i; + + pthread_mutex_lock(&remote_vm_list_lock); + for (i = 0 ; i < leftlen ; i++) { + dbg_printf(2, "Removing VMs owned by nodeid %u\n", left[i].nodeid); + vl_remove_by_owner(&remote_vm_list, left[i].nodeid); + } + pthread_mutex_unlock(&remote_vm_list_lock); + + pthread_mutex_lock(&local_vm_list_lock); + update_local_vms(info); + pthread_mutex_unlock(&local_vm_list_lock); +} + +static void +store_cb(void *data, size_t len, uint32_t nodeid, uint32_t seqno) +{ + uint32_t my_id; + virt_state_t *vs = (virt_state_t *) data; + struct cpg_info *info = cpg_virt_handle; + + cpg_get_ids(&my_id, NULL); + + if (nodeid == my_id) + return; + + pthread_mutex_lock(&local_vm_list_lock); + if (!local_vm_list) + update_local_vms(info); + pthread_mutex_unlock(&local_vm_list_lock); + + pthread_mutex_lock(&remote_vm_list_lock); + vl_update(&remote_vm_list, vs); + pthread_mutex_unlock(&remote_vm_list_lock); +} + +/* +** This function must a send reply from at least one node, otherwise +** the requesting fence_virtd will block forever in wait_cpt_reply. +*/ +static void +do_real_work(void *data, size_t len, uint32_t nodeid, uint32_t seqno) +{ + struct cpg_info *info = cpg_virt_handle; + struct cpg_fence_req *req = data; + struct cpg_fence_req reply; + int reply_code = -1; + virt_state_t *vs = NULL; + int cur_state; + uint32_t cur_owner = 0; + int local = 0; + uint32_t my_id, high_id; + + dbg_printf(2, "Request %d for VM %s\n", req->request, req->vm_name); + + if (cpg_get_ids(&my_id, &high_id) == -1) { + syslog(LOG_WARNING, "Unable to get CPG IDs"); + printf("Should never happen: Can't get CPG node ids - can't proceed\n"); + return; + } + + memcpy(&reply, req, sizeof(reply)); + + pthread_mutex_lock(&local_vm_list_lock); + update_local_vms(info); + if (strlen(req->vm_name)) { + if (use_uuid) + vs = vl_find_uuid(local_vm_list, req->vm_name); + else + vs = vl_find_name(local_vm_list, req->vm_name); + + if (vs) { + local = 1; + cur_owner = vs->v_state.s_owner; + cur_state = vs->v_state.s_state; + dbg_printf(2, "Found VM %s locally state %d\n", + req->vm_name, cur_state); + } + } + pthread_mutex_unlock(&local_vm_list_lock); + + if (vs == NULL) { + pthread_mutex_lock(&remote_vm_list_lock); + if (strlen(req->vm_name)) { + if (use_uuid) + vs = vl_find_uuid(remote_vm_list, req->vm_name); + else + vs = vl_find_name(remote_vm_list, req->vm_name); + + if (vs) { + cur_owner = vs->v_state.s_owner; + cur_state = vs->v_state.s_state; + dbg_printf(2, "Found VM %s remotely on %u state %d\n", + req->vm_name, cur_owner, cur_state); + } + } + pthread_mutex_unlock(&remote_vm_list_lock); + } + + if (!vs) { + /* + ** We know about all domains on all nodes in the CPG group. + ** If we didn't find it, and we're high ID, act on the request. + ** We can safely assume the VM is OFF because it wasn't found + ** on any current members of the CPG group. + */ + if (my_id == high_id) { + if (req->request == FENCE_STATUS) + reply_code = RESP_OFF; + else if (req->request == FENCE_OFF || req->request == FENCE_REBOOT) + reply_code = RESP_SUCCESS; + else + reply_code = 1; + + dbg_printf(2, "Acting on request %d for unknown domain %s -> %d\n", + req->request, req->vm_name, reply_code); + goto out; + } + + dbg_printf(2, "Not acting on request %d for unknown domain %s\n", + req->request, req->vm_name); + return; + } + + if (local) { + if (req->request == FENCE_STATUS) { + /* We already have the status */ + if (cur_state == VIR_DOMAIN_SHUTOFF) + reply_code = RESP_OFF; + else + reply_code = RESP_SUCCESS; + } else if (req->request == FENCE_OFF) { + reply_code = do_off(info, req->vm_name); + } else if (req->request == FENCE_ON) { + reply_code = do_on(info, req->vm_name); + } else if (req->request == FENCE_REBOOT) { + reply_code = do_reboot(info, req->vm_name); + } else { + dbg_printf(2, "Not explicitly handling request type %d for %s\n", + req->request, req->vm_name); + reply_code = 0; + } + goto out; + } + + /* + ** This is a request for a non-local domain that exists on a + ** current CPG group member, so that member will see the request + ** and act on it. We don't need to do anything. + */ + dbg_printf(2, "Nothing to do for non-local domain %s seq %d owner %u\n", + req->vm_name, seqno, cur_owner); + return; + +out: + dbg_printf(2, "[%s] sending reply code seq %d -> %d\n", + req->vm_name, seqno, reply_code); + + reply.response = reply_code; + if (cpg_send_reply(&reply, sizeof(reply), nodeid, seqno) < 0) { + dbg_printf(2, "cpg_send_reply failed for %s [%d %d]: %s\n", + req->vm_name, nodeid, seqno, strerror(errno)); + } +} + + +static int +do_request(const char *vm_name, int request, uint32_t seqno) +{ + struct cpg_fence_req freq, *frp; + size_t retlen; + uint32_t seq; + int ret; + + memset(&freq, 0, sizeof(freq)); + if (!vm_name) { + dbg_printf(1, "No VM name\n"); + return 1; + } + + if (strlen(vm_name) >= sizeof(freq.vm_name)) { + dbg_printf(1, "VM name %s too long\n", vm_name); + return 1; + } + + strcpy(freq.vm_name, vm_name); + + freq.request = request; + freq.seqno = seqno; + + if (cpg_send_req(&freq, sizeof(freq), &seq) != 0) { + dbg_printf(1, "Failed to send request %d for VM %s\n", + freq.request, vm_name); + return 1; + } + + dbg_printf(2, "Sent request %d for VM %s got seqno %d\n", + request, vm_name, seq); + + if (cpg_wait_reply((void *) &frp, &retlen, seq) != 0) { + dbg_printf(1, "Failed to receive reply seq %d for %s\n", seq, vm_name); + return 1; + } + + dbg_printf(2, "Received reply [%d] seq %d for %s\n", + frp->response, seq, vm_name); + + ret = frp->response; + free(frp); + + return ret; +} + + +static int +cpg_virt_null(const char *vm_name, void *priv) +{ + VALIDATE(priv); + printf("[cpg-virt] Null operation on %s\n", vm_name); + + return 1; +} + + +static int +cpg_virt_off(const char *vm_name, const char *src, uint32_t seqno, void *priv) +{ + VALIDATE(priv); + printf("[cpg-virt] OFF operation on %s seq %d\n", vm_name, seqno); + + return do_request(vm_name, FENCE_OFF, seqno); +} + + +static int +cpg_virt_on(const char *vm_name, const char *src, uint32_t seqno, void *priv) +{ + VALIDATE(priv); + printf("[cpg-virt] ON operation on %s seq %d\n", vm_name, seqno); + + return do_request(vm_name, FENCE_ON, seqno); +} + + +static int +cpg_virt_devstatus(void *priv) +{ + printf("[cpg-virt] Device status\n"); + VALIDATE(priv); + + return 0; +} + + +static int +cpg_virt_status(const char *vm_name, void *priv) +{ + VALIDATE(priv); + printf("[cpg-virt] STATUS operation on %s\n", vm_name); + + return do_request(vm_name, FENCE_STATUS, 0); +} + + +static int +cpg_virt_reboot(const char *vm_name, const char *src, + uint32_t seqno, void *priv) +{ + VALIDATE(priv); + printf("[cpg-virt] REBOOT operation on %s seq %d\n", vm_name, seqno); + + return do_request(vm_name, FENCE_REBOOT, 0); +} + + +static int +cpg_virt_hostlist(hostlist_callback callback, void *arg, void *priv) +{ + struct cpg_info *info = (struct cpg_info *) priv; + int i; + + VALIDATE(priv); + printf("[cpg-virt] HOSTLIST operation\n"); + + pthread_mutex_lock(&local_vm_list_lock); + update_local_vms(info); + for (i = 0 ; i < local_vm_list->vm_count ; i++) { + callback(local_vm_list->vm_states[i].v_name, + local_vm_list->vm_states[i].v_uuid, + local_vm_list->vm_states[i].v_state.s_state, arg); + } + pthread_mutex_unlock(&local_vm_list_lock); + + return 1; +} + +static void +cpg_virt_init_libvirt(struct cpg_info *info) { + config_object_t *config = info->config; + int i = 0; + + if (info->vp) { + dbg_printf(2, "Lost libvirtd connection. Reinitializing.\n"); + for (i = 0 ; i < info->vp_count ; i++) + virConnectClose(info->vp[i]); + free(info->vp); + info->vp = NULL; + } + info->vp_count = 0; + + do { + virConnectPtr vp; + virConnectPtr *vpl = NULL; + char conf_attr[256]; + char value[1024]; + char *uri; + + if (i != 0) { + snprintf(conf_attr, sizeof(conf_attr), + "backends/cpg/@uri%d", i); + } else + snprintf(conf_attr, sizeof(conf_attr), "backends/cpg/@uri"); + ++i; + + if (sc_get(config, conf_attr, value, sizeof(value)) != 0) + break; + + uri = value; + vp = virConnectOpen(uri); + if (!vp) { + dbg_printf(1, "[cpg-virt:INIT] Failed to connect to URI: %s\n", uri); + continue; + } + + vpl = realloc(info->vp, sizeof(*info->vp) * (info->vp_count + 1)); + if (!vpl) { + dbg_printf(1, "[cpg-virt:INIT] Out of memory allocating URI: %s\n", + uri); + virConnectClose(vp); + continue; + } + + info->vp = vpl; + info->vp[info->vp_count++] = vp; + + if (i > 1) + dbg_printf(1, "[cpg-virt:INIT] Added URI%d %s\n", i - 1, uri); + else + dbg_printf(1, "[cpg_virt:INIT] Added URI %s\n", uri); + } while (1); +} + +static int +cpg_virt_init(backend_context_t *c, config_object_t *config) +{ + char value[1024]; + struct cpg_info *info = NULL; + int ret; + + ret = cpg_start(PACKAGE_NAME, + do_real_work, store_cb, cpg_join_cb, cpg_leave_cb); + if (ret < 0) + return -1; + + info = calloc(1, sizeof(*info)); + if (!info) + return -1; + info->magic = MAGIC; + info->config = config; + + if (sc_get(config, "fence_virtd/@debug", value, sizeof(value)) == 0) + dset(atoi(value)); + + cpg_virt_init_libvirt(info); + + /* Naming scheme is no longer a top-level config option. + * However, we retain it here for configuration compatibility with + * versions 0.1.3 and previous. + */ + if (sc_get(config, "fence_virtd/@name_mode", + value, sizeof(value)-1) == 0) { + + dbg_printf(1, "Got %s for name_mode\n", value); + if (!strcasecmp(value, "uuid")) { + use_uuid = 1; + } else if (!strcasecmp(value, "name")) { + use_uuid = 0; + } else { + dbg_printf(1, "Unsupported name_mode: %s\n", value); + } + } + + if (sc_get(config, "backends/cpg/@name_mode", + value, sizeof(value)-1) == 0) + { + dbg_printf(1, "Got %s for name_mode\n", value); + if (!strcasecmp(value, "uuid")) { + use_uuid = 1; + } else if (!strcasecmp(value, "name")) { + use_uuid = 0; + } else { + dbg_printf(1, "Unsupported name_mode: %s\n", value); + } + } + + if (info->vp_count < 1) { + dbg_printf(1, "[cpg_virt:INIT] Could not connect to any hypervisors\n"); + cpg_stop(); + free(info); + return -1; + } + + pthread_mutex_lock(&local_vm_list_lock); + update_local_vms(info); + pthread_mutex_unlock(&local_vm_list_lock); + + *c = (void *) info; + cpg_virt_handle = info; + return 0; +} + + +static int +cpg_virt_shutdown(backend_context_t c) +{ + struct cpg_info *info = (struct cpg_info *)c; + int i = 0; + int ret = 0; + + VALIDATE(info); + info->magic = 0; + + cpg_stop(); + + for (i = 0 ; i < info->vp_count ; i++) { + if (virConnectClose(info->vp[i]) < 0) + ret = -errno; + } + + free(info->vp); + free(info); + + return ret; +} + + +static fence_callbacks_t cpg_callbacks = { + .null = cpg_virt_null, + .off = cpg_virt_off, + .on = cpg_virt_on, + .reboot = cpg_virt_reboot, + .status = cpg_virt_status, + .devstatus = cpg_virt_devstatus, + .hostlist = cpg_virt_hostlist +}; + +static backend_plugin_t cpg_virt_plugin = { + .name = NAME, + .version = CPG_VERSION, + .callbacks = &cpg_callbacks, + .init = cpg_virt_init, + .cleanup = cpg_virt_shutdown, +}; + +double +BACKEND_VER_SYM(void) +{ + return PLUGIN_VERSION_BACKEND; +} + +const backend_plugin_t * +BACKEND_INFO_SYM(void) +{ + return &cpg_virt_plugin; +} diff --git a/agents/virt/server/cpg.c b/agents/virt/server/cpg.c new file mode 100644 index 0000000..8f84cd8 --- /dev/null +++ b/agents/virt/server/cpg.c @@ -0,0 +1,411 @@ +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <stdint.h> +#include <malloc.h> +#include <signal.h> +#include <unistd.h> +#include <sys/select.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <sys/uio.h> +#include <list.h> +#include <pthread.h> + +#include <corosync/cpg.h> + +#include "debug.h" +#include "virt.h" +#include "cpg.h" + +#define NODE_ID_NONE ((uint32_t) -1) + +struct msg_queue_node { + list_head(); + uint32_t seqno; +#define STATE_CLEAR 0 +#define STATE_MESSAGE 1 + uint32_t state; + void *msg; + size_t msglen; +}; + +struct wire_msg { +#define TYPE_REQUEST 0 +#define TYPE_REPLY 1 +#define TYPE_STORE_VM 2 + uint32_t type; + uint32_t seqno; + uint32_t target; + uint32_t pad; + char data[0]; +}; + +static uint32_t seqnum = 0; +static struct msg_queue_node *pending = NULL; +static cpg_handle_t cpg_handle; +static struct cpg_name gname; + +static pthread_mutex_t cpg_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cpg_cond = PTHREAD_COND_INITIALIZER; +static pthread_t cpg_thread = 0; + +static pthread_mutex_t cpg_ids_mutex = PTHREAD_MUTEX_INITIALIZER; +static uint32_t my_node_id = NODE_ID_NONE; +static uint32_t high_id_from_callback = NODE_ID_NONE; + +static request_callback_fn req_callback_fn; +static request_callback_fn store_callback_fn; +static confchange_callback_fn conf_leave_fn; +static confchange_callback_fn conf_join_fn; + + +int +cpg_get_ids(uint32_t *my_id, uint32_t *high_id) +{ + if (!my_id && !high_id) + return -1; + + pthread_mutex_lock(&cpg_ids_mutex); + if (my_id) + *my_id = my_node_id; + + if (high_id) + *high_id = high_id_from_callback; + pthread_mutex_unlock(&cpg_ids_mutex); + + return 0; +} + +static void +cpg_deliver_func(cpg_handle_t h, + const struct cpg_name *group_name, + uint32_t nodeid, + uint32_t pid, + void *msg, + size_t msglen) +{ + struct msg_queue_node *n; + struct wire_msg *m = msg; + int x, found; + + pthread_mutex_lock(&cpg_mutex); + if (m->type == TYPE_REPLY) { + /* Reply to a request we sent */ + found = 0; + + list_for(&pending, n, x) { + if (m->seqno != n->seqno) + continue; + if (m->target != my_node_id) + continue; + found = 1; + break; + } + + if (!found) + goto out_unlock; + + /* Copy our message in to a buffer */ + n->msglen = msglen - sizeof(*m); + if (!n->msglen) { + /* XXX do what? */ + } + n->msg = malloc(n->msglen); + if (!n->msg) { + goto out_unlock; + } + n->state = STATE_MESSAGE; + memcpy(n->msg, (char *)msg + sizeof(*m), n->msglen); + + list_remove(&pending, n); + list_insert(&pending, n); + + dbg_printf(2, "Seqnum %d replied; removing from list\n", n->seqno); + + pthread_cond_broadcast(&cpg_cond); + goto out_unlock; + } + pthread_mutex_unlock(&cpg_mutex); + + if (m->type == TYPE_REQUEST) { + req_callback_fn(&m->data, msglen - sizeof(*m), + nodeid, m->seqno); + } + if (m->type == TYPE_STORE_VM) { + store_callback_fn(&m->data, msglen - sizeof(*m), + nodeid, m->seqno); + } + + return; + +out_unlock: + pthread_mutex_unlock(&cpg_mutex); +} + + +static void +cpg_config_change(cpg_handle_t h, + const struct cpg_name *group_name, + const struct cpg_address *members, size_t memberlen, + const struct cpg_address *left, size_t leftlen, + const struct cpg_address *join, size_t joinlen) +{ + int x; + int high; + + pthread_mutex_lock(&cpg_ids_mutex); + high = my_node_id; + + for (x = 0; x < memberlen; x++) { + if (members[x].nodeid > high) + high = members[x].nodeid; + } + + high_id_from_callback = high; + pthread_mutex_unlock(&cpg_ids_mutex); + + if (joinlen > 0) + conf_join_fn(join, joinlen); + + if (leftlen > 0) + conf_leave_fn(left, leftlen); +} + + +static cpg_callbacks_t my_callbacks = { + .cpg_deliver_fn = cpg_deliver_func, + .cpg_confchg_fn = cpg_config_change +}; + + +int +cpg_send_req(void *data, size_t len, uint32_t *seqno) +{ + struct iovec iov; + struct msg_queue_node *n; + struct wire_msg *m; + size_t msgsz = sizeof(*m) + len; + int ret; + + n = malloc(sizeof(*n)); + if (!n) + return -1; + + m = malloc(msgsz); + if (!m) { + free(n); + return -1; + } + + /* only incremented on send */ + n->state = STATE_CLEAR; + n->msg = NULL; + n->msglen = 0; + + pthread_mutex_lock(&cpg_mutex); + list_insert(&pending, n); + n->seqno = ++seqnum; + m->seqno = seqnum; + *seqno = seqnum; + pthread_mutex_unlock(&cpg_mutex); + + m->type = TYPE_REQUEST; /* XXX swab? */ + m->target = NODE_ID_NONE; + memcpy(&m->data, data, len); + + iov.iov_base = m; + iov.iov_len = msgsz; + ret = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, &iov, 1); + + free(m); + if (ret == CS_OK) + return 0; + return -1; +} + + +int +cpg_send_vm_state(virt_state_t *vs) +{ + struct iovec iov; + struct msg_queue_node *n; + struct wire_msg *m; + size_t msgsz = sizeof(*m) + sizeof(*vs); + int ret; + + n = calloc(1, (sizeof(*n))); + if (!n) + return -1; + + m = calloc(1, msgsz); + if (!m) { + free(n); + return -1; + } + + n->state = STATE_MESSAGE; + n->msg = NULL; + n->msglen = 0; + + pthread_mutex_lock(&cpg_mutex); + list_insert(&pending, n); + pthread_mutex_unlock(&cpg_mutex); + + m->type = TYPE_STORE_VM; + m->target = NODE_ID_NONE; + + memcpy(&m->data, vs, sizeof(*vs)); + + iov.iov_base = m; + iov.iov_len = msgsz; + ret = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, &iov, 1); + + free(m); + if (ret == CS_OK) + return 0; + + return -1; +} + + +int +cpg_send_reply(void *data, size_t len, uint32_t nodeid, uint32_t seqno) +{ + struct iovec iov; + struct wire_msg *m; + size_t msgsz = sizeof(*m) + len; + int ret; + + m = malloc(msgsz); + if (!m) + return -1; + + /* only incremented on send */ + m->seqno = seqno; + m->type = TYPE_REPLY; /* XXX swab? */ + m->target = nodeid; + memcpy(&m->data, data, len); + + iov.iov_base = m; + iov.iov_len = msgsz; + ret = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, &iov, 1); + + free(m); + if (ret == CS_OK) + return 0; + + return -1; +} + + +int +cpg_wait_reply(void **data, size_t *len, uint32_t seqno) +{ + struct msg_queue_node *n; + int x, found = 0; + + while (!found) { + found = 0; + pthread_mutex_lock(&cpg_mutex); + pthread_cond_wait(&cpg_cond, &cpg_mutex); + + list_for(&pending, n, x) { + if (n->seqno != seqno) + continue; + if (n->state != STATE_MESSAGE) + continue; + found = 1; + goto out; + } + pthread_mutex_unlock(&cpg_mutex); + } + +out: + list_remove(&pending, n); + pthread_mutex_unlock(&cpg_mutex); + + *data = n->msg; + *len = n->msglen; + free(n); + + return 0; +} + + +static void * +cpg_dispatch_thread(void *arg) +{ + cpg_dispatch(cpg_handle, CS_DISPATCH_BLOCKING); + + return NULL; +} + + +int +cpg_start( const char *name, + request_callback_fn req_cb_fn, + request_callback_fn store_cb_fn, + confchange_callback_fn join_fn, + confchange_callback_fn leave_fn) +{ + cpg_handle_t h; + int ret; + + errno = EINVAL; + + if (!name) + return -1; + + ret = snprintf(gname.value, sizeof(gname.value), "%s", name); + if (ret <= 0) + return -1; + + if (ret >= sizeof(gname.value)) { + errno = ENAMETOOLONG; + return -1; + } + gname.length = ret; + + memset(&h, 0, sizeof(h)); + if (cpg_initialize(&h, &my_callbacks) != CS_OK) { + perror("cpg_initialize"); + return -1; + } + + if (cpg_join(h, &gname) != CS_OK) { + perror("cpg_join"); + return -1; + } + + cpg_local_get(h, &my_node_id); + dbg_printf(2, "My CPG nodeid is %d\n", my_node_id); + + pthread_mutex_lock(&cpg_mutex); + pthread_create(&cpg_thread, NULL, cpg_dispatch_thread, NULL); + + memcpy(&cpg_handle, &h, sizeof(h)); + + req_callback_fn = req_cb_fn; + store_callback_fn = store_cb_fn; + conf_join_fn = join_fn; + conf_leave_fn = leave_fn; + + pthread_mutex_unlock(&cpg_mutex); + + return 0; +} + + +int +cpg_stop(void) +{ + pthread_cancel(cpg_thread); + pthread_join(cpg_thread, NULL); + cpg_leave(cpg_handle, &gname); + cpg_finalize(cpg_handle); + + return 0; +} diff --git a/agents/virt/server/cpg.h b/agents/virt/server/cpg.h new file mode 100644 index 0000000..6873955 --- /dev/null +++ b/agents/virt/server/cpg.h @@ -0,0 +1,29 @@ +#ifndef __FENCE_VIRTD_CPG_H +#define __FENCE_VIRTD_CPG_H + +struct cpg_fence_req { + char vm_name[128]; + int request; + uint32_t seqno; + uint32_t response; +}; + +typedef void (*request_callback_fn)(void *data, size_t len, uint32_t nodeid, + uint32_t seqno); +typedef void (*confchange_callback_fn)(const struct cpg_address *m, size_t len); + +int cpg_start( const char *name, + request_callback_fn func, + request_callback_fn store_func, + confchange_callback_fn join, + confchange_callback_fn leave); + +int cpg_get_ids(uint32_t *me, uint32_t *high); +int cpg_stop(void); +int cpg_send_req(void *data, size_t len, uint32_t *seqno); +int cpg_wait_reply(void **data, size_t *len, uint32_t seqno); +int cpg_send_reply(void *data, size_t len, uint32_t nodeid, uint32_t seqno); +int cpg_send_vm_state(virt_state_t *vs); + + +#endif diff --git a/agents/virt/server/daemon_init.c b/agents/virt/server/daemon_init.c new file mode 100644 index 0000000..29b33ad --- /dev/null +++ b/agents/virt/server/daemon_init.c @@ -0,0 +1,215 @@ +/** @file + * daemon_init function, does sanity checks and calls daemon(). + * + * Author: Jeff Moyer <jmoyer@redhat.com> + */ +/* + * TODO: Clean this up so that only one function constructs the + * pidfile /var/run/loggerd.PID, and perhaps only one function + * forms the /proc/PID/ path. + * + * Also need to add file locking for the pid file. + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <fcntl.h> +#include <dirent.h> +#include <sys/mman.h> +#include <sys/errno.h> +#include <libgen.h> +#include <signal.h> +#include <syslog.h> + + +/* + * This should ultimately go in a header file. + */ +void daemon_init(const char *prog, const char *pid_file, int nofork); +void daemon_cleanup(void); +int check_process_running(const char *cmd, const char *pid_file, pid_t * pid); + +/* + * Local prototypes. + */ +static void update_pidfile(const char *filename); +static int setup_sigmask(void); +static char pid_filename[PATH_MAX]; + +static int +check_pid_valid(pid_t pid, const char *prog) +{ + FILE *fp; + DIR *dir; + char filename[PATH_MAX]; + char dirpath[PATH_MAX]; + char proc_cmdline[64]; /* yank this from kernel somewhere */ + char *s = NULL; + + memset(filename, 0, PATH_MAX); + memset(dirpath, 0, PATH_MAX); + + snprintf(dirpath, sizeof (dirpath), "/proc/%d", pid); + if ((dir = opendir(dirpath)) == NULL) { + return 0; /* Pid has gone away. */ + } + closedir(dir); + + /* + * proc-pid directory exists. Now check to see if this + * PID corresponds to the daemon we want to start. + */ + snprintf(filename, sizeof (filename), "/proc/%d/cmdline", pid); + fp = fopen(filename, "r"); + if (fp == NULL) { + perror("check_pid_valid"); + return 0; /* Who cares.... Let's boogy on. */ + } + + if (!fgets(proc_cmdline, sizeof (proc_cmdline) - 1, fp)) { + /* + * Okay, we've seen processes keep a reference to a + * /proc/PID/stat file and not let go. Then when + * you try to read /proc/PID/cmline, you get either + * \000 or -1. In either case, we can safely assume + * the process has gone away. + */ + fclose(fp); + return 0; + } + fclose(fp); + + s = &(proc_cmdline[strlen(proc_cmdline)]); + if (*s == '\n') + *s = 0; + + /* + * Check to see if this is the same executable. + */ + if (strstr(proc_cmdline, prog) == NULL) { + return 0; + } else { + return 1; + } +} + + +int +check_process_running(const char *cmd, const char *filename, pid_t * pid) +{ + pid_t oldpid; + FILE *fp = NULL; + int ret; + + *pid = -1; + + /* + * Read the pid from the file. + */ + fp = fopen(filename, "r"); + if (fp == NULL) { /* error */ + return 0; + } + + ret = fscanf(fp, "%d\n", &oldpid); + fclose(fp); + + if ((ret == EOF) || (ret != 1)) + return 0; + + if (check_pid_valid(oldpid, cmd)) { + *pid = oldpid; + return 1; + } + return 0; +} + + +static void +update_pidfile(const char *filename) +{ + FILE *fp = NULL; + + strncpy(pid_filename, filename, PATH_MAX - 1); + + fp = fopen(pid_filename, "w"); + if (fp == NULL) { + syslog(LOG_ERR, "daemon_init: Unable to create pidfile %s: %s\n", + filename, strerror(errno)); + exit(1); + } + + fprintf(fp, "%d", getpid()); + fclose(fp); +} + + +static int +setup_sigmask(void) +{ + sigset_t set; + + sigfillset(&set); + + /* + * Dont't block signals which would cause us to dump core. + */ + sigdelset(&set, SIGQUIT); + sigdelset(&set, SIGILL); + sigdelset(&set, SIGTRAP); + sigdelset(&set, SIGABRT); + sigdelset(&set, SIGFPE); + sigdelset(&set, SIGSEGV); + sigdelset(&set, SIGBUS); + + /* + * Don't block SIGTERM or SIGCHLD + */ + sigdelset(&set, SIGTERM); + sigdelset(&set, SIGINT); + sigdelset(&set, SIGQUIT); + sigdelset(&set, SIGCHLD); + + return (sigprocmask(SIG_BLOCK, &set, NULL)); +} + + +void +daemon_init(const char *prog, const char *pid_file, int nofork) +{ + pid_t pid; + + if (check_process_running(prog, pid_file, &pid) && (pid != getpid())) { + syslog(LOG_ERR, + "daemon_init: Process \"%s\" already running.\n", + prog); + exit(1); + } + + if (setup_sigmask() < 0) { + syslog(LOG_ERR, "daemon_init: Unable to set signal mask.\n"); + exit(1); + } + + if (!nofork && daemon(0, 0)) { + syslog(LOG_ERR, "daemon_init: Unable to daemonize.\n"); + exit(1); + } + + update_pidfile(pid_file); +} + + +void +daemon_cleanup(void) +{ + if (strlen(pid_filename)) + unlink(pid_filename); +} diff --git a/agents/virt/server/history.c b/agents/virt/server/history.c new file mode 100644 index 0000000..bd3a68c --- /dev/null +++ b/agents/virt/server/history.c @@ -0,0 +1,124 @@ +#include "config.h" + +#include <stdio.h> +#include <malloc.h> +#include <sys/types.h> +#include <errno.h> +#include <string.h> +#include <list.h> +#include <time.h> + +#include "history.h" + +history_info_t * +history_init(history_compare_fn func, time_t expiration, size_t element_size) +{ + history_info_t *hist; + + errno = EINVAL; + if (!func || !expiration || !element_size) + return NULL; + + hist = malloc(sizeof(*hist)); + if (!hist) + return NULL; + memset(hist, 0, sizeof(*hist)); + + hist->timeout = expiration; + hist->element_size = element_size; + hist->compare_func = func; + + return hist; +} + + +/* + * Purge our history when the entries time out. + * + * Returns 1 if a matching history node was found, or 0 + * if not. + */ +int +history_check(history_info_t *hinfo, void *stuff) +{ + history_node *entry = NULL; + time_t now; + int x; + + if (!hinfo) + return 0; /* XXX */ + + if (!hinfo->hist) + return 0; + + now = time(NULL); + +loop_again: + list_for((&hinfo->hist), entry, x) { + if (entry->when < (now - hinfo->timeout)) { + list_remove((&hinfo->hist), entry); + free(entry->data); + free(entry); + goto loop_again; + } + + if (hinfo->compare_func(entry->data, stuff)) { + return 1; + } + } + return 0; +} + + +int +history_record(history_info_t *hinfo, void *data) +{ + history_node *entry = NULL; + + errno = EINVAL; + if (!data || !hinfo) + return -1; + + if (history_check(hinfo, data) == 1) { + errno = EEXIST; + return -1; + } + + entry = malloc(sizeof(*entry)); + if (!entry) { + return -1; + } + memset(entry, 0, sizeof(*entry)); + + entry->data = malloc(hinfo->element_size); + if (!entry->data) { + free(entry); + errno = ENOMEM; + return -1; + } + + memcpy(entry->data, data, hinfo->element_size); + entry->when = time(NULL); + list_insert((&hinfo->hist), entry); + return 0; +} + + +int +history_wipe(history_info_t *hinfo) +{ + history_node *entry = NULL; + + if (!hinfo) + return -1; + + while (hinfo->hist) { + entry = hinfo->hist; + list_remove((&hinfo->hist), entry); + free(entry->data); + free(entry); + } + + /* User must free(hinfo); */ + return 0; +} diff --git a/agents/virt/server/libvirt.c b/agents/virt/server/libvirt.c new file mode 100644 index 0000000..8f01045 --- /dev/null +++ b/agents/virt/server/libvirt.c @@ -0,0 +1,359 @@ +/* + Copyright Red Hat, Inc. 2006-2017 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +/* + * Author: Lon Hohberger <lhh at redhat.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/time.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <libvirt/virterror.h> +#include <nss.h> +#include <libgen.h> +#include <syslog.h> + +/* Local includes */ +#include "xvm.h" +#include "simple_auth.h" +#include "options.h" +#include "mcast.h" +#include "tcp.h" +#include "virt.h" +#include "debug.h" +#include "uuid-test.h" +#include "simpleconfig.h" +#include "static_map.h" +#include "server_plugin.h" + +#define NAME "libvirt" +#define LIBVIRT_VERSION "0.3" + +#define MAGIC 0x1e19317a + +struct libvirt_info { + int magic; + config_object_t *config; + int vp_count; + virConnectPtr *vp; +}; + +#define VALIDATE(arg) \ +do {\ + if (!arg || ((struct libvirt_info *)arg)->magic != MAGIC) { \ + errno = EINVAL;\ + return -1; \ + } \ +} while(0) + + +static void +libvirt_init_libvirt_conf(struct libvirt_info *info) { + config_object_t *config = info->config; + int i = 0; + + if (info->vp) { + dbg_printf(2, "Lost libvirtd connection. Reinitializing.\n"); + for (i = 0 ; i < info->vp_count ; i++) + virConnectClose(info->vp[i]); + free(info->vp); + info->vp = NULL; + } + info->vp_count = 0; + + do { + virConnectPtr vp; + virConnectPtr *vpl = NULL; + char conf_attr[256]; + char value[1024]; + char *uri; + + if (i != 0) { + snprintf(conf_attr, sizeof(conf_attr), + "backends/libvirt/@uri%d", i); + } else + snprintf(conf_attr, sizeof(conf_attr), "backends/libvirt/@uri"); + ++i; + + if (sc_get(config, conf_attr, value, sizeof(value)) != 0) + break; + + uri = value; + vp = virConnectOpen(uri); + if (!vp) { + dbg_printf(1, "[libvirt:INIT] Failed to connect to URI: %s\n", uri); + continue; + } + + vpl = realloc(info->vp, sizeof(*info->vp) * (info->vp_count + 1)); + if (!vpl) { + dbg_printf(1, "[libvirt:INIT] Out of memory allocating URI: %s\n", + uri); + virConnectClose(vp); + continue; + } + + info->vp = vpl; + info->vp[info->vp_count++] = vp; + + if (i > 1) + dbg_printf(1, "[libvirt:INIT] Added URI%d %s\n", i - 1, uri); + else + dbg_printf(1, "[libvirt:INIT] Added URI %s\n", uri); + } while (1); +} + + +static int +libvirt_bad_connections(struct libvirt_info *info) { + int bad = 0; + int i; + + for (i = 0 ; i < info->vp_count ; i++) { + /* + ** Send a dummy command to trigger an error if libvirtd + ** died or restarted + */ + virConnectNumOfDomains(info->vp[i]); + if (!virConnectIsAlive(info->vp[i])) { + dbg_printf(1, "libvirt connection %d is dead\n", i); + bad++; + } + } + + if (info->vp_count < 1 || bad) + libvirt_init_libvirt_conf(info); + + return bad || info->vp_count < 1; +} + +static void +libvirt_validate_connections(struct libvirt_info *info) { + while (1) { + if (libvirt_bad_connections(info)) + sleep(1); + else + break; + } +} + +static int +libvirt_null(const char *vm_name, void *priv) +{ + dbg_printf(5, "ENTER %s %s\n", __FUNCTION__, vm_name); + printf("NULL operation: returning failure\n"); + return 1; +} + + +static int +libvirt_off(const char *vm_name, const char *src, uint32_t seqno, void *priv) +{ + struct libvirt_info *info = (struct libvirt_info *)priv; + + dbg_printf(5, "ENTER %s %s %u\n", __FUNCTION__, vm_name, seqno); + VALIDATE(info); + + libvirt_validate_connections(info); + return vm_off(info->vp, info->vp_count, vm_name); +} + + +static int +libvirt_on(const char *vm_name, const char *src, uint32_t seqno, void *priv) +{ + struct libvirt_info *info = (struct libvirt_info *)priv; + + dbg_printf(5, "ENTER %s %s %u\n", __FUNCTION__, vm_name, seqno); + VALIDATE(info); + + libvirt_validate_connections(info); + return vm_on(info->vp, info->vp_count, vm_name); +} + + +static int +libvirt_devstatus(void *priv) +{ + dbg_printf(5, "%s ---\n", __FUNCTION__); + + if (priv) + return 0; + return 1; +} + + +static int +libvirt_status(const char *vm_name, void *priv) +{ + struct libvirt_info *info = (struct libvirt_info *)priv; + + dbg_printf(5, "ENTER %s %s\n", __FUNCTION__, vm_name); + VALIDATE(info); + + libvirt_validate_connections(info); + return vm_status(info->vp, info->vp_count, vm_name); +} + + +static int +libvirt_reboot(const char *vm_name, const char *src, uint32_t seqno, void *priv) +{ + struct libvirt_info *info = (struct libvirt_info *)priv; + + dbg_printf(5, "ENTER %s %s %u\n", __FUNCTION__, vm_name, seqno); + VALIDATE(info); + + libvirt_validate_connections(info); + return vm_reboot(info->vp, info->vp_count, vm_name); +} + + +static int +libvirt_hostlist(hostlist_callback callback, void *arg, void *priv) +{ + struct libvirt_info *info = (struct libvirt_info *)priv; + virt_list_t *vl; + int x; + + dbg_printf(5, "ENTER %s\n", __FUNCTION__); + VALIDATE(info); + + libvirt_validate_connections(info); + + vl = vl_get(info->vp, info->vp_count, 1); + if (!vl) + return 0; + + for (x = 0; x < vl->vm_count; x++) { + callback(vl->vm_states[x].v_name, + vl->vm_states[x].v_uuid, + vl->vm_states[x].v_state.s_state, arg); + + dbg_printf(10, "[libvirt:HOSTLIST] Sent %s %s %d\n", + vl->vm_states[x].v_name, + vl->vm_states[x].v_uuid, + vl->vm_states[x].v_state.s_state); + } + + vl_free(vl); + return 0; +} + + +static int +libvirt_init(backend_context_t *c, config_object_t *config) +{ + char value[256]; + struct libvirt_info *info = NULL; + + dbg_printf(5, "ENTER [%s:%d %s]\n", __FILE__, __LINE__, __FUNCTION__); + + info = calloc(1, sizeof(*info)); + if (!info) + return -1; + info->magic = MAGIC; + info->config = config; + + libvirt_init_libvirt_conf(info); + + if (sc_get(config, "fence_virtd/@debug", value, sizeof(value)) == 0) + dset(atoi(value)); + + if (info->vp_count < 1) { + dbg_printf(1, "[libvirt:INIT] Could not connect to any hypervisors\n"); + if (info->vp) + free(info->vp); + free(info); + return -1; + } + + *c = (void *) info; + return 0; +} + + +static int +libvirt_shutdown(backend_context_t c) +{ + struct libvirt_info *info = (struct libvirt_info *)c; + int i; + int ret = 0; + + VALIDATE(info); + + for (i = 0 ; i < info->vp_count ; i++) { + if (virConnectClose(info->vp[i]) < 0) + ret = -errno; + } + + free(info->vp); + free(info); + return ret; +} + + +static fence_callbacks_t libvirt_callbacks = { + .null = libvirt_null, + .off = libvirt_off, + .on = libvirt_on, + .reboot = libvirt_reboot, + .status = libvirt_status, + .devstatus = libvirt_devstatus, + .hostlist = libvirt_hostlist +}; + +static backend_plugin_t libvirt_plugin = { + .name = NAME, + .version = LIBVIRT_VERSION, + .callbacks = &libvirt_callbacks, + .init = libvirt_init, + .cleanup = libvirt_shutdown, +}; + +double +BACKEND_VER_SYM(void) +{ + return PLUGIN_VERSION_BACKEND; +} + +const backend_plugin_t * +BACKEND_INFO_SYM(void) +{ + return &libvirt_plugin; +} diff --git a/agents/virt/server/main.c b/agents/virt/server/main.c new file mode 100644 index 0000000..fe57899 --- /dev/null +++ b/agents/virt/server/main.c @@ -0,0 +1,281 @@ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/param.h> +#include <libgen.h> +#include <stdint.h> +#include <syslog.h> + +/* Local includes */ +#include "simpleconfig.h" +#include "static_map.h" +#include "xvm.h" +#include "server_plugin.h" +#include "simple_auth.h" +#include "debug.h" + +/* configure.c */ +int daemon_init(const char *prog, const char *pid_file, int nofork); +int daemon_cleanup(void); + + +static void +usage(void) +{ + printf("Usage: fence_virtd [options]\n"); + printf(" -F Do not daemonize.\n"); + printf(" -f <file> Use <file> as configuration file.\n"); + printf(" -d <level> Set debugging level to <level>.\n"); + printf(" -c Configuration mode.\n"); + printf(" -l List plugins.\n"); + printf(" -w Wait for initialization.\n"); + printf(" -p <file> Use <file> to record the active process id.\n"); +} + + +static int run = 1; +static void +exit_handler(int sig) +{ + run = 0; +} + + +int +main(int argc, char **argv) +{ + char val[4096]; + char listener_name[80]; + char backend_name[80]; + const char *config_file = SYSCONFDIR "/fence_virt.conf"; + char *pid_file = NULL; + config_object_t *config = NULL; + map_object_t *map = NULL; + const listener_plugin_t *lp; + const backend_plugin_t *p; + listener_context_t listener_ctx = NULL; + backend_context_t backend_ctx = NULL; + int debug_set = 0, foreground = 0, wait_for_init = 0; + int opt, configure = 0; + + config = sc_init(); + map = map_init(); + + if (!config || !map) { + perror("malloc"); + return -1; + } + + while ((opt = getopt(argc, argv, "Ff:d:cwlhp:")) != EOF) { + switch(opt) { + case 'F': + printf("Background mode disabled\n"); + foreground = 1; + break; + case 'f': + printf("Using %s\n", optarg); + config_file = optarg; + break; + case 'p': + printf("Using %s\n", optarg); + pid_file = optarg; + break; + case 'd': + debug_set = atoi(optarg); + break; + case 'c': + configure = 1; + break; + case 'w': + wait_for_init = 1; + break; + case 'l': + plugin_dump(); + return 0; + case 'h': + case '?': + usage(); + return 0; + default: + return -1; + } + } + + if (configure) { + return do_configure(config, config_file); + } + + if (sc_parse(config, config_file) != 0) { + printf("Failed to parse %s\n", config_file); + return -1; + } + + if (debug_set) { + snprintf(val, sizeof(val), "%d", debug_set); + sc_set(config, "fence_virtd/@debug", val); + } else { + if (sc_get(config, "fence_virtd/@debug", val, sizeof(val))==0) + debug_set = atoi(val); + } + + dset(debug_set); + + if (!foreground) { + if (sc_get(config, "fence_virtd/@foreground", + val, sizeof(val)) == 0) + foreground = atoi(val); + } + + if (!wait_for_init) { + if (sc_get(config, "fence_virtd/@wait_for_init", + val, sizeof(val)) == 0) + wait_for_init = atoi(val); + if (!wait_for_init) { + /* XXX compat */ + if (sc_get(config, "fence_virtd/@wait_for_backend", + val, sizeof(val)) == 0) + wait_for_init = atoi(val); + } + } + + if (dget() > 3) + sc_dump(config, stdout); + + if (sc_get(config, "fence_virtd/@backend", backend_name, + sizeof(backend_name))) { + printf("Failed to determine backend.\n"); + printf("%s\n", val); + return -1; + } + + dbg_printf(1, "Backend plugin: %s\n", backend_name); + + if (sc_get(config, "fence_virtd/@listener", listener_name, + sizeof(listener_name))) { + printf("Failed to determine backend.\n"); + printf("%s\n", val); + return -1; + } + + dbg_printf(1, "Listener plugin: %s\n", listener_name); + + if (sc_get(config, "fence_virtd/@module_path", val, + sizeof(val))) { +#ifdef MODULE_PATH + snprintf(val, sizeof(val), MODULE_PATH); +#else + printf("Failed to determine module path.\n"); + return -1; +#endif + } + + dbg_printf(1, "Searching %s for plugins...\n", val); + + opt = plugin_search(val); + if (opt > 0) { + dbg_printf(1, "%d plugins found\n", opt); + } else { + printf("No plugins found\n"); + return 1; + } + + if (dget() > 3) + plugin_dump(); + + lp = plugin_find_listener(listener_name); + if (!lp) { + printf("Could not find listener \"%s\"\n", listener_name); + return 1; + } + + p = plugin_find_backend(backend_name); + if (!p) { + printf("Could not find backend \"%s\"\n", backend_name); + return 1; + } + + if (pid_file == NULL) { + pid_file = malloc(PATH_MAX); + memset(pid_file, 0, PATH_MAX); + snprintf(pid_file, PATH_MAX, "/var/run/%s.pid", basename(argv[0])); + } + + if (check_file_permissions(config_file) != 0) + return -1; + + sprintf(val, "listeners/%s/@key_file", listener_name); + if (sc_get(config, val, + val, sizeof(val)-1) == 0) { + dbg_printf(1, "Got %s for key_file\n", val); + } else { + snprintf(val, sizeof(val), "%s", DEFAULT_KEY_FILE); + } + + if (check_file_permissions(val) != 0) + return -1; + + openlog(basename(argv[0]), LOG_NDELAY | LOG_PID, LOG_DAEMON); + + daemon_init(basename(argv[0]), pid_file, foreground); + + signal(SIGINT, exit_handler); + signal(SIGTERM, exit_handler); + signal(SIGQUIT, exit_handler); + + syslog(LOG_NOTICE, "fence_virtd starting. Listener: %s Backend: %s", + listener_name, backend_name); + + while (p->init(&backend_ctx, config) < 0) { + if (!wait_for_init || !run) { + if (foreground) { + printf("Backend plugin %s failed to initialize\n", + backend_name); + } + syslog(LOG_ERR, + "Backend plugin %s failed to initialize\n", + backend_name); + return 1; + } + sleep(5); + } + + if (map_load(map, config) < 0) { + syslog(LOG_WARNING, "Failed to load static maps\n"); + } + + /* only client we have now is mcast (fence_xvm behavior) */ + while (lp->init(&listener_ctx, p->callbacks, config, map, + backend_ctx) != 0) { + if (!wait_for_init || !run) { + if (foreground) { + printf("Listener plugin %s failed to initialize\n", + listener_name); + } + syslog(LOG_ERR, + "Listener plugin %s failed to initialize\n", + listener_name); + return 1; + } + sleep(5); + } + + while (run && lp->dispatch(listener_ctx, NULL) >= 0); + + syslog(LOG_NOTICE, "fence_virtd shutting down"); + + map_release(map); + sc_release(config); + + lp->cleanup(listener_ctx); + p->cleanup(backend_ctx); + + plugin_unload(); + daemon_cleanup(); + + return 0; +} diff --git a/agents/virt/server/mcast.c b/agents/virt/server/mcast.c new file mode 100644 index 0000000..a95ab37 --- /dev/null +++ b/agents/virt/server/mcast.c @@ -0,0 +1,622 @@ +/* + Copyright Red Hat, Inc. 2006 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +/* + * Author: Lon Hohberger <lhh at redhat.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/time.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <nss.h> +#include <libgen.h> + +/* Local includes */ +#include "xvm.h" +#include "simple_auth.h" +#include "options.h" +#include "mcast.h" +#include "tcp.h" +#include "debug.h" +#include "fdops.h" +#include "list.h" +#include "simpleconfig.h" +#include "static_map.h" +#include "server_plugin.h" +#include "history.h" + +#define NAME "multicast" +#define MCAST_VERSION "1.3" + +#define MCAST_MAGIC 0xabb911a3 + +#define VALIDATE(info) \ +do {\ + if (!info || info->magic != MCAST_MAGIC)\ + return -EINVAL;\ +} while(0) + +typedef struct _mcast_options { + char *addr; + char *key_file; + int ifindex; + int family; + unsigned int port; + unsigned int hash; + unsigned int auth; + unsigned int flags; +} mcast_options; + + +typedef struct _mcast_info { + uint64_t magic; + void *priv; + map_object_t *map; + history_info_t *history; + char key[MAX_KEY_LEN]; + mcast_options args; + const fence_callbacks_t *cb; + ssize_t key_len; + int mc_sock; + int need_kill; +} mcast_info; + + +struct mcast_hostlist_arg { + map_object_t *map; + const char *src; + int fd; +}; + + +/* + * See if we fenced this node recently (successfully) + * If so, ignore the request for a few seconds. + * + * We purge our history when the entries time out. + */ +static int +check_history(void *a, void *b) { + fence_req_t *old = a, *current = b; + + if (old->request == current->request && + old->seqno == current->seqno && + !strcasecmp((const char *)old->domain, + (const char *)current->domain)) { + return 1; + } + return 0; +} + + +static int +connect_tcp(fence_req_t *req, fence_auth_type_t auth, + void *key, size_t key_len) +{ + int fd = -1; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + char buf[128]; + + switch(req->family) { + case PF_INET: + memset(&sin, 0, sizeof(sin)); + memcpy(&sin.sin_addr, req->address, + sizeof(sin.sin_addr)); + sin.sin_family = PF_INET; + fd = ipv4_connect(&sin.sin_addr, req->port, + 5); + if (fd < 0) { + printf("Failed to call back\n"); + return -1; + } + break; + case PF_INET6: + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6.sin6_addr, req->address, + sizeof(sin6.sin6_addr)); + sin.sin_family = PF_INET6; + fd = ipv6_connect(&sin6.sin6_addr, req->port, + 5); + + memset(buf,0,sizeof(buf)); + inet_ntop(PF_INET6, &sin6.sin6_addr, buf, sizeof(buf)); + + if (fd < 0) { + printf("Failed to call back %s\n", buf); + return -1; + } + break; + default: + printf("Family = %d\n", req->family); + return -1; + } + + /* Noops if auth == AUTH_NONE */ + if (sock_response(fd, auth, key, key_len, 10) <= 0) { + printf("Failed to respond to challenge\n"); + close(fd); + return -1; + } + + if (sock_challenge(fd, auth, key, key_len, 10) <= 0) { + printf("Remote failed challenge\n"); + close(fd); + return -1; + } + return fd; +} + + +static int +mcast_hostlist(const char *vm_name, const char *vm_uuid, + int state, void *priv) +{ + struct mcast_hostlist_arg *arg = (struct mcast_hostlist_arg *)priv; + host_state_t hinfo; + struct timeval tv; + int ret; + + if (map_check2(arg->map, arg->src, vm_uuid, vm_name) == 0) { + /* if we don't have access to fence this VM, + * we should not see it in a hostlist either */ + return 0; + } + + strncpy((char *)hinfo.domain, vm_name, sizeof(hinfo.domain) - 1); + strncpy((char *)hinfo.uuid, vm_uuid, sizeof(hinfo.uuid) - 1); + hinfo.state = state; + + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = _write_retry(arg->fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + + +static int +mcast_hostlist_begin(int fd) +{ + struct timeval tv; + char val = (char)RESP_HOSTLIST; + + tv.tv_sec = 1; + tv.tv_usec = 0; + return _write_retry(fd, &val, 1, &tv); +} + + +static int +mcast_hostlist_end(int fd) +{ + host_state_t hinfo; + struct timeval tv; + int ret; + + printf("Sending terminator packet\n"); + + memset(&hinfo, 0, sizeof(hinfo)); + + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = _write_retry(fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + + +static int +do_fence_request_tcp(fence_req_t *req, mcast_info *info) +{ + char ip_addr_src[1024]; + int fd = -1; + char response = 1; + struct mcast_hostlist_arg arg; + + fd = connect_tcp(req, info->args.auth, info->key, info->key_len); + if (fd < 0) { + dbg_printf(2, "Could not send reply to fence request: %s\n", + strerror(errno)); + goto out; + } + + inet_ntop(req->family, req->address, + ip_addr_src, sizeof(ip_addr_src)); + + dbg_printf(2, "Request %d seqno %d src %s target %s\n", + req->request, req->seqno, ip_addr_src, req->domain); + + switch(req->request) { + case FENCE_NULL: + response = info->cb->null((char *)req->domain, info->priv); + break; + case FENCE_ON: + if (map_check(info->map, ip_addr_src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->on((char *)req->domain, ip_addr_src, + req->seqno, info->priv); + break; + case FENCE_OFF: + if (map_check(info->map, ip_addr_src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->off((char *)req->domain, ip_addr_src, + req->seqno, info->priv); + break; + case FENCE_REBOOT: + if (map_check(info->map, ip_addr_src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->reboot((char *)req->domain, ip_addr_src, + req->seqno, info->priv); + break; + case FENCE_STATUS: + if (map_check(info->map, ip_addr_src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->status((char *)req->domain, info->priv); + break; + case FENCE_DEVSTATUS: + response = info->cb->devstatus(info->priv); + break; + case FENCE_HOSTLIST: + arg.map = info->map; + arg.src = ip_addr_src; + arg.fd = fd; + + mcast_hostlist_begin(arg.fd); + response = info->cb->hostlist(mcast_hostlist, &arg, + info->priv); + mcast_hostlist_end(arg.fd); + break; + } + + dbg_printf(3, "Sending response to caller...\n"); + if (_write_retry(fd, &response, 1, NULL) < 0) { + perror("write"); + } + + /* XVM shotguns multicast packets, so we want to avoid + * acting on the same request multiple times if the first + * attempt was successful. + */ + history_record(info->history, req); +out: + if (fd != -1) + close(fd); + + return 1; +} + + +static int +mcast_dispatch(listener_context_t c, struct timeval *timeout) +{ + mcast_info *info; + fence_req_t data; + fd_set rfds; + struct sockaddr_in sin; + int len; + int n; + socklen_t slen; + + info = (mcast_info *)c; + VALIDATE(info); + + FD_ZERO(&rfds); + FD_SET(info->mc_sock, &rfds); + + n = select((info->mc_sock)+1, &rfds, NULL, NULL, timeout); + if (n <= 0) { + if (errno == EINTR || errno == EAGAIN) + n = 0; + else + dbg_printf(2, "select: %s\n", strerror(errno)); + return n; + } + + slen = sizeof(sin); + len = recvfrom(info->mc_sock, &data, sizeof(data), 0, + (struct sockaddr *)&sin, &slen); + + if (len <= 0) { + perror("recvfrom"); + return len; + } + + swab_fence_req_t(&data); + + if (!verify_request(&data, info->args.hash, info->key, + info->key_len)) { + printf("Key mismatch; dropping packet\n"); + return 0; + } + + printf("Request %d seqno %d domain %s\n", data.request, data.seqno, + data.domain); + + if (history_check(info->history, &data) == 1) { + printf("We just did this request; dropping packet\n"); + return 0; + } + + switch(info->args.auth) { + case AUTH_NONE: + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + printf("Plain TCP request\n"); + do_fence_request_tcp(&data, info); + break; + default: + printf("XXX Unhandled authentication\n"); + } + + return 0; +} + + +static int +mcast_config(config_object_t *config, mcast_options *args) +{ + char value[1024]; + int errors = 0; + + if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0) + dset(atoi(value)); + + if (sc_get(config, "listeners/multicast/@key_file", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for key_file\n", value); + args->key_file = strdup(value); + } else { + args->key_file = strdup(DEFAULT_KEY_FILE); + if (!args->key_file) { + dbg_printf(1, "Failed to allocate memory\n"); + return -1; + } + } + + args->hash = DEFAULT_HASH; + if (sc_get(config, "listeners/multicast/@hash", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for hash\n", value); + if (!strcasecmp(value, "none")) { + args->hash = HASH_NONE; + } else if (!strcasecmp(value, "sha1")) { + args->hash = HASH_SHA1; + } else if (!strcasecmp(value, "sha256")) { + args->hash = HASH_SHA256; + } else if (!strcasecmp(value, "sha512")) { + args->hash = HASH_SHA512; + } else { + dbg_printf(1, "Unsupported hash: %s\n", value); + ++errors; + } + } + + args->auth = DEFAULT_AUTH; + if (sc_get(config, "listeners/multicast/@auth", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for auth\n", value); + if (!strcasecmp(value, "none")) { + args->auth = AUTH_NONE; + } else if (!strcasecmp(value, "sha1")) { + args->auth = AUTH_SHA1; + } else if (!strcasecmp(value, "sha256")) { + args->auth = AUTH_SHA256; + } else if (!strcasecmp(value, "sha512")) { + args->auth = AUTH_SHA512; + } else { + dbg_printf(1, "Unsupported auth: %s\n", value); + ++errors; + } + } + + args->family = PF_INET; + if (sc_get(config, "listeners/multicast/@family", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for family\n", value); + if (!strcasecmp(value, "ipv4")) { + args->family = PF_INET; + } else if (!strcasecmp(value, "ipv6")) { + args->family = PF_INET6; + } else { + dbg_printf(1, "Unsupported family: %s\n", value); + ++errors; + } + } + + if (sc_get(config, "listeners/multicast/@address", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for address\n", value); + args->addr = strdup(value); + } else { + if (args->family == PF_INET) { + args->addr = strdup(IPV4_MCAST_DEFAULT); + } else { + args->addr = strdup(IPV6_MCAST_DEFAULT); + } + } + if (!args->addr) { + return -1; + } + + args->port = DEFAULT_MCAST_PORT; + if (sc_get(config, "listeners/multicast/@port", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for port\n", value); + args->port = atoi(value); + if (args->port <= 0) { + dbg_printf(1, "Invalid port: %s\n", value); + ++errors; + } + } + + args->ifindex = 0; + if (sc_get(config, "listeners/multicast/@interface", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for interface\n", value); + args->ifindex = if_nametoindex(value); + if (args->ifindex < 0) { + dbg_printf(1, "Invalid interface: %s\n", value); + ++errors; + } + } + + return errors; +} + + +static int +mcast_init(listener_context_t *c, const fence_callbacks_t *cb, + config_object_t *config, map_object_t *map, void *priv) +{ + mcast_info *info; + int mc_sock, ret; + + /* Initialize NSS; required to do hashing, as silly as that + sounds... */ + if (NSS_NoDB_Init(NULL) != SECSuccess) { + printf("Could not initialize NSS\n"); + return 1; + } + + info = malloc(sizeof(*info)); + if (!info) + return -1; + memset(info, 0, sizeof(*info)); + + info->priv = priv; + info->cb = cb; + info->map = map; + + ret = mcast_config(config, &info->args); + if (ret < 0) { + perror("mcast_config"); + free(info); + return -1; + } else if (ret > 0) { + printf("%d errors found during configuration\n",ret); + free(info); + return -1; + } + + if (info->args.auth != AUTH_NONE || info->args.hash != HASH_NONE) { + info->key_len = read_key_file(info->args.key_file, + info->key, sizeof(info->key)); + if (info->key_len < 0) { + printf("Could not read %s; operating without " + "authentication\n", info->args.key_file); + info->args.auth = AUTH_NONE; + info->args.hash = HASH_NONE; + info->key_len = 0; + } + } + + if (info->args.family == PF_INET) + mc_sock = ipv4_recv_sk(info->args.addr, + info->args.port, + info->args.ifindex); + else + mc_sock = ipv6_recv_sk(info->args.addr, + info->args.port, + info->args.ifindex); + if (mc_sock < 0) { + printf("Could not set up multicast listen socket\n"); + free(info); + return -1; + } + + info->magic = MCAST_MAGIC; + info->mc_sock = mc_sock; + info->history = history_init(check_history, 10, sizeof(fence_req_t)); + *c = (listener_context_t)info; + return 0; +} + + +static int +mcast_shutdown(listener_context_t c) +{ + mcast_info *info = (mcast_info *)c; + + VALIDATE(info); + info->magic = 0; + history_wipe(info->history); + free(info->history); + free(info->args.key_file); + free(info->args.addr); + close(info->mc_sock); + free(info); + + return 0; +} + + +static listener_plugin_t mcast_plugin = { + .name = NAME, + .version = MCAST_VERSION, + .init = mcast_init, + .dispatch = mcast_dispatch, + .cleanup = mcast_shutdown, +}; + +double +LISTENER_VER_SYM(void) +{ + return PLUGIN_VERSION_LISTENER; +} + +const listener_plugin_t * +LISTENER_INFO_SYM(void) +{ + return &mcast_plugin; +} diff --git a/agents/virt/server/plugin.c b/agents/virt/server/plugin.c new file mode 100644 index 0000000..d9a69fb --- /dev/null +++ b/agents/virt/server/plugin.c @@ -0,0 +1,417 @@ +/* + Copyright Red Hat, Inc. 2002-2004, 2009 + + The Magma Cluster API Library is free software; you can redistribute + it and/or modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either version + 2.1 of the License, or (at your option) any later version. + + The Magma Cluster API Library is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. + */ +/** @file + * Plugin loading routines + */ + +#include "config.h" + +#include <dlfcn.h> +#include <stdlib.h> +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdint.h> +#include <malloc.h> +#include <string.h> +#include <dirent.h> + +#include "list.h" +#include "simpleconfig.h" +#include "static_map.h" +#include "server_plugin.h" +#include "debug.h" + +typedef struct _plugin_list { + list_head(); + const listener_plugin_t *listener; + const backend_plugin_t *backend; + void *handle; + plugin_type_t type; +} plugin_list_t; + +static plugin_list_t *server_plugins = NULL; + + +static int +plugin_reg_backend(void *handle, const backend_plugin_t *plugin) +{ + plugin_list_t *newplug; + + if (plugin_find_backend(plugin->name)) { + errno = EEXIST; + return -1; + } + + newplug = malloc(sizeof(*newplug)); + if (!newplug) + return -1; + memset(newplug, 0, sizeof(*newplug)); + newplug->backend = plugin; + newplug->type = PLUGIN_BACKEND; + newplug->handle = handle; + + list_insert(&server_plugins, newplug); + return 0; +} + + +static int +plugin_reg_listener(void *handle, const listener_plugin_t *plugin) +{ + plugin_list_t *newplug; + + if (plugin_find_listener(plugin->name)) { + errno = EEXIST; + return -1; + } + + newplug = malloc(sizeof(*newplug)); + if (!newplug) + return -1; + memset(newplug, 0, sizeof(*newplug)); + newplug->listener = plugin; + newplug->type = PLUGIN_LISTENER; + newplug->handle = handle; + + list_insert(&server_plugins, newplug); + return 0; +} + + +void +plugin_dump(void) +{ + plugin_list_t *p; + int x, y; + + y = 0; + list_for(&server_plugins, p, x) { + if (p->type == PLUGIN_BACKEND) { + if (!y) { + y = 1; + printf("Available backends:\n"); + } + printf(" %s %s\n", + p->backend->name, p->backend->version); + } + } + + y = 0; + list_for(&server_plugins, p, x) { + if (p->type == PLUGIN_LISTENER) { + if (!y) { + y = 1; + printf("Available listeners:\n"); + } + printf(" %s %s\n", + p->listener->name, p->listener->version); + } + } +} + + +const backend_plugin_t * +plugin_find_backend(const char *name) +{ + plugin_list_t *p; + int x; + + list_for(&server_plugins, p, x) { + if (p->type != PLUGIN_BACKEND) + continue; + if (!strcasecmp(name, p->backend->name)) + return p->backend; + } + + return NULL; +} + + +const listener_plugin_t * +plugin_find_listener(const char *name) +{ + plugin_list_t *p; + int x; + + list_for(&server_plugins, p, x) { + if (p->type != PLUGIN_LISTENER) + continue; + if (!strcasecmp(name, p->listener->name)) + return p->listener; + } + + return NULL; +} + + +static int +backend_plugin_load(void *handle, const char *libpath) +{ + const backend_plugin_t *plug = NULL; + double (*modversion)(void); + backend_plugin_t *(*modinfo)(void); + + modversion = dlsym(handle, BACKEND_VER_STR); + if (!modversion) { + dbg_printf(1, "Failed to map %s\n", BACKEND_VER_STR); + errno = EINVAL; + return -1; + } + + if (modversion() != PLUGIN_VERSION_BACKEND) { + dbg_printf(1, "API version mismatch in %s: \n" + " %f expected; %f received.\n", libpath, + PLUGIN_VERSION_BACKEND, modversion()); + errno = EINVAL; + return -1; + } + + modinfo = dlsym(handle, BACKEND_INFO_STR); + if (!modinfo) { + dbg_printf(1, "Failed to map %s\n", BACKEND_INFO_STR); + errno = EINVAL; + return -1; + } + + plug = modinfo(); + if (plugin_reg_backend(handle, plug) < 0) { + dbg_printf(1, "Failed to register %s %s\n", plug->name, + plug->version); + errno = EINVAL; + return -1; + } else { + dbg_printf(1, "Registered backend plugin %s %s\n", + plug->name, plug->version); + } + + return 0; +} + + +static int +listener_plugin_load(void *handle, const char *libpath) +{ + const listener_plugin_t *plug = NULL; + double (*modversion)(void); + listener_plugin_t *(*modinfo)(void); + + modversion = dlsym(handle, LISTENER_VER_STR); + if (!modversion) { + dbg_printf(1, "Failed to map %s\n", LISTENER_VER_STR); + errno = EINVAL; + return -1; + } + + if (modversion() != PLUGIN_VERSION_LISTENER) { + dbg_printf(1, "API version mismatch in %s: \n" + " %f expected; %f received.\n", libpath, + PLUGIN_VERSION_LISTENER, modversion()); + dlclose(handle); + errno = EINVAL; + return -1; + } + + modinfo = dlsym(handle, LISTENER_INFO_STR); + if (!modinfo) { + dbg_printf(1, "Failed to map %s\n", LISTENER_INFO_STR); + errno = EINVAL; + return -1; + } + + plug = modinfo(); + if (plugin_reg_listener(handle, plug) < 0) { + dbg_printf(1, "Failed to register %s %s\n", plug->name, + plug->version); + errno = EINVAL; + return -1; + } else { + dbg_printf(1, "Registered listener plugin %s %s\n", + plug->name, plug->version); + } + + return 0; +} + + +/** + * Load a cluster plugin .so file and map all the functions + * provided to entries in a backend_plugin_t structure. + * + * @param libpath Path to file. + * @return NULL on failure, or plugin-specific + * (const) backend_plugin_t * structure on + * success. + */ +int +plugin_load(const char *libpath) +{ + void *handle = NULL; + + errno = 0; + + if (!libpath) { + errno = EINVAL; + return -1; + } + + dbg_printf(3, "Loading plugin from %s\n", libpath); + handle = dlopen(libpath, RTLD_NOW); + if (!handle) { + dbg_printf(3, "Could not dlopen %s: %s\n", libpath, dlerror()); + errno = ELIBACC; + return -1; + } + + if (!backend_plugin_load(handle, libpath) || + !listener_plugin_load(handle, libpath)) + return 0; + + dbg_printf(3, "%s is not a valid plugin\n", libpath); + dlclose(handle); + errno = EINVAL; + return -1; +} + +void +plugin_unload(void) +{ + plugin_list_t *p; + int x; + + list_for(&server_plugins, p, x) { + dlclose(p->handle); + } +} + +/** + Free up a null-terminated array of strings + */ +static void +free_dirnames(char **dirnames) +{ + int x = 0; + + for (; dirnames[x]; x++) + free(dirnames[x]); + + free(dirnames); +} + + +static int +_compare(const void *a, const void *b) +{ + return strcmp((const char *)a, (const char *)b); +} + + +/** + Read all entries in a directory and return them in a NULL-terminated, + sorted array. + */ +static int +read_dirnames_sorted(const char *directory, char ***dirnames) +{ + DIR *dir; + struct dirent *entry; + char filename[1024]; + int count = 0, x = 0; + + dir = opendir(directory); + if (!dir) + return -1; + + /* Count the number of plugins */ + while ((entry = readdir(dir)) != NULL) + ++count; + + /* Malloc the entries */ + *dirnames = malloc(sizeof(char *) * (count+1)); + if (!*dirnames) { +#ifdef DEBUG + printf("%s: Failed to malloc %d bytes", + __FUNCTION__, (int)(sizeof(char *) * (count+1))); +#endif + closedir(dir); + errno = ENOMEM; + return -1; + } + memset(*dirnames, 0, sizeof(char *) * (count + 1)); + rewinddir(dir); + + /* Store the directory names. */ + while ((entry = readdir(dir)) != NULL) { + snprintf(filename, sizeof(filename), "%s/%s", directory, + entry->d_name); + + (*dirnames)[x] = strdup(filename); + if (!(*dirnames)[x]) { +#ifdef DEBUG + printf("Failed to duplicate %s\n", + filename); +#endif + free_dirnames(*dirnames); + closedir(dir); + errno = ENOMEM; + return -1; + } + ++x; + } + + closedir(dir); + + /* Sort the directory names. */ + qsort((*dirnames), count, sizeof(char *), _compare); + + return 0; +} + + +/** + */ +int +plugin_search(const char *pathname) +{ + int found = 0; + int fcount = 0; + char **filenames; + + dbg_printf(1, "Searching for plugins in %s\n", pathname); + if (read_dirnames_sorted(pathname, &filenames) != 0) { + return -1; + } + + for (fcount = 0; filenames[fcount]; fcount++) { + + if (plugin_load(filenames[fcount]) == 0) + ++found; + } + + free_dirnames(filenames); + if (!found) { + dbg_printf(1, "No usable plugins found.\n"); + errno = ELIBACC; + return -1; + } + + return found; +} diff --git a/agents/virt/server/serial.c b/agents/virt/server/serial.c new file mode 100644 index 0000000..bde8218 --- /dev/null +++ b/agents/virt/server/serial.c @@ -0,0 +1,459 @@ +/* + Copyright Red Hat, Inc. 2010 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +/* + * Author: Lon Hohberger <lhh at redhat.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/time.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <nss.h> +#include <libgen.h> + +/* Local includes */ +#include "debug.h" +#include "fdops.h" +#include "serial.h" +#include "list.h" +#include "simpleconfig.h" +#include "static_map.h" +#include "server_plugin.h" +#include "history.h" +#include "xvm.h" + +#define NAME "serial" +#define SERIAL_VERSION "0.5" + +#define SERIAL_PLUG_MAGIC 0x1227a000 + +#define VALIDATE(info) \ +do {\ + if (!info || info->magic != SERIAL_PLUG_MAGIC)\ + return -EINVAL;\ +} while(0) + + +typedef struct _serial_info { + uint64_t magic; + const fence_callbacks_t *cb; + void *priv; + char *uri; + char *path; + history_info_t *history; + map_object_t *maps; + int mode; + int wake_fd; +} serial_info; + + +struct serial_hostlist_arg { + map_object_t *map; + const char *src; + int fd; +}; + + +/* + * See if we fenced this node recently (successfully) + * If so, ignore the request for a few seconds. + * + * We purge our history when the entries time out. + */ +static int +check_history(void *a, void *b) { + serial_req_t *old = a, *current = b; + + if (old->request == current->request && + old->seqno == current->seqno && + !strcasecmp((const char *)old->domain, + (const char *)current->domain)) { + return 1; + } + return 0; +} + + +static int +serial_hostlist(const char *vm_name, const char *vm_uuid, + int state, void *priv) +{ + struct serial_hostlist_arg *arg = (struct serial_hostlist_arg *)priv; + host_state_t hinfo; + struct timeval tv; + int ret; + + if (map_check2(arg->map, arg->src, vm_uuid, vm_name) == 0) { + /* if we don't have access to fence this VM, + * we should not see it in a hostlist either */ + return 0; + } + + strncpy((char *)hinfo.domain, vm_name, sizeof(hinfo.domain) - 1); + strncpy((char *)hinfo.uuid, vm_uuid, sizeof(hinfo.uuid) - 1); + hinfo.state = state; + + tv.tv_sec = 1; + tv.tv_usec = 0; + + ret = _write_retry(arg->fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + + +static int +serial_hostlist_begin(int fd) +{ + struct timeval tv; + serial_resp_t resp; + + resp.magic = SERIAL_MAGIC; + resp.response = RESP_HOSTLIST; + + tv.tv_sec = 1; + tv.tv_usec = 0; + return _write_retry(fd, &resp, sizeof(resp), &tv); +} + + +static int +serial_hostlist_end(int fd) +{ + host_state_t hinfo; + struct timeval tv; + int ret; + + //printf("Sending terminator packet\n"); + + memset(&hinfo, 0, sizeof(hinfo)); + + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = _write_retry(fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + + +static int +do_fence_request(int fd, const char *src, serial_req_t *req, serial_info *info) +{ + char response = RESP_FAIL; + struct serial_hostlist_arg arg; + serial_resp_t resp; + + arg.fd = fd; + + switch(req->request) { + case FENCE_NULL: + response = info->cb->null((char *)req->domain, info->priv); + break; + case FENCE_ON: + if (map_check(info->maps, src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->on((char *)req->domain, src, + req->seqno, info->priv); + break; + case FENCE_OFF: + if (map_check(info->maps, src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->off((char *)req->domain, src, + req->seqno, info->priv); + break; + case FENCE_REBOOT: + if (map_check(info->maps, src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->reboot((char *)req->domain, src, + req->seqno, info->priv); + break; + case FENCE_STATUS: + if (map_check(info->maps, src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->status((char *)req->domain, info->priv); + break; + case FENCE_DEVSTATUS: + response = info->cb->devstatus(info->priv); + break; + case FENCE_HOSTLIST: + arg.map = info->maps; + arg.src = src; + arg.fd = fd; + + serial_hostlist_begin(arg.fd); + response = info->cb->hostlist(serial_hostlist, &arg, + info->priv); + serial_hostlist_end(arg.fd); + break; + } + + resp.magic = SERIAL_MAGIC; + resp.response = response; + swab_serial_resp_t(&resp); + + dbg_printf(3, "Sending response to caller...\n"); + if (_write_retry(fd, &resp, sizeof(resp), NULL) < 0) + perror("write"); + + /* XVM shotguns multicast packets, so we want to avoid + * acting on the same request multiple times if the first + * attempt was successful. + */ + history_record(info->history, req); + + return 1; +} + + +static int +serial_dispatch(listener_context_t c, struct timeval *timeout) +{ + char src_domain[MAX_DOMAINNAME_LENGTH]; + serial_info *info; + serial_req_t data; + fd_set rfds; + struct timeval tv; + int max; + int n, x, ret; + + info = (serial_info *)c; + VALIDATE(info); + + FD_ZERO(&rfds); + domain_sock_fdset(&rfds, &max); + FD_SET(info->wake_fd, &rfds); + if (info->wake_fd > max) + max = info->wake_fd; + + n = select(max+1, &rfds, NULL, NULL, timeout); + if (n < 0) { + if (errno == EINTR || errno == EAGAIN) + n = 0; + else + dbg_printf(2, "select: %s\n", strerror(errno)); + return n; + } + + /* + * See if the goal was just to be woken up in order to refill our + * file descriptor set. For example, if multiple domains were + * created simultaneously, we would have to refill our fd_set + */ + if (FD_ISSET(info->wake_fd, &rfds)) { + tv.tv_sec = 0; + tv.tv_usec = 10000; + _read_retry(info->wake_fd, &c, 1, &tv); + return 0; + } + + /* + * If no requests, we're done + */ + if (n == 0) + return 0; + + /* find & read request */ + for (x = 0; x <= max; x++) { + if (FD_ISSET(x, &rfds)) { + tv.tv_sec = 1; + tv.tv_usec = 0; + + ret = _read_retry(x, &data, sizeof(data), &tv); + + if (ret != sizeof(data)) { + if (--n > 0) + continue; + else + return 0; + } else { + swab_serial_req_t(&data); + break; + } + } + } + + src_domain[0] = 0; + domain_sock_name(x, src_domain, sizeof(src_domain)); + + dbg_printf(2, "Sock %d Request %d seqno %d src %s target %s\n", x, + data.request, data.seqno, src_domain, data.domain); + + if (history_check(info->history, &data) == 1) { + dbg_printf(3, "We just did this request; dropping packet\n"); + return 0; + } + + do_fence_request(x, src_domain[0] == 0 ? NULL : src_domain, + &data, info); + + return 0; +} + + +static int +serial_config(config_object_t *config, serial_info *args) +{ + char value[1024]; + int errors = 0; + + if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0) + dset(atoi(value)); + + if (sc_get(config, "listeners/serial/@uri", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for uri\n", value); + args->uri = strdup(value); + } + + if (sc_get(config, "listeners/serial/@path", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for path\n", value); + args->path = strdup(value); + } + + if (sc_get(config, "listeners/serial/@mode", + value, sizeof(value)-1) == 0) { + if (!strcasecmp(value, "vmchannel")) { + args->mode = 1; + } else if (!strcasecmp(value, "serial")) { + args->mode = 0; + } else { + args->mode = atoi(value); + if (args->mode < 0) + args->mode = 0; + } + + dbg_printf(1, "Got %s for mode\n", + args->mode?"VMChannel":"serial"); + + } + + return errors; +} + + +static int +serial_init(listener_context_t *c, const fence_callbacks_t *cb, + config_object_t *config, map_object_t *map, void *priv) +{ + serial_info *info; + int ret; + + info = malloc(sizeof(*info)); + if (!info) + return -1; + memset(info, 0, sizeof(*info)); + + info->priv = priv; + info->cb = cb; + + ret = serial_config(config, info); + if (ret < 0) { + perror("serial_config"); + return -1; + } else if (ret > 0) { + printf("%d errors found during configuration\n",ret); + return -1; + } + + info->maps = map; + + info->magic = SERIAL_PLUG_MAGIC; + info->history = history_init(check_history, 10, sizeof(fence_req_t)); + *c = (listener_context_t)info; + start_event_listener(info->uri, info->path, info->mode, &info->wake_fd); + sleep(1); + + return 0; +} + + +static int +serial_shutdown(listener_context_t c) +{ + serial_info *info = (serial_info *)c; + + dbg_printf(3, "Shutting down serial\n"); + + VALIDATE(info); + info->magic = 0; + stop_event_listener(); + domain_sock_cleanup(); + history_wipe(info->history); + free(info->history); + free(info->uri); + free(info->path); + free(info); + + return 0; +} + + +static listener_plugin_t serial_plugin = { + .name = NAME, + .version = SERIAL_VERSION, + .init = serial_init, + .dispatch = serial_dispatch, + .cleanup = serial_shutdown, +}; + +double +LISTENER_VER_SYM(void) +{ + return PLUGIN_VERSION_LISTENER; +} + +const listener_plugin_t * +LISTENER_INFO_SYM(void) +{ + return &serial_plugin; +} diff --git a/agents/virt/server/serial.h b/agents/virt/server/serial.h new file mode 100644 index 0000000..481400a --- /dev/null +++ b/agents/virt/server/serial.h @@ -0,0 +1,20 @@ +#ifndef __VIRT_SERIAL_H +#define __VIRT_SERIAL_H + +#include <sys/select.h> + +/* virt-sockets.c */ +int domain_sock_setup(const char *domain, const char *socket_path); +int domain_sock_close(const char *domain); +int domain_sock_fdset(fd_set *set, int *max); + +/* Find the domain name associated with a FD */ +int domain_sock_name(int fd, char *outbuf, size_t buflen); +int domain_sock_cleanup(void); + +/* virt-serial.c - event thread control functions */ +int start_event_listener(const char *uri, const char *path, int mode, int *wake_fd); +int stop_event_listener(void); + + +#endif diff --git a/agents/virt/server/static_map.c b/agents/virt/server/static_map.c new file mode 100644 index 0000000..7bdc400 --- /dev/null +++ b/agents/virt/server/static_map.c @@ -0,0 +1,237 @@ +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <stdlib.h> +#include <assert.h> +#include <stdio.h> + +#include "simpleconfig.h" +#include "static_map.h" +#include "list.h" +#include "debug.h" +#include "serial.h" +#include "uuid-test.h" + +struct perm_entry { + list_head(); + char name[129]; +}; + +struct perm_group { + list_head(); + struct perm_entry *uuids; + struct perm_entry *ips; + char name[129]; +}; + + +static void +static_map_cleanup(void **info) +{ + struct perm_group *groups = (struct perm_group *)(*info); + struct perm_group *group; + struct perm_entry *entry; + + while (groups) { + group = groups; + list_remove(&groups, group); + while (group->uuids) { + entry = group->uuids; + list_remove(&group->uuids, entry); + free(entry); + } + while (group->ips) { + entry = group->ips; + list_remove(&group->ips, entry); + free(entry); + } + free(group); + } + + *info = NULL; +} + + +static int +static_map_check(void *info, const char *src, const char *tgt_uuid, const char *tgt_name) +{ + struct perm_group *groups = (struct perm_group *)info; + struct perm_group *group; + struct perm_entry *left, *tmp; + int x, y, uuid = 0; + + if (!info) + return 1; /* no maps == wide open */ + + dbg_printf(99, "[server:map_check] map request: src: %s uuid: %s name: %s\n", src, tgt_uuid, tgt_name); + + uuid = is_uuid(src); + + list_for(&groups, group, x) { + left = NULL; + + if (uuid) { + list_for(&group->uuids, tmp, y) { + if (!strcasecmp(tmp->name, src)) { + left = tmp; + break; + } + } + } else { + list_for(&group->ips, tmp, y) { + if (!strcasecmp(tmp->name, src)) { + left = tmp; + break; + } + } + } + + if (!left) + continue; + + list_for(&group->uuids, tmp, y) { + if (!strcasecmp(tmp->name, tgt_uuid)) { + return 1; + } + /* useful only for list */ + if (tgt_name) { + if (!strcasecmp(tmp->name, tgt_name)) { + return 1; + } + } + } + } + + return 0; +} + + +static int +static_map_load(void *config_ptr, void **perm_info) +{ + config_object_t *config = config_ptr; + int group_idx = 0; + int entry_idx = 0; + int found; + char value[128]; + char buf[256]; + char buf2[512]; + struct perm_group *group = NULL, *groups = NULL; + struct perm_entry *entry = NULL; + + if (!perm_info) + return -1; + + do { + snprintf(buf, sizeof(buf)-1, "groups/group[%d]", ++group_idx); + + if (sc_get(config, buf, value, sizeof(value)) != 0) { + snprintf(buf2, sizeof(buf2)-1, "%s/@uuid", buf); + if (sc_get(config, buf2, value, sizeof(value)) != 0) { + snprintf(buf2, sizeof(buf2)-1, "%s/@ip", buf); + if (sc_get(config, buf2, value, + sizeof(value)) != 0) { + break; + } + } + snprintf(buf2, sizeof(buf2)-1, "%s/@name", buf); + if (sc_get(config, buf2, value, sizeof(value)) != 0) { + snprintf(value, sizeof(value), "unnamed-%d", + group_idx); + } + } + + group = malloc(sizeof(*group)); + assert(group); + memset(group, 0, sizeof(*group)); + strncpy(group->name, value, sizeof(group->name)); + dbg_printf(3, "Group: %s\n", value); + + found = 0; + entry_idx = 0; + do { + snprintf(buf2, sizeof(buf2)-1, "%s/@uuid[%d]", + buf, ++entry_idx); + + if (sc_get(config, buf2, value, sizeof(value)) != 0) { + break; + } + + ++found; + entry = malloc(sizeof(*entry)); + assert(entry); + memset(entry, 0, sizeof(*entry)); + strncpy(entry->name, value, sizeof(entry->name)); + dbg_printf(3, " - UUID Entry: %s\n", value); + + list_insert(&group->uuids, entry); + + } while (1); + + entry_idx = 0; + do { + snprintf(buf2, sizeof(buf2)-1, "%s/@ip[%d]", + buf, ++entry_idx); + + if (sc_get(config, buf2, value, sizeof(value)) != 0) { + break; + } + + ++found; + entry = malloc(sizeof(*entry)); + assert(entry); + memset(entry, 0, sizeof(*entry)); + strncpy(entry->name, value, sizeof(entry->name)); + dbg_printf(3, " - IP Entry: %s\n", value); + + list_insert(&group->ips, entry); + + } while (1); + + + if (!found) + free(group); + else + list_insert(&groups, group); + + } while (1); + + *perm_info = groups; + + return 0; +} + + +static const map_object_t static_map_obj = { + .load = static_map_load, + .check = static_map_check, + .cleanup = static_map_cleanup, + .info = NULL +}; + + +void * +map_init(void) +{ + map_object_t *o; + + o = malloc(sizeof(*o)); + if (!o) + return NULL; + memset(o, 0, sizeof(*o)); + memcpy(o, &static_map_obj, sizeof(*o)); + + return (void *)o; +} + + +void +map_release(void *c) +{ + map_object_t *o = (map_object_t *)c; + + static_map_cleanup(&o->info); + free(c); +} diff --git a/agents/virt/server/tcp.c b/agents/virt/server/tcp.c new file mode 100644 index 0000000..c1fb60c --- /dev/null +++ b/agents/virt/server/tcp.c @@ -0,0 +1,575 @@ +/* + Copyright Red Hat, Inc. 2006-2012 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ + +#include "config.h" + +#include <unistd.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <nss.h> +#include <sys/socket.h> +#include <netdb.h> + +/* Local includes */ +#include "xvm.h" +#include "simple_auth.h" +#include "options.h" +#include "mcast.h" +#include "tcp.h" +#include "tcp_listener.h" +#include "debug.h" +#include "fdops.h" +#include "list.h" +#include "simpleconfig.h" +#include "static_map.h" +#include "server_plugin.h" +#include "history.h" + +#define NAME "tcp" +#define TCP_VERSION "0.2" + +#define TCP_MAGIC 0xc3dff7a9 + +#define VALIDATE(info) \ +do {\ + if (!info || info->magic != TCP_MAGIC)\ + return -EINVAL;\ +} while(0) + +typedef struct _tcp_options { + char *key_file; + char *addr; + int family; + unsigned int port; + unsigned int hash; + unsigned int auth; + unsigned int flags; +} tcp_options; + + +typedef struct _tcp_info { + uint64_t magic; + void *priv; + map_object_t *map; + history_info_t *history; + char key[MAX_KEY_LEN]; + tcp_options args; + const fence_callbacks_t *cb; + ssize_t key_len; + int listen_sock; +} tcp_info; + + +struct tcp_hostlist_arg { + map_object_t *map; + const char *src; + int fd; +}; + + +/* + * See if we fenced this node recently (successfully) + * If so, ignore the request for a few seconds. + * + * We purge our history when the entries time out. + */ +static int +check_history(void *a, void *b) { + fence_req_t *old = a, *current = b; + + if (old->request == current->request && + old->seqno == current->seqno && + !strcasecmp((const char *)old->domain, + (const char *)current->domain)) { + return 1; + } + return 0; +} + +static int +tcp_hostlist(const char *vm_name, const char *vm_uuid, + int state, void *priv) +{ + struct tcp_hostlist_arg *arg = (struct tcp_hostlist_arg *)priv; + host_state_t hinfo; + struct timeval tv; + int ret; + + if (map_check2(arg->map, arg->src, vm_uuid, vm_name) == 0) { + /* if we don't have access to fence this VM, + * we should not see it in a hostlist either */ + return 0; + } + + strncpy((char *)hinfo.domain, vm_name, sizeof(hinfo.domain) - 1); + strncpy((char *)hinfo.uuid, vm_uuid, sizeof(hinfo.uuid) - 1); + hinfo.state = state; + + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = _write_retry(arg->fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + + +static int +tcp_hostlist_begin(int fd) +{ + struct timeval tv; + char val = (char)RESP_HOSTLIST; + + tv.tv_sec = 1; + tv.tv_usec = 0; + return _write_retry(fd, &val, 1, &tv); +} + + +static int +tcp_hostlist_end(int fd) +{ + host_state_t hinfo; + struct timeval tv; + int ret; + + printf("Sending terminator packet\n"); + + memset(&hinfo, 0, sizeof(hinfo)); + + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = _write_retry(fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + +static socklen_t +sockaddr_len(const struct sockaddr_storage *ss) +{ + if (ss->ss_family == AF_INET) { + return sizeof(struct sockaddr_in); + } else { + return sizeof(struct sockaddr_in6); + } +} + +static int +do_fence_request_tcp(int fd, struct sockaddr_storage *ss, socklen_t sock_len, fence_req_t *req, tcp_info *info) +{ + char ip_addr_src[1024]; + char response = 1; + struct tcp_hostlist_arg arg; + int ret; + + /* Noops if auth == AUTH_NONE */ + if (sock_response(fd, info->args.auth, info->key, info->key_len, 10) <= 0) { + printf("Failed to respond to challenge\n"); + close(fd); + return -1; + } + + ret = sock_challenge(fd, info->args.auth, info->key, info->key_len, 10); + if (ret <= 0) { + printf("Remote failed challenge\n"); + close(fd); + return -1; + } + + + if (getnameinfo((struct sockaddr *)ss, sockaddr_len(ss), + ip_addr_src, sizeof(ip_addr_src), + NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV) < 0) { + printf("Unable to resolve!\n"); + close(fd); + return -1; + } + + dbg_printf(2, "Request %d seqno %d src %s target %s\n", + req->request, req->seqno, ip_addr_src, req->domain); + + switch(req->request) { + case FENCE_NULL: + response = info->cb->null((char *)req->domain, info->priv); + break; + case FENCE_ON: + if (map_check(info->map, ip_addr_src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->on((char *)req->domain, ip_addr_src, + req->seqno, info->priv); + break; + case FENCE_OFF: + if (map_check(info->map, ip_addr_src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->off((char *)req->domain, ip_addr_src, + req->seqno, info->priv); + break; + case FENCE_REBOOT: + if (map_check(info->map, ip_addr_src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->reboot((char *)req->domain, ip_addr_src, + req->seqno, info->priv); + break; + case FENCE_STATUS: + if (map_check(info->map, ip_addr_src, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->status((char *)req->domain, info->priv); + break; + case FENCE_DEVSTATUS: + response = info->cb->devstatus(info->priv); + break; + case FENCE_HOSTLIST: + arg.map = info->map; + arg.src = ip_addr_src; + arg.fd = fd; + + tcp_hostlist_begin(arg.fd); + response = info->cb->hostlist(tcp_hostlist, &arg, + info->priv); + tcp_hostlist_end(arg.fd); + break; + } + + dbg_printf(3, "Sending response to caller...\n"); + if (_write_retry(fd, &response, 1, NULL) < 0) { + perror("write"); + } + + history_record(info->history, req); + + if (fd != -1) + close(fd); + + return 1; +} + + +static int +tcp_dispatch(listener_context_t c, struct timeval *timeout) +{ + tcp_info *info; + fence_req_t data; + fd_set rfds; + int n; + int client_fd; + int ret; + struct timeval tv; + struct sockaddr_storage ss; + socklen_t sock_len = sizeof(ss); + + if (timeout != NULL) + memcpy(&tv, timeout, sizeof(tv)); + else { + tv.tv_sec = 1; + tv.tv_usec = 0; + } + + info = (tcp_info *)c; + VALIDATE(info); + + FD_ZERO(&rfds); + FD_SET(info->listen_sock, &rfds); + + n = select(info->listen_sock + 1, &rfds, NULL, NULL, timeout); + if (n <= 0) { + if (errno == EINTR || errno == EAGAIN) + n = 0; + else + dbg_printf(2, "select: %s\n", strerror(errno)); + return n; + } + + client_fd = accept(info->listen_sock, (struct sockaddr *)&ss, &sock_len); + if (client_fd < 0) { + perror("accept"); + return -1; + } + + dbg_printf(3, "Accepted client...\n"); + + ret = _read_retry(client_fd, &data, sizeof(data), &tv); + if (ret != sizeof(data)) { + dbg_printf(3, "Invalid request (read %d bytes)\n", ret); + close(client_fd); + return 0; + } + + swab_fence_req_t(&data); + + if (!verify_request(&data, info->args.hash, info->key, + info->key_len)) { + printf("Key mismatch; dropping client\n"); + close(client_fd); + return 0; + } + + dbg_printf(3, "Request %d seqno %d domain %s\n", + data.request, data.seqno, data.domain); + + if (history_check(info->history, &data) == 1) { + printf("We just did this request; dropping client\n"); + close(client_fd); + return 0; + } + + switch(info->args.auth) { + case AUTH_NONE: + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + printf("Plain TCP request\n"); + do_fence_request_tcp(client_fd, &ss, sock_len, &data, info); + break; + default: + printf("XXX Unhandled authentication\n"); + } + + return 0; +} + + +static int +tcp_config(config_object_t *config, tcp_options *args) +{ + char value[1024]; + int errors = 0; + + if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0) + dset(atoi(value)); + + if (sc_get(config, "listeners/tcp/@key_file", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for key_file\n", value); + args->key_file = strdup(value); + } else { + args->key_file = strdup(DEFAULT_KEY_FILE); + if (!args->key_file) { + dbg_printf(1, "Failed to allocate memory\n"); + return -1; + } + } + + args->hash = DEFAULT_HASH; + if (sc_get(config, "listeners/tcp/@hash", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for hash\n", value); + if (!strcasecmp(value, "none")) { + args->hash = HASH_NONE; + } else if (!strcasecmp(value, "sha1")) { + args->hash = HASH_SHA1; + } else if (!strcasecmp(value, "sha256")) { + args->hash = HASH_SHA256; + } else if (!strcasecmp(value, "sha512")) { + args->hash = HASH_SHA512; + } else { + dbg_printf(1, "Unsupported hash: %s\n", value); + ++errors; + } + } + + args->auth = DEFAULT_AUTH; + if (sc_get(config, "listeners/tcp/@auth", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for auth\n", value); + if (!strcasecmp(value, "none")) { + args->hash = AUTH_NONE; + } else if (!strcasecmp(value, "sha1")) { + args->hash = AUTH_SHA1; + } else if (!strcasecmp(value, "sha256")) { + args->hash = AUTH_SHA256; + } else if (!strcasecmp(value, "sha512")) { + args->hash = AUTH_SHA512; + } else { + dbg_printf(1, "Unsupported auth: %s\n", value); + ++errors; + } + } + + args->family = PF_INET; + if (sc_get(config, "listeners/tcp/@family", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for family\n", value); + if (!strcasecmp(value, "ipv4")) { + args->family = PF_INET; + } else if (!strcasecmp(value, "ipv6")) { + args->family = PF_INET6; + } else { + dbg_printf(1, "Unsupported family: %s\n", value); + ++errors; + } + } + + if (sc_get(config, "listeners/tcp/@address", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for address\n", value); + args->addr = strdup(value); + } else { + if (args->family == PF_INET) { + args->addr = strdup(IPV4_TCP_ADDR_DEFAULT); + } else { + args->addr = strdup(IPV6_TCP_ADDR_DEFAULT); + } + } + if (!args->addr) { + return -1; + } + + args->port = DEFAULT_MCAST_PORT; + if (sc_get(config, "listeners/tcp/@port", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for port\n", value); + args->port = atoi(value); + if (args->port <= 0) { + dbg_printf(1, "Invalid port: %s\n", value); + ++errors; + } + } + + return errors; +} + + +static int +tcp_init(listener_context_t *c, const fence_callbacks_t *cb, + config_object_t *config, map_object_t *map, void *priv) +{ + tcp_info *info; + int listen_sock, ret; + + /* Initialize NSS; required to do hashing, as silly as that + sounds... */ + if (NSS_NoDB_Init(NULL) != SECSuccess) { + printf("Could not initialize NSS\n"); + return 1; + } + + info = calloc(1, sizeof(*info)); + if (!info) + return -1; + + info->priv = priv; + info->cb = cb; + info->map = map; + + ret = tcp_config(config, &info->args); + if (ret < 0) + perror("tcp_config"); + else if (ret > 0) + printf("%d errors found during configuration\n",ret); + + if (ret != 0) { + if (info->args.key_file) + free(info->args.key_file); + if (info->args.addr) + free(info->args.addr); + free(info); + return -1; + } + + if (info->args.auth != AUTH_NONE || info->args.hash != HASH_NONE) { + info->key_len = read_key_file(info->args.key_file, + info->key, sizeof(info->key)); + if (info->key_len < 0) { + printf("Could not read %s; operating without " + "authentication\n", info->args.key_file); + info->args.auth = AUTH_NONE; + info->args.hash = HASH_NONE; + info->key_len = 0; + } + } + + if (info->args.family == PF_INET) { + listen_sock = ipv4_listen(info->args.addr, info->args.port, 10); + } else { + listen_sock = ipv6_listen(info->args.addr, info->args.port, 10); + } + + if (listen_sock < 0) { + printf("Could not set up listen socket\n"); + if (info->args.key_file) + free(info->args.key_file); + if (info->args.addr) + free(info->args.addr); + free(info); + return -1; + } + + info->magic = TCP_MAGIC; + info->listen_sock = listen_sock; + info->history = history_init(check_history, 10, sizeof(fence_req_t)); + *c = (listener_context_t)info; + return 0; +} + + +static int +tcp_shutdown(listener_context_t c) +{ + tcp_info *info = (tcp_info *)c; + + VALIDATE(info); + info->magic = 0; + history_wipe(info->history); + free(info->history); + free(info->args.key_file); + free(info->args.addr); + close(info->listen_sock); + free(info); + + return 0; +} + + +static listener_plugin_t tcp_plugin = { + .name = NAME, + .version = TCP_VERSION, + .init = tcp_init, + .dispatch = tcp_dispatch, + .cleanup = tcp_shutdown, +}; + +double +LISTENER_VER_SYM(void) +{ + return PLUGIN_VERSION_LISTENER; +} + +const listener_plugin_t * +LISTENER_INFO_SYM(void) +{ + return &tcp_plugin; +} diff --git a/agents/virt/server/uuid-test.c b/agents/virt/server/uuid-test.c new file mode 100644 index 0000000..3116ef9 --- /dev/null +++ b/agents/virt/server/uuid-test.c @@ -0,0 +1,66 @@ +#include "config.h" + +#include <uuid/uuid.h> +#include <errno.h> +#include <string.h> + +#include "uuid-test.h" + +int +is_uuid(const char *value) +{ + uuid_t id; + char test_value[37]; + + if (strlen(value) < 36) { + return 0; + } + + memset(id, 0, sizeof(uuid_t)); + + if (uuid_is_null(id) < 0) { + errno = EINVAL; + return -1; + } + + if (uuid_parse(value, id) < 0) { + return 0; + } + + memset(test_value, 0, sizeof(test_value)); + uuid_unparse(id, test_value); + + if (strcasecmp(value, test_value)) { + return 0; + } + + return 1; +} + +#ifdef STANDALONE +#include <stdio.h> + +int +main(int argc, char **argv) +{ + int ret; + + if (argc < 2) { + printf("Usage: uuidtest <value>\n"); + return 1; + } + + ret = is_uuid(argv[1]); + if (ret == 0) { + printf("%s is NOT a uuid\n", argv[1]); + } else if (ret == 1) { + printf("%s is a uuid\n", argv[1]); + } else { + printf("Error: %s\n", strerror(errno)); + return 1; + } + + return 0; +} + +#endif diff --git a/agents/virt/server/uuid-test.h b/agents/virt/server/uuid-test.h new file mode 100644 index 0000000..164fec7 --- /dev/null +++ b/agents/virt/server/uuid-test.h @@ -0,0 +1,14 @@ +#ifndef __UUID_TEST_H +#define __UUID_TEST_H + +#ifdef __cplusplus +extern "C" { +#endif + +int is_uuid(const char *value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/agents/virt/server/virt-serial.c b/agents/virt/server/virt-serial.c new file mode 100644 index 0000000..6b369bc --- /dev/null +++ b/agents/virt/server/virt-serial.c @@ -0,0 +1,444 @@ +// #include <config.h> + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <pthread.h> +#include <unistd.h> +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/poll.h> +#include <libvirt/libvirt.h> + +#include <libxml/xmlreader.h> + +#include "simpleconfig.h" +#include "debug.h" + +#define DEBUG0(fmt) dbg_printf(5,"%s:%d :: " fmt "\n", \ + __func__, __LINE__) +#define DEBUG1(fmt, ...) dbg_printf(5, "%s:%d: " fmt "\n", \ + __func__, __LINE__, __VA_ARGS__) + +#include "serial.h" + +#define STREQ(a,b) (strcmp((a),(b)) == 0) + +static pthread_t event_tid = 0; +static int run = 0; + +/* Prototypes */ +const char *eventToString(int event); +int myDomainEventCallback1(virConnectPtr conn, virDomainPtr dom, + int event, int detail, void *opaque); + +void usage(const char *pname); + +struct domain_info { + virDomainPtr dom; + virDomainEventType event; +}; + +static int +is_in_directory(const char *dir, const char *pathspec) +{ + char *last_slash = NULL; + size_t dirlen, pathlen; + + if (!dir || !pathspec) + return 0; + + dirlen = strlen(dir); + pathlen = strlen(pathspec); + + /* + printf("dirlen = %d pathlen = %d\n", + dirlen, pathlen); + */ + + /* chop off trailing slashes */ + while (dirlen && dir[dirlen-1]=='/') + --dirlen; + + /* chop off leading slashes */ + while (dirlen && dir[0] == '/') { + ++dir; + --dirlen; + } + + /* chop off leading slashes */ + while (pathlen && pathspec[0] == '/') { + ++pathspec; + --pathlen; + } + + if (!dirlen || !pathlen) + return 0; + + if (pathlen <= dirlen) + return 0; + + last_slash = strrchr(pathspec, '/'); + + if (!last_slash) + return 0; + + while (*last_slash == '/' && last_slash > pathspec) + --last_slash; + + if (last_slash == pathspec) + return 0; + + pathlen = last_slash - pathspec + 1; + /*printf("real dirlen = %d real pathlen = %d\n", + dirlen, pathlen);*/ + if (pathlen != dirlen) + return 0; + + /* todo - intelligently skip multiple slashes mid-path */ + return !strncmp(dir, pathspec, dirlen); +} + + +static int +domainStarted(virDomainPtr mojaDomain, const char *path, int mode) +{ + char dom_uuid[42]; + char *xml; + xmlDocPtr doc; + xmlNodePtr cur, devices, child, serial; + xmlAttrPtr attr, attr_mode, attr_path; + + if (!mojaDomain) + return -1; + + virDomainGetUUIDString(mojaDomain, dom_uuid); + + xml = virDomainGetXMLDesc(mojaDomain, 0); + // printf("%s\n", xml); + // @todo: free mojaDomain + + // parseXML output + doc = xmlParseMemory(xml, strlen(xml)); + xmlFree(xml); + cur = xmlDocGetRootElement(doc); + + if (cur == NULL) { + fprintf(stderr, "Empty doc\n"); + xmlFreeDoc(doc); + return -1; + } + + if (xmlStrcmp(cur->name, (const xmlChar *) "domain")) { + fprintf(stderr, "no domain?\n"); + xmlFreeDoc(doc); + return -1; + } + + devices = cur->xmlChildrenNode; + for (devices = cur->xmlChildrenNode; devices != NULL; + devices = devices->next) { + if (xmlStrcmp(devices->name, (const xmlChar *) "devices")) { + continue; + } + + for (child = devices->xmlChildrenNode; child != NULL; + child = child->next) { + + if ((!mode && xmlStrcmp(child->name, (const xmlChar *) "serial")) || + (mode && xmlStrcmp(child->name, (const xmlChar *) "channel"))) { + continue; + } + + attr = xmlHasProp(child, (const xmlChar *)"type"); + if (attr == NULL) + continue; + + if (xmlStrcmp(attr->children->content, + (const xmlChar *) "unix")) { + continue; + } + + for (serial = child->xmlChildrenNode; serial != NULL; + serial = serial->next) { + if (xmlStrcmp(serial->name, + (const xmlChar *) "source")) { + continue; + } + + attr_mode = xmlHasProp(serial, (const xmlChar *)"mode"); + attr_path = xmlHasProp(serial, (const xmlChar *)"path"); + + if (!attr_path || !attr_mode) + continue; + + if (xmlStrcmp(attr_mode->children->content, + (const xmlChar *) "bind")) + continue; + + if (path && !is_in_directory(path, (const char *) + attr_path->children->content)) + continue; + + domain_sock_setup(dom_uuid, (const char *) + attr_path->children->content); + } + } + } + + xmlFreeDoc(doc); + return 0; +} + +static int +registerExisting(virConnectPtr vp, const char *path, int mode) +{ + int *d_ids = NULL; + int d_count, x; + virDomainPtr dom; + virDomainInfo d_info; + + errno = EINVAL; + if (!vp) + return -1; + + d_count = virConnectNumOfDomains(vp); + if (d_count <= 0) { + if (d_count == 0) { + /* Successful, but no domains running */ + errno = 0; + return 0; + } + goto out_fail; + } + + d_ids = malloc(sizeof (int) * d_count); + if (!d_ids) + goto out_fail; + + if (virConnectListDomains(vp, d_ids, d_count) < 0) + goto out_fail; + + /* Ok, we have the domain IDs - let's get their names and states */ + for (x = 0; x < d_count; x++) { + dom = virDomainLookupByID(vp, d_ids[x]); + if (!dom) { + /* XXX doom */ + goto out_fail; + } + + if (virDomainGetInfo(dom, &d_info) < 0) { + /* XXX no info for the domain?!! */ + virDomainFree(dom); + goto out_fail; + } + + if (d_info.state != VIR_DOMAIN_SHUTOFF && + d_info.state != VIR_DOMAIN_CRASHED) + domainStarted(dom, path, mode); + + virDomainFree(dom); + } + + out_fail: + free(d_ids); + return 0; +} + +static int +domainStopped(virDomainPtr mojaDomain) +{ + char dom_uuid[42]; + + if (!mojaDomain) + return -1; + + virDomainGetUUIDString(mojaDomain, dom_uuid); + domain_sock_close(dom_uuid); + + return 0; +} + + +struct event_args { + char *uri; + char *path; + int mode; + int wake_fd; +}; + +static void +connectClose(virConnectPtr conn ATTRIBUTE_UNUSED, + int reason, + void *opaque ATTRIBUTE_UNUSED) +{ + switch (reason) { + case VIR_CONNECT_CLOSE_REASON_ERROR: + dbg_printf(2, "Connection closed due to I/O error\n"); + break; + case VIR_CONNECT_CLOSE_REASON_EOF: + dbg_printf(2, "Connection closed due to end of file\n"); + break; + case VIR_CONNECT_CLOSE_REASON_KEEPALIVE: + dbg_printf(2, "Connection closed due to keepalive timeout\n"); + break; + case VIR_CONNECT_CLOSE_REASON_CLIENT: + dbg_printf(2, "Connection closed due to client request\n"); + break; + default: + dbg_printf(2, "Connection closed due to unknown reason\n"); + break; + }; + run = 0; +} + +int +myDomainEventCallback1(virConnectPtr conn, + virDomainPtr dom, int event, int detail, void *opaque) +{ + struct event_args *args = (struct event_args *)opaque; + + if (event == VIR_DOMAIN_EVENT_STARTED || + event == VIR_DOMAIN_EVENT_STOPPED) { + virDomainRef(dom); + if (event == VIR_DOMAIN_EVENT_STARTED) { + domainStarted(dom, args->path, args->mode); + virDomainFree(dom); + if (write(args->wake_fd, "x", 1) != 1) { + dbg_printf(3, "Unable to wake up thread\n"); + } + } else if (event == VIR_DOMAIN_EVENT_STOPPED) { + domainStopped(dom); + virDomainFree(dom); + } + } + + return 0; +} + + +static void * +event_thread(void *arg) +{ + struct event_args *args = (struct event_args *)arg; + virConnectPtr dconn = NULL; + int callback1ret = -1; + + dbg_printf(3, "Libvirt event listener starting\n"); + if (args->uri) + dbg_printf(3," * URI: %s\n", args->uri); + if (args->path) + dbg_printf(3," * Socket path: %s\n", args->path); + dbg_printf(3," * Mode: %s\n", args->mode ? "VMChannel" : "Serial"); + + if (virEventRegisterDefaultImpl() < 0) { + dbg_printf(1, "Failed to register default event impl\n"); + goto out; + } + + dconn = virConnectOpen(args->uri); + if (!dconn) { + dbg_printf(1, "Error connecting to libvirt\n"); + goto out; + } + + virConnectRegisterCloseCallback(dconn, connectClose, NULL, NULL); + + DEBUG0("Registering domain event cbs"); + + registerExisting(dconn, args->path, args->mode); + + callback1ret = + virConnectDomainEventRegister(dconn, myDomainEventCallback1, arg, NULL); + + if (callback1ret != -1) { + if (virConnectSetKeepAlive(dconn, 5, 5) < 0) { + dbg_printf(1, "Failed to start keepalive protocol\n"); + run = 0; + } + while (run) { + if (virEventRunDefaultImpl() < 0) { + dbg_printf(1, "RunDefaultImpl Failed\n"); + } + } + + DEBUG0("Deregistering event handlers"); + virConnectDomainEventDeregister(dconn, myDomainEventCallback1); + } + + DEBUG0("Closing connection"); + if (dconn && virConnectClose(dconn) < 0) { + dbg_printf(1, "error closing libvirt connection\n"); + } + +out: + free(args->uri); + free(args->path); + free(args); + return NULL; +} + + +int +start_event_listener(const char *uri, const char *path, int mode, int *wake_fd) +{ + struct event_args *args = NULL; + int wake_pipe[2]; + + virInitialize(); + + args = malloc(sizeof(*args)); + if (!args) + return -1; + memset(args, 0, sizeof(*args)); + + if (pipe2(wake_pipe, O_CLOEXEC) < 0) { + goto out_fail; + } + + if (uri) { + args->uri = strdup(uri); + if (args->uri == NULL) + goto out_fail; + } + + if (path) { + args->path = strdup(path); + if (args->path == NULL) + goto out_fail; + } + + args->mode = mode; + //args->p_tid = pthread_self(); + *wake_fd = wake_pipe[0]; + args->wake_fd = wake_pipe[1]; + + run = 1; + + return pthread_create(&event_tid, NULL, event_thread, args); + +out_fail: + free(args->uri); + free(args->path); + free(args); + return -1; +} + + +int +stop_event_listener(void) +{ + run = 0; + //pthread_cancel(event_tid); + pthread_join(event_tid, NULL); + event_tid = 0; + + return 0; +} + + diff --git a/agents/virt/server/virt-sockets.c b/agents/virt/server/virt-sockets.c new file mode 100644 index 0000000..7f36f62 --- /dev/null +++ b/agents/virt/server/virt-sockets.c @@ -0,0 +1,242 @@ +#include "config.h" + +#include <pthread.h> +#include <unistd.h> +#include <stdio.h> +#include <list.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> + +#include "serial.h" +#include "debug.h" +#include "simpleconfig.h" + +struct socket_list { + list_head(); + char *domain_name; + char *socket_path; + int socket_fd; +}; + +static struct socket_list *socks = NULL; +static pthread_mutex_t sock_list_mutex = PTHREAD_MUTEX_INITIALIZER; + + +static int +connect_nb(int fd, struct sockaddr *dest, socklen_t len, int timeout) +{ + int ret, flags, err; + unsigned l; + fd_set rfds, wfds; + struct timeval tv; + + /* + Set up non-blocking connect + */ + flags = fcntl(fd, F_GETFL, 0); + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + return -1; + } + + ret = connect(fd, dest, len); + + if ((ret < 0) && (errno != EINPROGRESS)) + return -1; + + if (ret == 0) + goto done; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + FD_ZERO(&wfds); + FD_SET(fd, &wfds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + if (select(fd + 1, &rfds, &wfds, NULL, &tv) == 0) { + errno = ETIMEDOUT; + return -1; + } + + if (!FD_ISSET(fd, &rfds) && !FD_ISSET(fd, &wfds)) { + errno = EIO; + return -1; + } + + l = sizeof(err); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, + (void *)&err, &l) < 0) { + return -1; + } + + if (err != 0) { + errno = err; + return -1; + } + +done: + if (fcntl(fd, F_SETFL, flags) < 0) { + return -1; + } + return 0; +} + + +int +domain_sock_setup(const char *domain, const char *socket_path) +{ + struct sockaddr_un *sun = NULL; + struct socket_list *node = NULL; + socklen_t sun_len; + int sock = -1; + + sun_len = sizeof(*sun) + strlen(socket_path) + 1; + sun = malloc(sun_len); + if (!sun) + return -1; + + memset((char *)sun, 0, sun_len); + sun->sun_family = PF_LOCAL; + strncpy(sun->sun_path, socket_path, sizeof(sun->sun_path) - 1); + + sock = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) + goto out_fail; + + if (connect_nb(sock, (struct sockaddr *)sun, SUN_LEN(sun), 3) < 0) + goto out_fail; + + free(sun); + sun = NULL; + + node = calloc(1, sizeof(*node)); + if (!node) + goto out_fail; + + node->domain_name = strdup(domain); + if (!node->domain_name) + goto out_fail; + + node->socket_path = strdup(socket_path); + if (!node->socket_path) + goto out_fail; + + node->socket_fd = sock; + + pthread_mutex_lock(&sock_list_mutex); + list_insert(&socks, node); + pthread_mutex_unlock(&sock_list_mutex); + + dbg_printf(3, "Registered %s on %d\n", domain, sock); + return 0; + +out_fail: + if (node) { + free(node->domain_name); + if (node->socket_path) + free(node->socket_path); + free(node); + } + free(sun); + if (sock >= 0) + close(sock); + return -1; +} + + +int +domain_sock_close(const char *domain) +{ + struct socket_list *node = NULL; + struct socket_list *dead = NULL; + int x; + + pthread_mutex_lock(&sock_list_mutex); + list_for(&socks, node, x) { + if (!strcasecmp(domain, node->domain_name)) { + list_remove(&socks, node); + dead = node; + break; + } + } + pthread_mutex_unlock(&sock_list_mutex); + + if (dead) { + dbg_printf(3, "Unregistered %s, fd%d\n", + dead->domain_name, + dead->socket_fd); + close(dead->socket_fd); + free(dead->domain_name); + free(dead->socket_path); + free(dead); + } + + return 0; +} + + +int +domain_sock_fdset(fd_set *fds, int *max) +{ + struct socket_list *node = NULL; + int x = 0, _max = -1; + + pthread_mutex_lock(&sock_list_mutex); + list_for(&socks, node, x) { + FD_SET(node->socket_fd, fds); + if (node->socket_fd > _max) + _max = node->socket_fd; + } + pthread_mutex_unlock(&sock_list_mutex); + + if (max) + *max = _max; + + return x; +} + + +int +domain_sock_name(int fd, char *outbuf, size_t buflen) +{ + struct socket_list *node = NULL; + int ret = 1, x = 0; + + pthread_mutex_lock(&sock_list_mutex); + list_for(&socks, node, x) { + if (node->socket_fd == fd) { + snprintf(outbuf, buflen, "%s", node->domain_name); + ret = 0; + break; + } + } + pthread_mutex_unlock(&sock_list_mutex); + + return ret; +} + + +int +domain_sock_cleanup(void) +{ + struct socket_list *dead= NULL; + + pthread_mutex_lock(&sock_list_mutex); + while(socks) { + dead = socks; + list_remove(&socks, dead); + close(dead->socket_fd); + free(dead->domain_name); + free(dead->socket_path); + free(dead); + } + pthread_mutex_unlock(&sock_list_mutex); + + return 0; +} + diff --git a/agents/virt/server/virt.c b/agents/virt/server/virt.c new file mode 100644 index 0000000..d4c94e9 --- /dev/null +++ b/agents/virt/server/virt.c @@ -0,0 +1,630 @@ +/* + Copyright Red Hat, Inc. 2006-2017 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <stdlib.h> +#include <libvirt/libvirt.h> +#include <string.h> +#include <malloc.h> +#include <stdint.h> +#include <errno.h> +#include <syslog.h> + +#include "debug.h" +#include "uuid-test.h" +#include "virt.h" + +static int +_compare_virt(const void *_left, const void *_right) +{ + virt_state_t *left = (virt_state_t *)_left, + *right = (virt_state_t *)_right; + + return strcasecmp(left->v_name, right->v_name); +} + + +static void +_free_dom_list(virDomainPtr *dom_list, int len) { + int x; + + if (!dom_list || len <= 0) + return; + for (x = 0 ; x < len; x++) + virDomainFree(dom_list[x]); + + free(dom_list); +} + + +virt_list_t *vl_get(virConnectPtr *vp, int vp_count, int my_id) +{ + virt_list_t *vl = NULL; + int d_count = 0; + int i; + + errno = EINVAL; + if (!vp || vp_count < 1) + return NULL; + + for (i = 0 ; i < vp_count ; i++) { + int x; + virDomainPtr *dom_list; + virt_list_t *new_vl; + + int ret = virConnectListAllDomains(vp[i], &dom_list, 0); + if (ret == 0) + continue; + + if (ret < 0) { + int saved_errno = errno; + dbg_printf(2, "Error: virConnectListAllDomains: %d %d\n", + ret, saved_errno); + if (vl) + free(vl); + errno = saved_errno; + return NULL; + } + + d_count += ret; + new_vl = realloc(vl, sizeof(uint32_t) + sizeof(virt_state_t) * d_count); + if (!new_vl) { + _free_dom_list(dom_list, ret); + free(vl); + return NULL; + } + vl = new_vl; + vl->vm_count = d_count; + + /* Ok, we have the domain IDs - let's get their names and states */ + for (x = 0; x < ret; x++) { + char *d_name; + virDomainInfo d_info; + char d_uuid[MAX_DOMAINNAME_LENGTH]; + virDomainPtr dom = dom_list[x]; + + if (!(d_name = (char *)virDomainGetName(dom))) { + _free_dom_list(dom_list, ret); + free(vl); + return NULL; + } + + if (virDomainGetUUIDString(dom, d_uuid) != 0) { + _free_dom_list(dom_list, ret); + free(vl); + return NULL; + } + + if (virDomainGetInfo(dom, &d_info) < 0) { + _free_dom_list(dom_list, ret); + free(vl); + return NULL; + } + + /* Store the name & state */ + strncpy(vl->vm_states[x].v_name, d_name, MAX_DOMAINNAME_LENGTH); + strncpy(vl->vm_states[x].v_uuid, d_uuid, MAX_DOMAINNAME_LENGTH); + vl->vm_states[x].v_state.s_state = d_info.state; + vl->vm_states[x].v_state.s_owner = my_id; + } + + _free_dom_list(dom_list, ret); + } + /* No domains found */ + if (!vl) + return NULL; + + /* We have all the locally running domains & states now */ + /* Sort */ + qsort(&vl->vm_states[0], vl->vm_count, sizeof(vl->vm_states[0]), + _compare_virt); + return vl; +} + +int +vl_add(virt_list_t **vl, virt_state_t *vm) { + virt_list_t *new_vl; + size_t oldlen; + size_t newlen; + + if (!vl) + return -1; + + if (!*vl) { + *vl = malloc(sizeof(uint32_t) + sizeof(virt_state_t)); + if (!*vl) + return -1; + (*vl)->vm_count = 1; + memcpy(&(*vl)->vm_states[0], vm, sizeof(virt_state_t)); + return 0; + } + + oldlen = sizeof(uint32_t) + sizeof(virt_state_t) * (*vl)->vm_count; + newlen = oldlen + sizeof(virt_state_t); + + new_vl = malloc(newlen); + if (!new_vl) + return -1; + + memcpy(new_vl, *vl, oldlen); + memcpy(&new_vl->vm_states[(*vl)->vm_count], vm, sizeof(virt_state_t)); + new_vl->vm_count++; + + free(*vl); + *vl = new_vl; + return 0; +} + +int vl_remove_by_owner(virt_list_t **vl, uint32_t owner) { + int i; + int removed = 0; + virt_list_t *new_vl; + + if (!vl || !*vl) + return 0; + + for (i = 0 ; i < (*vl)->vm_count ; i++) { + if ((*vl)->vm_states[i].v_state.s_owner == owner) { + dbg_printf(2, "Removing %s\n", (*vl)->vm_states[i].v_name); + memset(&(*vl)->vm_states[i].v_state, 0, + sizeof((*vl)->vm_states[i].v_state)); + (*vl)->vm_states[i].v_name[0] = 0xff; + (*vl)->vm_states[i].v_uuid[0] = 0xff; + removed++; + } + } + + if (!removed) + return 0; + + qsort(&(*vl)->vm_states[0], (*vl)->vm_count, sizeof((*vl)->vm_states[0]), + _compare_virt); + (*vl)->vm_count -= removed; + + new_vl = realloc(*vl, sizeof(uint32_t) + (sizeof(virt_state_t) * ((*vl)->vm_count))); + if (new_vl) + *vl = new_vl; + return removed; +} + + +int +vl_update(virt_list_t **vl, virt_state_t *vm) { + virt_state_t *v = NULL; + + if (!vl) + return -1; + + if (!*vl) + return vl_add(vl, vm); + + if (strlen(vm->v_uuid) > 0) + v = vl_find_uuid(*vl, vm->v_uuid); + + if (v == NULL && strlen(vm->v_name) > 0) + v = vl_find_name(*vl, vm->v_name); + + if (v == NULL) { + dbg_printf(2, "Adding new entry for VM %s\n", vm->v_name); + vl_add(vl, vm); + } else { + dbg_printf(2, "Updating entry for VM %s\n", vm->v_name); + memcpy(&v->v_state, &vm->v_state, sizeof(v->v_state)); + } + + return 0; +} + + +void +vl_print(virt_list_t *vl) +{ + int x; + + printf("%-24.24s %-36.36s %-5.5s %-5.5s\n", "Domain", "UUID", + "Owner", "State"); + printf("%-24.24s %-36.36s %-5.5s %-5.5s\n", "------", "----", + "-----", "-----"); + + if (!vl || !vl->vm_count) + return; + + for (x = 0; x < vl->vm_count; x++) { + printf("%-24.24s %-36.36s %-5.5d %-5.5d\n", + vl->vm_states[x].v_name, + vl->vm_states[x].v_uuid, + vl->vm_states[x].v_state.s_owner, + vl->vm_states[x].v_state.s_state); + } +} + + +virt_state_t * +vl_find_name(virt_list_t *vl, const char *name) +{ + int x; + + if (!vl || !name || !vl->vm_count) + return NULL; + + for (x = 0; x < vl->vm_count; x++) { + if (!strcasecmp(vl->vm_states[x].v_name, name)) + return &vl->vm_states[x]; + } + + return NULL; +} + + +virt_state_t * +vl_find_uuid(virt_list_t *vl, const char *uuid) +{ + int x; + + if (!vl || !uuid || !vl->vm_count) + return NULL; + + for (x = 0; x < vl->vm_count; x++) { + if (!strcasecmp(vl->vm_states[x].v_uuid, uuid)) + return &vl->vm_states[x]; + } + + return NULL; +} + + +void +vl_free(virt_list_t *old) +{ + free(old); +} + + +static inline int +wait_domain(const char *vm_name, virConnectPtr vp, int timeout) +{ + int tries = 0; + int response = 1; + int ret; + virDomainPtr vdp; + virDomainInfo vdi; + int uuid_check; + + uuid_check = is_uuid(vm_name); + + if (uuid_check) { + vdp = virDomainLookupByUUIDString(vp, (const char *)vm_name); + } else { + vdp = virDomainLookupByName(vp, vm_name); + } + if (!vdp) + return 0; + + /* Check domain liveliness. If the domain is still here, + we return failure, and the client must then retry */ + /* XXX On the xen 3.0.4 API, we will be able to guarantee + synchronous virDomainDestroy, so this check will not + be necessary */ + do { + if (++tries > timeout) + break; + + sleep(1); + if (uuid_check) { + vdp = virDomainLookupByUUIDString(vp, (const char *)vm_name); + } else { + vdp = virDomainLookupByName(vp, vm_name); + } + if (!vdp) { + dbg_printf(2, "Domain no longer exists\n"); + response = 0; + break; + } + + memset(&vdi, 0, sizeof(vdi)); + ret = virDomainGetInfo(vdp, &vdi); + virDomainFree(vdp); + if (ret < 0) + continue; + + if (vdi.state == VIR_DOMAIN_SHUTOFF) { + dbg_printf(2, "Domain has been shut off\n"); + response = 0; + break; + } + + dbg_printf(4, "Domain still exists (state %d) after %d seconds\n", + vdi.state, tries); + } while (1); + + return response; +} + + +int +vm_off(virConnectPtr *vp, int vp_count, const char *vm_name) +{ + virDomainPtr vdp = NULL; + virDomainInfo vdi; + virDomainPtr (*virt_lookup_fn)(virConnectPtr, const char *); + int ret = -1; + int i; + + if (is_uuid(vm_name)) + virt_lookup_fn = virDomainLookupByUUIDString; + else + virt_lookup_fn = virDomainLookupByName; + + for (i = 0 ; i < vp_count ; i++) { + vdp = virt_lookup_fn(vp[i], vm_name); + if (vdp) + break; + } + + if (!vdp) { + dbg_printf(2, "[virt:OFF] Domain %s does not exist\n", vm_name); + return 1; + } + + if (virDomainGetInfo(vdp, &vdi) == 0 && vdi.state == VIR_DOMAIN_SHUTOFF) + { + dbg_printf(2, "[virt:OFF] Nothing to do - " + "domain %s is already off\n", + vm_name); + virDomainFree(vdp); + return 0; + } + + syslog(LOG_NOTICE, "Destroying domain %s\n", vm_name); + dbg_printf(2, "[virt:OFF] Calling virDomainDestroy for %s\n", vm_name); + + ret = virDomainDestroy(vdp); + virDomainFree(vdp); + + if (ret < 0) { + syslog(LOG_NOTICE, + "Failed to destroy domain %s: %d\n", vm_name, ret); + dbg_printf(2, "[virt:OFF] Failed to destroy domain: %s %d\n", + vm_name, ret); + return 1; + } + + if (ret) { + syslog(LOG_NOTICE, "Domain %s still exists; fencing failed\n", + vm_name); + dbg_printf(2, + "[virt:OFF] Domain %s still exists; fencing failed\n", + vm_name); + return 1; + } + + dbg_printf(2, "[virt:OFF] Success for %s\n", vm_name); + return 0; +} + + +int +vm_on(virConnectPtr *vp, int vp_count, const char *vm_name) +{ + virDomainPtr vdp = NULL; + virDomainInfo vdi; + virDomainPtr (*virt_lookup_fn)(virConnectPtr, const char *); + int ret = -1; + int i; + + if (is_uuid(vm_name)) + virt_lookup_fn = virDomainLookupByUUIDString; + else + virt_lookup_fn = virDomainLookupByName; + + for (i = 0 ; i < vp_count ; i++) { + vdp = virt_lookup_fn(vp[i], vm_name); + if (vdp) + break; + } + + if (!vdp) { + dbg_printf(2, "[virt:ON] Domain %s does not exist\n", vm_name); + return 1; + } + + if (virDomainGetInfo(vdp, &vdi) == 0 && vdi.state != VIR_DOMAIN_SHUTOFF) { + dbg_printf(2, "Nothing to do - domain %s is already running\n", + vm_name); + virDomainFree(vdp); + return 0; + } + + syslog(LOG_NOTICE, "Starting domain %s\n", vm_name); + dbg_printf(2, "[virt:ON] Calling virDomainCreate for %s\n", vm_name); + + ret = virDomainCreate(vdp); + virDomainFree(vdp); + + if (ret < 0) { + syslog(LOG_NOTICE, "Failed to start domain %s: %d\n", vm_name, ret); + dbg_printf(2, "[virt:ON] virDomainCreate() failed for %s: %d\n", + vm_name, ret); + return 1; + } + + if (ret) { + syslog(LOG_NOTICE, "Domain %s did not start\n", vm_name); + dbg_printf(2, "[virt:ON] Domain %s did not start\n", vm_name); + return 1; + } + + syslog(LOG_NOTICE, "Domain %s started\n", vm_name); + dbg_printf(2, "[virt:ON] Success for %s\n", vm_name); + return 0; +} + + +int +vm_status(virConnectPtr *vp, int vp_count, const char *vm_name) +{ + virDomainPtr vdp = NULL; + virDomainInfo vdi; + int ret = 0; + int i; + virDomainPtr (*virt_lookup_fn)(virConnectPtr, const char *); + + if (is_uuid(vm_name)) + virt_lookup_fn = virDomainLookupByUUIDString; + else + virt_lookup_fn = virDomainLookupByName; + + for (i = 0 ; i < vp_count ; i++) { + vdp = virt_lookup_fn(vp[i], vm_name); + if (vdp) + break; + } + + if (!vdp) { + dbg_printf(2, "[virt:STATUS] Unknown VM %s - return OFF\n", vm_name); + return RESP_OFF; + } + + if (virDomainGetInfo(vdp, &vdi) == 0 && vdi.state == VIR_DOMAIN_SHUTOFF) { + dbg_printf(2, "[virt:STATUS] VM %s is OFF\n", vm_name); + ret = RESP_OFF; + } + + if (vdp) + virDomainFree(vdp); + return ret; +} + + +int +vm_reboot(virConnectPtr *vp, int vp_count, const char *vm_name) +{ + virDomainPtr vdp = NULL, nvdp; + virDomainInfo vdi; + char *domain_desc; + virConnectPtr vcp = NULL; + virDomainPtr (*virt_lookup_fn)(virConnectPtr, const char *); + int ret; + int i; + + if (is_uuid(vm_name)) + virt_lookup_fn = virDomainLookupByUUIDString; + else + virt_lookup_fn = virDomainLookupByName; + + for (i = 0 ; i < vp_count ; i++) { + vdp = virt_lookup_fn(vp[i], vm_name); + if (vdp) { + vcp = vp[i]; + break; + } + } + + if (!vdp || !vcp) { + dbg_printf(2, + "[virt:REBOOT] Nothing to do - domain %s does not exist\n", + vm_name); + return 1; + } + + if (virDomainGetInfo(vdp, &vdi) == 0 && vdi.state == VIR_DOMAIN_SHUTOFF) { + dbg_printf(2, "[virt:REBOOT] Nothing to do - domain %s is off\n", + vm_name); + virDomainFree(vdp); + return 0; + } + + syslog(LOG_NOTICE, "Rebooting domain %s\n", vm_name); + dbg_printf(5, "[virt:REBOOT] Rebooting domain %s...\n", vm_name); + + domain_desc = virDomainGetXMLDesc(vdp, 0); + + if (!domain_desc) { + dbg_printf(5, "[virt:REBOOT] Failed getting domain description " + "from libvirt for %s...\n", vm_name); + } + + dbg_printf(2, "[virt:REBOOT] Calling virDomainDestroy(%p) for %s\n", + vdp, vm_name); + + ret = virDomainDestroy(vdp); + if (ret < 0) { + dbg_printf(2, + "[virt:REBOOT] virDomainDestroy() failed for %s: %d/%d\n", + vm_name, ret, errno); + + if (domain_desc) + free(domain_desc); + virDomainFree(vdp); + return 1; + } + + ret = wait_domain(vm_name, vcp, 15); + + if (ret) { + syslog(LOG_NOTICE, "Domain %s still exists; fencing failed\n", vm_name); + dbg_printf(2, + "[virt:REBOOT] Domain %s still exists; fencing failed\n", + vm_name); + + if (domain_desc) + free(domain_desc); + virDomainFree(vdp); + return 1; + } + + if (!domain_desc) + return 0; + + /* 'on' is not a failure */ + ret = 0; + + dbg_printf(3, "[[ XML Domain Info ]]\n"); + dbg_printf(3, "%s\n[[ XML END ]]\n", domain_desc); + + dbg_printf(2, "[virt:REBOOT] Calling virDomainCreateLinux() for %s\n", + vm_name); + + nvdp = virDomainCreateLinux(vcp, domain_desc, 0); + if (nvdp == NULL) { + /* More recent versions of libvirt or perhaps the + * KVM back-end do not let you create a domain from + * XML if there is already a defined domain description + * with the same name that it knows about. You must + * then call virDomainCreate() */ + dbg_printf(2, + "[virt:REBOOT] virDomainCreateLinux() failed for %s; " + "Trying virDomainCreate()\n", + vm_name); + + if (virDomainCreate(vdp) < 0) { + syslog(LOG_NOTICE, "Could not restart %s\n", vm_name); + dbg_printf(1, "[virt:REBOOT] Failed to recreate guest %s!\n", + vm_name); + } + } + + free(domain_desc); + virDomainFree(vdp); + return ret; +} diff --git a/agents/virt/server/virt.h b/agents/virt/server/virt.h new file mode 100644 index 0000000..1d9140c --- /dev/null +++ b/agents/virt/server/virt.h @@ -0,0 +1,62 @@ +/* + Copyright Red Hat, Inc. 2006-2017 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ + +#ifndef _VIRT_H +#define _VIRT_H + +#include <stdint.h> +#include <netinet/in.h> +#include <libvirt/libvirt.h> + +#include "xvm.h" + +typedef struct { + uint32_t s_owner; + int32_t s_state; +} vm_state_t; + +typedef struct { + char v_name[MAX_DOMAINNAME_LENGTH + 1]; + char v_uuid[MAX_DOMAINNAME_LENGTH + 1]; + vm_state_t v_state; +} virt_state_t; + +/** + This is stored in our private checkpoint section. + */ +typedef struct _virt_list { + uint32_t vm_count; + virt_state_t vm_states[0]; +} virt_list_t; + +virt_list_t *vl_get(virConnectPtr *vp, int vp_count, int my_id); +void vl_print(virt_list_t *vl); +void vl_free(virt_list_t *old); +virt_state_t *vl_find_uuid(virt_list_t *vl, const char *name); +virt_state_t *vl_find_name(virt_list_t *vl, const char *name); +int vl_add(virt_list_t **vl, virt_state_t *vm); +int vl_update(virt_list_t **vl, virt_state_t *vm); +int vl_remove_by_owner(virt_list_t **vl, uint32_t owner); + +int vm_off(virConnectPtr *vp, int vp_count, const char *vm_name); +int vm_on(virConnectPtr *vp, int vp_count, const char *vm_name); +int vm_status(virConnectPtr *vp, int vp_count, const char *vm_name); +int vm_reboot(virConnectPtr *vp, int vp_count, const char *vm_name); + +#endif diff --git a/agents/virt/server/vsock.c b/agents/virt/server/vsock.c new file mode 100644 index 0000000..1b88fa5 --- /dev/null +++ b/agents/virt/server/vsock.c @@ -0,0 +1,565 @@ +/* + Copyright Red Hat, Inc. 2017 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. +*/ +#include "config.h" + +#include <unistd.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <nss.h> +#include <sys/socket.h> +#include <linux/vm_sockets.h> + +/* Local includes */ +#include "list.h" +#include "simpleconfig.h" +#include "static_map.h" +#include "server_plugin.h" +#include "history.h" +#include "xvm.h" +#include "simple_auth.h" +#include "options.h" +#include "mcast.h" +#include "tcp.h" +#include "tcp_listener.h" +#include "debug.h" +#include "fdops.h" + +#define NAME "vsock" +#define VSOCK_VERSION "0.2" + +#define VSOCK_MAGIC 0xa32d27c1e + +#define VALIDATE(info) \ +do {\ + if (!info || info->magic != VSOCK_MAGIC)\ + return -EINVAL;\ +} while(0) + +typedef struct _vsock_options { + char *key_file; + int cid; + unsigned int port; + unsigned int hash; + unsigned int auth; + unsigned int flags; +} vsock_options; + + +typedef struct _vsock_info { + uint64_t magic; + void *priv; + map_object_t *map; + history_info_t *history; + char key[MAX_KEY_LEN]; + vsock_options args; + const fence_callbacks_t *cb; + ssize_t key_len; + int listen_sock; +} vsock_info; + + +struct vsock_hostlist_arg { + map_object_t *map; + int cid; + int fd; +}; + + +static int get_peer_cid(int fd, uint32_t *peer_cid) { + struct sockaddr_vm svm; + socklen_t len; + int ret; + + if (!peer_cid) + return -1; + + len = sizeof(svm); + ret = getpeername(fd, (struct sockaddr *) &svm, &len); + if (ret < 0) { + printf("Error getting peer CID: %s\n", strerror(errno)); + return -1; + } + + *peer_cid = svm.svm_cid; + return 0; +} + + +/* + * See if we fenced this node recently (successfully) + * If so, ignore the request for a few seconds. + * + * We purge our history when the entries time out. + */ +static int +check_history(void *a, void *b) { + fence_req_t *old = a, *current = b; + + if (old->request == current->request && + old->seqno == current->seqno && + !strcasecmp((const char *)old->domain, + (const char *)current->domain)) { + return 1; + } + return 0; +} + + +static int +vsock_hostlist(const char *vm_name, const char *vm_uuid, + int state, void *priv) +{ + struct vsock_hostlist_arg *arg = (struct vsock_hostlist_arg *) priv; + host_state_t hinfo; + struct timeval tv; + int ret; + uint32_t peer_cid = 0; + char peer_cid_str[24]; + + ret = get_peer_cid(arg->fd, &peer_cid); + if (ret < 0) { + printf("Unable to get peer CID: %s\n", strerror(errno)); + peer_cid_str[0] = '\0'; + } else + snprintf(peer_cid_str, sizeof(peer_cid_str), "%u", peer_cid); + + /* Noops if auth == AUTH_NONE */ + + if (map_check2(arg->map, peer_cid_str, vm_uuid, vm_name) == 0) { + /* if we don't have access to fence this VM, + * we should not see it in a hostlist either */ + return 0; + } + + strncpy((char *)hinfo.domain, vm_name, sizeof(hinfo.domain) - 1); + strncpy((char *)hinfo.uuid, vm_uuid, sizeof(hinfo.uuid) - 1); + hinfo.state = state; + + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = _write_retry(arg->fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + + +static int +vsock_hostlist_begin(int fd) +{ + struct timeval tv; + char val = (char) RESP_HOSTLIST; + + tv.tv_sec = 1; + tv.tv_usec = 0; + return _write_retry(fd, &val, 1, &tv); +} + + +static int +vsock_hostlist_end(int fd) +{ + host_state_t hinfo; + struct timeval tv; + int ret; + + printf("Sending terminator packet\n"); + + memset(&hinfo, 0, sizeof(hinfo)); + + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = _write_retry(fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + + +static int +do_fence_request_vsock(int fd, fence_req_t *req, vsock_info *info) +{ + char response = 1; + struct vsock_hostlist_arg arg; + uint32_t peer_cid = 0; + char peer_cid_str[24]; + int ret; + + ret = get_peer_cid(fd, &peer_cid); + if (ret < 0) { + printf("Unable to get peer CID: %s\n", strerror(errno)); + return -1; + } + + snprintf(peer_cid_str, sizeof(peer_cid_str), "%u", peer_cid); + + /* Noops if auth == AUTH_NONE */ + if (sock_response(fd, info->args.auth, info->key, info->key_len, 10) <= 0) { + printf("CID %u Failed to respond to challenge\n", peer_cid); + close(fd); + return -1; + } + + ret = sock_challenge(fd, info->args.auth, info->key, info->key_len, 10); + if (ret <= 0) { + printf("Remote CID %u failed challenge\n", peer_cid); + close(fd); + return -1; + } + + dbg_printf(2, "Request %d seqno %d target %s from CID %u\n", + req->request, req->seqno, req->domain, peer_cid); + + switch(req->request) { + case FENCE_NULL: + response = info->cb->null((char *)req->domain, info->priv); + break; + case FENCE_ON: + if (map_check(info->map, peer_cid_str, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->on((char *)req->domain, peer_cid_str, + req->seqno, info->priv); + break; + case FENCE_OFF: + if (map_check(info->map, peer_cid_str, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->off((char *)req->domain, peer_cid_str, + req->seqno, info->priv); + break; + case FENCE_REBOOT: + if (map_check(info->map, peer_cid_str, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->reboot((char *)req->domain, peer_cid_str, + req->seqno, info->priv); + break; + case FENCE_STATUS: + if (map_check(info->map, peer_cid_str, + (const char *)req->domain) == 0) { + response = RESP_PERM; + break; + } + response = info->cb->status((char *)req->domain, info->priv); + break; + case FENCE_DEVSTATUS: + response = info->cb->devstatus(info->priv); + break; + case FENCE_HOSTLIST: + arg.map = info->map; + arg.fd = fd; + + vsock_hostlist_begin(arg.fd); + response = info->cb->hostlist(vsock_hostlist, &arg, info->priv); + vsock_hostlist_end(arg.fd); + break; + } + + dbg_printf(3, "Sending response to caller CID %u...\n", peer_cid); + if (_write_retry(fd, &response, 1, NULL) < 0) + perror("write"); + + history_record(info->history, req); + + if (fd != -1) + close(fd); + + return 1; +} + + +static int +vsock_dispatch(listener_context_t c, struct timeval *timeout) +{ + vsock_info *info; + fence_req_t data; + fd_set rfds; + int n; + int client_fd; + int ret; + struct timeval tv; + + if (timeout != NULL) + memcpy(&tv, timeout, sizeof(tv)); + else { + tv.tv_sec = 1; + tv.tv_usec = 0; + } + + info = (vsock_info *) c; + VALIDATE(info); + + FD_ZERO(&rfds); + FD_SET(info->listen_sock, &rfds); + + n = select(info->listen_sock + 1, &rfds, NULL, NULL, timeout); + if (n <= 0) { + if (errno == EINTR || errno == EAGAIN) + n = 0; + else + dbg_printf(2, "select: %s\n", strerror(errno)); + return n; + } + + + client_fd = accept(info->listen_sock, NULL, NULL); + if (client_fd < 0) { + perror("accept"); + return -1; + } + + dbg_printf(3, "Accepted vsock client...\n"); + + ret = _read_retry(client_fd, &data, sizeof(data), &tv); + if (ret != sizeof(data)) { + dbg_printf(3, "Invalid request (read %d bytes)\n", ret); + close(client_fd); + return 0; + } + + swab_fence_req_t(&data); + + if (!verify_request(&data, info->args.hash, info->key, info->key_len)) { + printf("Key mismatch; dropping client\n"); + close(client_fd); + return 0; + } + + dbg_printf(3, "Request %d seqno %d domain %s\n", + data.request, data.seqno, data.domain); + + if (history_check(info->history, &data) == 1) { + printf("We just did this request; dropping client\n"); + close(client_fd); + return 0; + } + + switch(info->args.auth) { + case AUTH_NONE: + case AUTH_SHA1: + case AUTH_SHA256: + case AUTH_SHA512: + printf("VSOCK request\n"); + do_fence_request_vsock(client_fd, &data, info); + break; + default: + printf("XXX Unhandled authentication\n"); + } + + return 0; +} + + +static int +vsock_config(config_object_t *config, vsock_options *args) +{ + char value[1024]; + int errors = 0; + + if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0) + dset(atoi(value)); + + if (sc_get(config, "listeners/vsock/@key_file", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for key_file\n", value); + args->key_file = strdup(value); + } else { + args->key_file = strdup(DEFAULT_KEY_FILE); + if (!args->key_file) { + dbg_printf(1, "Failed to allocate memory\n"); + return -1; + } + } + + args->hash = DEFAULT_HASH; + if (sc_get(config, "listeners/vsock/@hash", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for hash\n", value); + if (!strcasecmp(value, "none")) { + args->hash = HASH_NONE; + } else if (!strcasecmp(value, "sha1")) { + args->hash = HASH_SHA1; + } else if (!strcasecmp(value, "sha256")) { + args->hash = HASH_SHA256; + } else if (!strcasecmp(value, "sha512")) { + args->hash = HASH_SHA512; + } else { + dbg_printf(1, "Unsupported hash: %s\n", value); + ++errors; + } + } + + args->auth = DEFAULT_AUTH; + if (sc_get(config, "listeners/vsock/@auth", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for auth\n", value); + if (!strcasecmp(value, "none")) { + args->hash = AUTH_NONE; + } else if (!strcasecmp(value, "sha1")) { + args->hash = AUTH_SHA1; + } else if (!strcasecmp(value, "sha256")) { + args->hash = AUTH_SHA256; + } else if (!strcasecmp(value, "sha512")) { + args->hash = AUTH_SHA512; + } else { + dbg_printf(1, "Unsupported auth: %s\n", value); + ++errors; + } + } + + args->port = DEFAULT_MCAST_PORT; + if (sc_get(config, "listeners/vsock/@port", + value, sizeof(value)-1) == 0) { + dbg_printf(1, "Got %s for port\n", value); + args->port = atoi(value); + if (args->port <= 0) { + dbg_printf(1, "Invalid port: %s\n", value); + ++errors; + } + } + + return errors; +} + + +static int +vsock_init(listener_context_t *c, const fence_callbacks_t *cb, + config_object_t *config, map_object_t *map, void *priv) +{ + vsock_info *info; + int listen_sock, ret; + struct sockaddr_vm svm; + + if (NSS_NoDB_Init(NULL) != SECSuccess) { + printf("Could not initialize NSS\n"); + return 1; + } + + info = calloc(1, sizeof(*info)); + if (!info) + return -1; + + info->priv = priv; + info->cb = cb; + info->map = map; + + ret = vsock_config(config, &info->args); + if (ret < 0) + perror("vsock_config"); + else if (ret > 0) + printf("%d errors found during vsock listener configuration\n", ret); + + if (ret != 0) { + if (info->args.key_file) + free(info->args.key_file); + free(info); + return -1; + } + + if (info->args.auth != AUTH_NONE || info->args.hash != HASH_NONE) { + info->key_len = read_key_file(info->args.key_file, + info->key, sizeof(info->key)); + if (info->key_len < 0) { + printf("Could not read %s; operating without " + "authentication\n", info->args.key_file); + info->args.auth = AUTH_NONE; + info->args.hash = HASH_NONE; + info->key_len = 0; + } + } + + listen_sock = socket(PF_VSOCK, SOCK_STREAM, 0); + if (listen_sock < 0) + goto out_fail; + + memset(&svm, 0, sizeof(svm)); + svm.svm_family = AF_VSOCK; + svm.svm_cid = VMADDR_CID_ANY; + svm.svm_port = info->args.port; + + if (bind(listen_sock, (struct sockaddr *) &svm, sizeof(svm)) < 0) + goto out_fail; + + if (listen(listen_sock, 1) < 0) + goto out_fail; + + info->magic = VSOCK_MAGIC; + info->listen_sock = listen_sock; + info->history = history_init(check_history, 10, sizeof(fence_req_t)); + *c = (listener_context_t)info; + return 0; + +out_fail: + printf("Could not set up listen socket: %s\n", strerror(errno)); + if (listen_sock >= 0) + close(listen_sock); + if (info->args.key_file) + free(info->args.key_file); + free(info); + return -1; +} + + +static int +vsock_shutdown(listener_context_t c) +{ + vsock_info *info = (vsock_info *)c; + + VALIDATE(info); + info->magic = 0; + history_wipe(info->history); + free(info->history); + free(info->args.key_file); + close(info->listen_sock); + free(info); + + return 0; +} + + +static listener_plugin_t vsock_plugin = { + .name = NAME, + .version = VSOCK_VERSION, + .init = vsock_init, + .dispatch = vsock_dispatch, + .cleanup = vsock_shutdown, +}; + +double +LISTENER_VER_SYM(void) +{ + return PLUGIN_VERSION_LISTENER; +} + +const listener_plugin_t * +LISTENER_INFO_SYM(void) +{ + return &vsock_plugin; +} diff --git a/agents/vmware/fence_vmware.py b/agents/vmware/fence_vmware.py new file mode 100644 index 0000000..bc1785f --- /dev/null +++ b/agents/vmware/fence_vmware.py @@ -0,0 +1,336 @@ +#!@PYTHON@ -tt + +# +# The Following agent has been tested on: +# vmrun 2.0.0 build-116503 (from VMware Server 2.0) against: +# VMware ESX 4.0.0 +# VMware vCenter 4.0.0 +# VMware ESX 3.5 +# VMware Server 2.0.0 +# VMware ESXi 3.5 update 2 +# VMware Server 1.0.7 (works but list/status show only running VMs) +# +# VI Perl API 1.6 against: +# VMware ESX 4.0.0 +# VMware vCenter 4.0.0 +# VMware ESX 3.5 +# VMware ESXi 3.5 update 2 +# VMware Virtual Center 2.5 +# +# VMware vSphere SDK for Perl 4.0.0 against: +# VMware ESX 4.0.0 +# VMware vCenter 4.0.0 +# + +import sys, re, pexpect +import logging +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay, frun + +### CONSTANTS #### +# VMware type is ESX/ESXi/VC +VMWARE_TYPE_ESX = 0 +# VMware type is Server 1.x +VMWARE_TYPE_SERVER1 = 1 +# VMware type is Server 2.x and/or ESX 3.5 up2, ESXi 3.5 up2, VC 2.5 up2 +VMWARE_TYPE_SERVER2 = 2 + +# Minimum required version of vmrun command +VMRUN_MINIMUM_REQUIRED_VERSION = 2 + +# Default path to vmhelper command +VMHELPER_COMMAND = "fence_vmware_helper" +# Default path to vmrun command +VMRUN_COMMAND = "/usr/bin/vmrun" +# Default type of vmware +VMWARE_DEFAULT_TYPE = "esx" + +#### GLOBAL VARIABLES #### +# Internal type. One of VMWARE_TYPE_, set by #vmware_check_vmware_type +vmware_internal_type = VMWARE_TYPE_ESX + +# If ESX is disconnected, say, that VM is off (don't return previous state) +vmware_disconnected_hack = False + +### FUNCTIONS #### + +#Split string in simplified DSV format to array of items +def dsv_split(dsv_str): + delimiter_c = ':' + escape_c = '\\' + + res = [] + status = 0 + tmp_str = "" + + for x in dsv_str: + if status == 0: + if x == delimiter_c: + res.append(tmp_str) + tmp_str = "" + elif x == escape_c: + status = 1 + else: + tmp_str += x + elif status == 1: + if x == delimiter_c: + tmp_str += delimiter_c + elif x == escape_c: + tmp_str += escape_c + else: + tmp_str += escape_c+x + status = 0 + + if tmp_str != "": + res.append(tmp_str) + + return res + +# Quote string for proper existence in quoted string used for pexpect.run function +# Ex. test'this will return test'\''this. So pexpect run will really pass ' to argument +def quote_for_run(text): + dstr = '' + + for c in text: + if c == r"'": + dstr += "'\\''" + else: + dstr += c + + return dstr + +# Return string with command and additional parameters (something like vmrun -h 'host' +def vmware_prepare_command(options, add_login_params, additional_params): + res = options["--exec"] + + if add_login_params: + if vmware_internal_type == VMWARE_TYPE_ESX: + res += " --server '%s' --username '%s' --password '%s' "% (quote_for_run(options["--ip"]), + quote_for_run(options["--username"]), + quote_for_run(options["--password"])) + elif vmware_internal_type == VMWARE_TYPE_SERVER2: + res += " -h 'https://%s/sdk' -u '%s' -p '%s' -T server "% (quote_for_run(options["--ip"]), + quote_for_run(options["--username"]), + quote_for_run(options["--password"])) + elif vmware_internal_type == VMWARE_TYPE_SERVER1: + host_name_array = options["--ip"].split(':') + + res += " -h '%s' -u '%s' -p '%s' -T server1 "% (quote_for_run(host_name_array[0]), + quote_for_run(options["--username"]), + quote_for_run(options["--password"])) + if len(host_name_array) > 1: + res += "-P '%s' "% (quote_for_run(host_name_array[1])) + + if "--vmware-datacenter" in options and vmware_internal_type == VMWARE_TYPE_ESX: + res += "--datacenter '%s' "% (quote_for_run(options["--vmware-datacenter"])) + + if additional_params != "": + res += additional_params + + return res + +# Run command with timeout and parameters. Internaly uses vmware_prepare_command. Returns string +# with output from vmrun command. If something fails (command not found, exit code is not 0), fail_usage +# function is called (and never return). +def vmware_run_command(options, add_login_params, additional_params, additional_timeout): + command = vmware_prepare_command(options, add_login_params, additional_params) + + try: + logging.debug("%s\n", command) + + (res_output, res_code) = frun(command, + int(options["--shell-timeout"]) + int(options["--login-timeout"]) + additional_timeout, True) + + if res_code == None: + fail(EC_TIMED_OUT) + if res_code != 0 and add_login_params: + logging.debug("%s\n", res_output) + fail_usage("%s returned %s"% (options["--exec"], res_output)) + else: + logging.debug("%s\n", res_output) + + except pexpect.ExceptionPexpect: + fail_usage("Cannot run command %s"% (options["--exec"])) + + return res_output + +# Get outlet list with status as hash table. If you will use add_vm_name, only VM with vmname is +# returned. This is used in get_status function +def vmware_get_outlets_vi(options, add_vm_name): + outlets = {} + + if add_vm_name: + all_machines = vmware_run_command(options, True, + ("--operation status --vmname '%s'"% (quote_for_run(options["--plug"]))), 0) + else: + all_machines = vmware_run_command(options, True, "--operation list", int(options["--power-timeout"])) + + all_machines_array = all_machines.splitlines() + + for machine in all_machines_array: + machine_array = dsv_split(machine) + if len(machine_array) == 4: + if machine_array[0] in outlets: + fail_usage("Failed. More machines with same name %s found!"%(machine_array[0])) + + if vmware_disconnected_hack: + outlets[machine_array[0]] = ("", ( + ((machine_array[2].lower() in ["poweredon"]) and + (machine_array[3].lower() == "connected")) + and "on" or "off")) + else: + outlets[machine_array[0]] = ("", ((machine_array[2].lower() in ["poweredon"]) and "on" or "off")) + return outlets + +# Get outlet list with status as hash table. +def vmware_get_outlets_vix(options): + outlets = {} + + running_machines = vmware_run_command(options, True, "list", 0) + running_machines_array = running_machines.splitlines()[1:] + + if vmware_internal_type == VMWARE_TYPE_SERVER2: + all_machines = vmware_run_command(options, True, "listRegisteredVM", 0) + all_machines_array = all_machines.splitlines()[1:] + elif vmware_internal_type == VMWARE_TYPE_SERVER1: + all_machines_array = running_machines_array + + for machine in all_machines_array: + if machine != "": + outlets[machine] = ("", ((machine in running_machines_array) and "on" or "off")) + + return outlets + +def get_outlets_status(conn, options): + del conn + + if vmware_internal_type == VMWARE_TYPE_ESX: + return vmware_get_outlets_vi(options, False) + if vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2: + return vmware_get_outlets_vix(options) + +def get_power_status(conn, options): + if vmware_internal_type == VMWARE_TYPE_ESX: + outlets = vmware_get_outlets_vi(options, True) + else: + outlets = get_outlets_status(conn, options) + + if vmware_internal_type == VMWARE_TYPE_SERVER2 or vmware_internal_type == VMWARE_TYPE_ESX: + if not options["--plug"] in outlets: + fail_usage("Failed: You have to enter existing name of virtual machine!") + else: + return outlets[options["--plug"]][1] + elif vmware_internal_type == VMWARE_TYPE_SERVER1: + return (options["--plug"] in outlets) and "on" or "off" + +def set_power_status(conn, options): + del conn + + if vmware_internal_type == VMWARE_TYPE_ESX: + additional_params = "--operation %s --vmname '%s'" % \ + ((options["--action"] == "on" and "on" or "off"), quote_for_run(options["--plug"])) + elif vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2: + additional_params = "%s '%s'" % \ + ((options["--action"] == "on" and "start" or "stop"), quote_for_run(options["--plug"])) + if options["--action"] == "off": + additional_params += " hard" + + vmware_run_command(options, True, additional_params, int(options["--power-timeout"])) + +# Returns True, if user uses supported vmrun version (currently >=2.0.0) otherwise False. +def vmware_is_supported_vmrun_version(options): + vmware_help_str = vmware_run_command(options, False, "", 0) + version_re = re.search(r"vmrun version (\d\.(\d[\.]*)*)", vmware_help_str.lower()) + if version_re == None: + return False # Looks like this "vmrun" is not real vmrun + + version_array = version_re.group(1).split(".") + + try: + if int(version_array[0]) < VMRUN_MINIMUM_REQUIRED_VERSION: + return False + except Exception: + return False + + return True + +# Check vmware type, set vmware_internal_type to one of VMWARE_TYPE_ value and +# options["--exec"] to path (if not specified) +def vmware_check_vmware_type(options): + global vmware_internal_type + + options["--vmware_type"] = options["--vmware_type"].lower() + + if options["--vmware_type"] == "esx": + vmware_internal_type = VMWARE_TYPE_ESX + if "--exec" not in options: + options["--exec"] = VMHELPER_COMMAND + elif options["--vmware_type"] == "server2": + vmware_internal_type = VMWARE_TYPE_SERVER2 + if "--exec" not in options: + options["--exec"] = VMRUN_COMMAND + elif options["--vmware_type"] == "server1": + vmware_internal_type = VMWARE_TYPE_SERVER1 + if "--exec" not in options: + options["--exec"] = VMRUN_COMMAND + else: + fail_usage("vmware_type can be esx,server2 or server1!") + +# Main agent method +def main(): + device_opt = ["ipaddr", "login", "passwd", "secure", + "exec", "vmware_type", "vmware_datacenter"] + + atexit.register(atexit_handler) + + all_opt["secure"]["default"] = "1" + all_opt["vmware_type"]["default"] = VMWARE_DEFAULT_TYPE + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for VMWare" + docs["longdesc"] = "fence_vmware is an I/O Fencing agent \ +which can be used with the VMware ESX, VMware ESXi or VMware Server \ +to fence virtual machines.\ +\n.P\n\ +Before you can use this agent, it must be installed VI Perl Toolkit or \ +vmrun command on every node you want to make fencing.\ +\n.P\n\ +VI Perl Toolkit is preferred for VMware ESX/ESXi and Virtual Center. Vmrun \ +command is only solution for VMware Server 1/2 (this command will works against \ +ESX/ESXi 3.5 up2 and VC up2 too, but not cluster aware!) and is available as part \ +of VMware VIX API SDK package. VI Perl and VIX API SDK are both available from \ +VMware web pages (not int RHEL repository!). \ +\n.P\n\ +You can specify type of VMware you are connecting to with \\fB-d\\fP switch \ +(or \\fIvmware_type\\fR for stdin). Possible values are esx, server2 and server1.\ +Default value is esx, which will use VI Perl. With server1 and server2, vmrun \ +command is used.\ +\n.P\n\ +After you have successfully installed VI Perl Toolkit or VIX API, you should \ +be able to run fence_vmware_helper (part of this agent) or vmrun command. \ +This agent supports only vmrun from version 2.0.0 (VIX API 1.6.0)." + docs["vendorurl"] = "http://www.vmware.com" + show_docs(options, docs) + + run_delay(options) + + # Check vmware type and set path + vmware_check_vmware_type(options) + + # Test user vmrun command version + if vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2: + if not vmware_is_supported_vmrun_version(options): + fail_usage("Unsupported version of vmrun command! You must use at least version %d!" % + (VMRUN_MINIMUM_REQUIRED_VERSION)) + + # Operate the fencing device + result = fence_action(None, options, set_power_status, get_power_status, get_outlets_status) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/vmware/fence_vmware_helper.pl b/agents/vmware/fence_vmware_helper.pl new file mode 100644 index 0000000..a0b5cea --- /dev/null +++ b/agents/vmware/fence_vmware_helper.pl @@ -0,0 +1,276 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my $ME = $0; + +END { + defined fileno STDOUT or return; + close STDOUT and return; + warn "$ME: failed to close standard output: $!\n"; + $? ||= 1; +} + +my ($RELEASE_VERSION, $REDHAT_COPYRIGHT, $BUILD_DATE); + +#BEGIN_VERSION_GENERATION +$RELEASE_VERSION=""; +$REDHAT_COPYRIGHT=""; +$BUILD_DATE=""; +#END_VERSION_GENERATION + +#### FUNCTIONS ##### +# Show error message +sub show_error { + print STDERR @_; +} + +sub my_exit { + my ($exit_code)=@_; + + # Disconnect from server + Util::disconnect(); + + exit $exit_code; +} + +# Convert one field (string) to format acceptable by DSV. This +# means replace any : with \: and \ with \\. +sub convert_field_to_dsv { + my ($input_line)=@_; + + $input_line =~ s/([\\:])/\\$1/g; + return $input_line +} + +#### Global variables ##### +# Aditional options +my %opts = ( + 'operation' => { + type => "=s", + help => "The operation to perform (on,off,list,status). " + . "Operations on/off/status require name of the virtual machine", + default => "list", + required => 0, + }, + 'vmname' => { + type => "=s", + help => "The name of the virtual machine", + required => 0, + }, + 'datacenter' => { + type => "=s", + help => "The name of the datacenter", + required => 0, + } +); + +################# +##### MAIN ###### +################# + +# Conditional use of VIRuntime +eval "use VMware::VIRuntime;"; + +if ($@) { + show_error "Please install VI Perl API package to use this tool!\nPerl error: $@"; + exit 1; +} + +# Parse options +Opts::add_options(%opts); +Opts::parse(); +Opts::validate(); + +if (!(Opts::get_option('operation')=~/^(on|off|list|status)$/i)) { + show_error "Operation should be on, off, list or status!\n"; + exit 2; +} + +my $operation=lc(Opts::get_option('operation')); + +if (($operation ne 'list') && (!defined Opts::get_option('vmname'))) { + show_error "Operation on, off, status require vmname parameter!\n"; + exit 2; +} + + +# Try connect to machine +eval { + Util::connect(); +}; + +if ($@) { + show_error "Cannot connect to server!\nVMware error:".$@; + exit 3; +} + +my ($datacenter, $datacenter_view, $vm_views,$vm); +# We are connected to machine + +# If user want's datacenter, we must first find datacenter +my %filter=(view_type => 'VirtualMachine'); + +if( defined (Opts::get_option('datacenter')) ) { + $datacenter = Opts::get_option('datacenter'); + $datacenter_view = Vim::find_entity_view(view_type => 'Datacenter', + filter => { name => $datacenter }); + if (!$datacenter_view) { + show_error "Cannot find datacenter ".$datacenter."!\n"; + + my_exit 4; + } + + $filter{'begin_entity'}=$datacenter_view; +} + +if ($operation ne 'list') { + $filter{'filter'}= {"config.name" => Opts::get_option('vmname')}; +} + +$vm_views = Vim::find_entity_views(%filter); + +my $found=0; + +# Traverse all found vm +foreach $vm(@$vm_views) { + if (($operation eq 'list') or ($operation eq 'status')) { + if (!$vm->summary->config->template) { + print convert_field_to_dsv($vm->name).":". + convert_field_to_dsv($vm->summary->config->vmPathName).":". + convert_field_to_dsv($vm->runtime->powerState->val).":". + convert_field_to_dsv($vm->runtime->connectionState->val)."\n"; + } + } elsif ($operation eq 'on') { + eval { + $vm->PowerOnVM(); + }; + + if ($@) { + # If error is SoapFault with InvalidPowerState, user maybe use some auto power on tool. + # This is not error, warning is enought. + if (ref($@) eq 'SoapFault') { + if (ref($@->detail) eq 'InvalidPowerState') { + show_error "Warning: Cannot power on vm (somebody done it before???) ".Opts::get_option('vmname'). + "!\nVMware error:".$@."\n"; + } + } else { + # Some other more serious problem + show_error "Cannot power on vm ".Opts::get_option('vmname')."!\nVMware error:".$@."\n"; + my_exit 6; + } + } + } elsif ($operation eq 'off') { + eval { + $vm->PowerOffVM(); + }; + + if ($@) { + # If error is SoapFault with InvalidPowerState, user maybe use some auto power off tool. + # This is not error, warning is enought. + if (ref($@) eq 'SoapFault') { + if (ref($@->detail) eq 'InvalidPowerState') { + show_error "Warning: Cannot power off vm (somebody done it before???) ".Opts::get_option('vmname'). + "!\nVMware error:".$@."\n"; + } + } else { + # Some other more serious problem + show_error "Cannot power off vm ".Opts::get_option('vmname')."!\nVMware error:".$@."\n"; + my_exit 6; + } + } + } else { + show_error "Operation should be on, off or list!\n"; + my_exit 2; + } + $found++; +} + +if ((!$found) && ($operation ne 'list')) { + show_error "Cannot find vm ".Opts::get_option('vmname')."!\n"; + my_exit 5; +} + +# Should be 0 -> success all, or 6 in case of error +my_exit 0; + +__END__ + +=head1 NAME + +fence_vmware_helper - Perform list of virtual machines and + poweron, poweroff of operations on virtual machines. + +=head1 SYNOPSIS + + fence_vmware_helper --operation <on|off|list|status> [options] + +=head1 DESCRIPTION + +This VI Perl command-line utility provides an interface for +seven common provisioning operations on one or more virtual +machines: powering on, powering off and listing virtual mode. + +=head1 OPTIONS + +=head2 GENERAL OPTIONS + +=over + +=item B<operation> + +Operation to be performed. One of the following: + + <on> (power on one or more virtual machines), + <off> (power off one or more virtual machines), + <list> (list virtual machines and their status) + <status> (same as list, but show only machines with vmname) + +=item B<vmname> + +Optional. Name of the virtual machine on which the +operation is to be performed. + +=item B<datacenter> + +Optional. Name of the datacenter for the virtual machine(s). +Operations will be performed on all the virtual machines under the given datacenter. + +=back + +=head1 EXAMPLES + +Power on a virtual machine + + fence_vmware_helper --username administrator --password administrator --operation on + --vmname rhel --server win1 + + fence_vmware_helper --username administrator --password administrator --operation on + --vmname rhel --server win1 --datacenter Datacenter + +Power off a virtual machine + + fence_vmware_helper --username administrator --password administrator --operation off + --vmname rhel --server win1 + + perl fence_vmware_helper --username administrator --password administrator --operation off + --vmname rhel --server win1 --datacenter Datacenter + +List of virtual machines + + fence_vmware_helper --username administrator --password administrator --server win1 + + fence_vmware_helper --username administrator --password administrator --server win1 + --operation list + +Get status of virtual machine + + fence_vmware_helper --username administrator --password administrator --server win1 + --vmname rhel --operation status + +=head1 SUPPORTED PLATFORMS + +All operations supported on ESX 3.0.1 + +All operations supported on Virtual Center 2.0.1 diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py new file mode 100644 index 0000000..4b884fc --- /dev/null +++ b/agents/vmware_rest/fence_vmware_rest.py @@ -0,0 +1,229 @@ +#!@PYTHON@ -tt + +import sys +import pycurl, io, json +import logging +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS + +if sys.version_info[0] > 2: import urllib.parse as urllib +else: import urllib + +state = {"POWERED_ON": "on", 'POWERED_OFF': "off", 'SUSPENDED': "off"} + +def get_power_status(conn, options): + try: + res = send_command(conn, "vcenter/vm?filter.names={}".format(urllib.quote(options["--plug"])))["value"] + except Exception as e: + logging.debug("Failed: {}".format(e)) + fail(EC_STATUS) + + if len(res) == 0: + fail(EC_STATUS) + + options["id"] = res[0]["vm"] + + result = res[0]["power_state"] + + return state[result] + +def set_power_status(conn, options): + action = { + "on" : "start", + "off" : "stop" + }[options["--action"]] + + try: + send_command(conn, "vcenter/vm/{}/power/{}".format(options["id"], action), "POST") + except Exception as e: + logging.debug("Failed: {}".format(e)) + fail(EC_STATUS) + +def get_list(conn, options): + outlets = {} + + try: + command = "vcenter/vm" + if "--filter" in options: + command = command + "?" + options["--filter"] + res = send_command(conn, command) + except Exception as e: + logging.debug("Failed: {}".format(e)) + if str(e).startswith("400"): + if options.get("--original-action") == "monitor": + return outlets + else: + logging.error("More than 1000 VMs returned. Use --filter parameter to limit which VMs to list.") + fail(EC_STATUS) + else: + fail(EC_STATUS) + + for r in res["value"]: + outlets[r["name"]] = ("", state[r["power_state"]]) + + return outlets + +def connect(opt): + conn = pycurl.Curl() + + ## setup correct URL + if "--ssl-secure" in opt or "--ssl-insecure" in opt: + conn.base_url = "https:" + else: + conn.base_url = "http:" + if "--api-path" in opt: + api_path = opt["--api-path"] + else: + api_path = "/rest" + + conn.base_url += "//" + opt["--ip"] + ":" + str(opt["--ipport"]) + api_path + "/" + + ## send command through pycurl + conn.setopt(pycurl.HTTPHEADER, [ + "Accept: application/json", + ]) + + conn.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC) + conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"]) + + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) + + if "--ssl-secure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + elif "--ssl-insecure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + + try: + result = send_command(conn, "com/vmware/cis/session", "POST") + except Exception as e: + logging.debug("Failed: {}".format(e)) + fail(EC_LOGIN_DENIED) + + # set session id for later requests + conn.setopt(pycurl.HTTPHEADER, [ + "Accept: application/json", + "vmware-api-session-id: {}".format(result["value"]), + ]) + + return conn + +def disconnect(conn): + try: + send_command(conn, "com/vmware/cis/session", "DELETE") + except Exception as e: + logging.debug("Failed: {}".format(e)) + conn.close() + +def send_command(conn, command, method="GET"): + url = conn.base_url + command + + conn.setopt(pycurl.URL, url.encode("ascii")) + + web_buffer = io.BytesIO() + + if method == "GET": + conn.setopt(pycurl.POST, 0) + if method == "POST": + conn.setopt(pycurl.POSTFIELDS, "") + if method == "DELETE": + conn.setopt(pycurl.CUSTOMREQUEST, "DELETE") + + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + + try: + conn.perform() + except Exception as e: + raise(e) + + rc = conn.getinfo(pycurl.HTTP_CODE) + result = web_buffer.getvalue().decode("UTF-8") + + web_buffer.close() + + if len(result) > 0: + result = json.loads(result) + + if rc != 200: + if len(result) > 0: + raise Exception("{}: {}".format(rc, + result["value"]["messages"][0]["default_message"])) + else: + raise Exception("Remote returned {} for request to {}".format(rc, url)) + + logging.debug("url: {}".format(url)) + logging.debug("method: {}".format(method)) + logging.debug("response code: {}".format(rc)) + logging.debug("result: {}\n".format(result)) + + return result + +def define_new_opts(): + all_opt["api_path"] = { + "getopt" : ":", + "longopt" : "api-path", + "help" : "--api-path=[path] The path part of the API URL", + "default" : "/rest", + "required" : "0", + "shortdesc" : "The path part of the API URL", + "order" : 2} + all_opt["filter"] = { + "getopt" : ":", + "longopt" : "filter", + "help" : "--filter=[filter] Filter to only return relevant VMs" + " (e.g. \"filter.names=node1&filter.names=node2\").", + "required" : "0", + "shortdesc" : "Filter to only return relevant VMs. It can be used to avoid " + "the agent failing when more than 1000 VMs should be returned.", + "order" : 2} + + +def main(): + device_opt = [ + "ipaddr", + "api_path", + "login", + "passwd", + "ssl", + "notls", + "web", + "port", + "filter", + ] + + atexit.register(atexit_handler) + define_new_opts() + + all_opt["shell_timeout"]["default"] = "5" + all_opt["power_wait"]["default"] = "1" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for VMware REST API" + docs["longdesc"] = """fence_vmware_rest is an I/O Fencing agent which can be \ +used with VMware API to fence virtual machines. + +NOTE: If there's more than 1000 VMs there is a filter parameter to work around \ +the API limit. See https://code.vmware.com/apis/62/vcenter-management#/VM%20/get_vcenter_vm \ +for full list of filters.""" + docs["vendorurl"] = "https://www.vmware.com" + show_docs(options, docs) + + #### + ## Fence operations + #### + run_delay(options) + + conn = connect(options) + atexit.register(disconnect, conn) + + result = fence_action(conn, options, set_power_status, get_power_status, get_list) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/vmware_soap/fence_vmware_soap.py b/agents/vmware_soap/fence_vmware_soap.py new file mode 100644 index 0000000..4a4ec17 --- /dev/null +++ b/agents/vmware_soap/fence_vmware_soap.py @@ -0,0 +1,265 @@ +#!@PYTHON@ -tt + +import sys +import shutil, tempfile, suds +import logging, requests +import atexit, signal +sys.path.append("@FENCEAGENTSLIBDIR@") + +from suds.client import Client +from suds.sudsobject import Property +from suds.transport.http import HttpAuthenticated +from suds.transport import Reply, TransportError +from fencing import * +from fencing import fail, fail_usage, EC_STATUS, EC_LOGIN_DENIED, EC_INVALID_PRIVILEGES, EC_WAITING_ON, EC_WAITING_OFF +from fencing import run_delay + +options_global = None +conn_global = None + +class RequestsTransport(HttpAuthenticated): + def __init__(self, **kwargs): + self.cert = kwargs.pop('cert', None) + self.verify = kwargs.pop('verify', True) + self.session = requests.Session() + # super won't work because not using new style class + HttpAuthenticated.__init__(self, **kwargs) + + def send(self, request): + self.addcredentials(request) + resp = self.session.post(request.url, data=request.message, headers=request.headers, cert=self.cert, verify=self.verify) + result = Reply(resp.status_code, resp.headers, resp.content) + return result + +def soap_login(options): + run_delay(options) + + if "--ssl-secure" in options or "--ssl-insecure" in options: + if "--ssl-insecure" in options: + import ssl + import urllib3 + if hasattr(ssl, '_create_unverified_context'): + ssl._create_default_https_context = ssl._create_unverified_context + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + verify = False + else: + verify = True + url = "https://" + else: + verify = False + url = "http://" + + url += options["--ip"] + ":" + str(options["--ipport"]) + "/sdk" + + tmp_dir = tempfile.mkdtemp() + tempfile.tempdir = tmp_dir + atexit.register(remove_tmp_dir, tmp_dir) + + try: + headers = {"Content-Type" : "text/xml;charset=UTF-8", "SOAPAction" : "vim25"} + login_timeout = int(options["--login-timeout"]) or 15 + conn = Client(url + "/vimService.wsdl", location=url, transport=RequestsTransport(verify=verify), headers=headers, timeout=login_timeout) + + mo_ServiceInstance = Property('ServiceInstance') + mo_ServiceInstance._type = 'ServiceInstance' + ServiceContent = conn.service.RetrieveServiceContent(mo_ServiceInstance) + mo_SessionManager = Property(ServiceContent.sessionManager.value) + mo_SessionManager._type = 'SessionManager' + + conn.service.Login(mo_SessionManager, options["--username"], options["--password"]) + except requests.exceptions.SSLError as ex: + fail_usage("Server side certificate verification failed: %s" % ex) + except Exception as e: + logging.error("Server side certificate verification failed: {}".format(str(e))) + fail(EC_LOGIN_DENIED) + + options["ServiceContent"] = ServiceContent + options["mo_SessionManager"] = mo_SessionManager + return conn + +def process_results(results, machines, uuid, mappingToUUID): + for m in results.objects: + info = {} + for i in m.propSet: + info[i.name] = i.val + # Prevent error KeyError: 'config.uuid' when reaching systems which P2V failed, + # since these systems don't have a valid UUID + if "config.uuid" in info: + machines[info["name"]] = (info["config.uuid"], info["summary.runtime.powerState"]) + uuid[info["config.uuid"]] = info["summary.runtime.powerState"] + mappingToUUID[m.obj.value] = info["config.uuid"] + + return (machines, uuid, mappingToUUID) + +def get_power_status(conn, options): + mo_ViewManager = Property(options["ServiceContent"].viewManager.value) + mo_ViewManager._type = "ViewManager" + + mo_RootFolder = Property(options["ServiceContent"].rootFolder.value) + mo_RootFolder._type = "Folder" + + mo_PropertyCollector = Property(options["ServiceContent"].propertyCollector.value) + mo_PropertyCollector._type = 'PropertyCollector' + + ContainerView = conn.service.CreateContainerView(mo_ViewManager, recursive=1, + container=mo_RootFolder, type=['VirtualMachine']) + mo_ContainerView = Property(ContainerView.value) + mo_ContainerView._type = "ContainerView" + + FolderTraversalSpec = conn.factory.create('ns0:TraversalSpec') + FolderTraversalSpec.name = "traverseEntities" + FolderTraversalSpec.path = "view" + FolderTraversalSpec.skip = False + FolderTraversalSpec.type = "ContainerView" + + objSpec = conn.factory.create('ns0:ObjectSpec') + objSpec.obj = mo_ContainerView + objSpec.selectSet = [FolderTraversalSpec] + objSpec.skip = True + + propSpec = conn.factory.create('ns0:PropertySpec') + propSpec.all = False + propSpec.pathSet = ["name", "summary.runtime.powerState", "config.uuid"] + propSpec.type = "VirtualMachine" + + propFilterSpec = conn.factory.create('ns0:PropertyFilterSpec') + propFilterSpec.propSet = [propSpec] + propFilterSpec.objectSet = [objSpec] + + try: + raw_machines = conn.service.RetrievePropertiesEx(mo_PropertyCollector, propFilterSpec) + except Exception as e: + logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + + (machines, uuid, mappingToUUID) = process_results(raw_machines, {}, {}, {}) + + # Probably need to loop over the ContinueRetreive if there are more results after 1 iteration. + while hasattr(raw_machines, 'token'): + try: + raw_machines = conn.service.ContinueRetrievePropertiesEx(mo_PropertyCollector, raw_machines.token) + except Exception as e: + logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + (more_machines, more_uuid, more_mappingToUUID) = process_results(raw_machines, {}, {}, {}) + machines.update(more_machines) + uuid.update(more_uuid) + mappingToUUID.update(more_mappingToUUID) + # Do not run unnecessary SOAP requests + if "--uuid" in options and options["--uuid"] in uuid: + break + + if ["list", "monitor"].count(options["--action"]) == 1: + return machines + else: + if "--uuid" not in options: + if options["--plug"].startswith('/'): + ## Transform InventoryPath to UUID + mo_SearchIndex = Property(options["ServiceContent"].searchIndex.value) + mo_SearchIndex._type = "SearchIndex" + + vm = conn.service.FindByInventoryPath(mo_SearchIndex, options["--plug"]) + + try: + options["--uuid"] = mappingToUUID[vm.value] + except KeyError: + fail(EC_STATUS) + except AttributeError: + fail(EC_STATUS) + else: + ## Name of virtual machine instead of path + ## warning: if you have same names of machines this won't work correctly + try: + (options["--uuid"], _) = machines[options["--plug"]] + except KeyError: + fail(EC_STATUS) + except AttributeError: + fail(EC_STATUS) + + try: + if uuid[options["--uuid"]] == "poweredOn": + return "on" + else: + return "off" + except KeyError: + fail(EC_STATUS) + +def set_power_status(conn, options): + mo_SearchIndex = Property(options["ServiceContent"].searchIndex.value) + mo_SearchIndex._type = "SearchIndex" + vm = conn.service.FindByUuid(mo_SearchIndex, vmSearch=1, uuid=options["--uuid"]) + + mo_machine = Property(vm.value) + mo_machine._type = "VirtualMachine" + + try: + if options["--action"] == "on": + conn.service.PowerOnVM_Task(mo_machine) + else: + conn.service.PowerOffVM_Task(mo_machine) + except suds.WebFault as ex: + if (str(ex).find("Permission to perform this operation was denied")) >= 0: + fail(EC_INVALID_PRIVILEGES) + else: + if options["--action"] == "on": + fail(EC_WAITING_ON) + else: + fail(EC_WAITING_OFF) + +def remove_tmp_dir(tmp_dir): + shutil.rmtree(tmp_dir) + +def logout(): + try: + conn_global.service.Logout(options_global["mo_SessionManager"]) + except Exception: + pass + +def signal_handler(signum, frame): + raise Exception("Signal \"%d\" received which has triggered an exit of the process." % signum) + +def main(): + global options_global + global conn_global + device_opt = ["ipaddr", "login", "passwd", "web", "ssl", "notls", "port"] + + atexit.register(atexit_handler) + atexit.register(logout) + + signal.signal(signal.SIGTERM, signal_handler) + + options_global = check_input(device_opt, process_input(device_opt)) + + ## + ## Fence agent specific defaults + ##### + docs = {} + docs["shortdesc"] = "Fence agent for VMWare over SOAP API" + docs["longdesc"] = "fence_vmware_soap is an I/O Fencing agent \ +which can be used with the virtual machines managed by VMWare products \ +that have SOAP API v4.1+. \ +\n.P\n\ +Name of virtual machine (-n / port) has to be used in inventory path \ +format (e.g. /datacenter/vm/Discovered virtual machine/myMachine). \ +In the cases when name of yours VM is unique you can use it instead. \ +Alternatively you can always use UUID to access virtual machine." + docs["vendorurl"] = "http://www.vmware.com" + show_docs(options_global, docs) + + logging.basicConfig(level=logging.INFO) + logging.getLogger('suds.client').setLevel(logging.CRITICAL) + logging.getLogger("requests").setLevel(logging.CRITICAL) + logging.getLogger("urllib3").setLevel(logging.CRITICAL) + + ## + ## Operate the fencing device + #### + conn_global = soap_login(options_global) + + result = fence_action(conn_global, options_global, set_power_status, get_power_status, get_power_status) + + ## Logout from system is done automatically via atexit() + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/vmware_vcloud/fence_vmware_vcloud.py b/agents/vmware_vcloud/fence_vmware_vcloud.py new file mode 100644 index 0000000..7626b82 --- /dev/null +++ b/agents/vmware_vcloud/fence_vmware_vcloud.py @@ -0,0 +1,214 @@ +#!@PYTHON@ -tt + +import sys +import pycurl, io +import logging +import atexit +import xml.etree.ElementTree as etree +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS + +state = {"POWERED_ON": "on", 'POWERED_OFF': "off", 'SUSPENDED': "off"} + +def get_power_status(conn, options): + try: + VM = send_command(conn, "vApp/vm-{}".format(options["--plug"])) + except Exception as e: + logging.debug("Failed: {}".format(e)) + fail(EC_STATUS) + + options["id"] = VM.attrib['href'].split('/vm-', 1)[1] + + if (VM.attrib['status'] == '3'): + return state['SUSPENDED'] + elif (VM.attrib['status'] == '4'): + return state['POWERED_ON'] + elif (VM.attrib['status'] == '8'): + return state['POWERED_OFF'] + return EC_STATUS + + +def set_power_status(conn, options): + action = { + "on" : "powerOn", + "off" : "powerOff", + "shutdown": "shutdown", + "suspend": "suspend", + "reset": "reset" + }[options["--action"]] + try: + VM = send_command(conn, "vApp/vm-{}/power/action/{}".format(options["--plug"], action), "POST") + except Exception as e: + logging.debug("Failed: {}".format(e)) + fail(EC_STATUS) + +def get_list(conn, options): + outlets = {} + + VMsResponse = send_command(conn, "vms/query") + + for VM in VMsResponse.iter('{http://www.vmware.com/vcloud/v1.5}VMRecord'): + if '/vApp/' not in VM.attrib['href']: + continue + uuid = (VM.attrib['href'].split('/vm-', 1))[1] + outlets['['+ uuid + '] ' + VM.attrib['containerName'] + '\\' + VM.attrib['name']] = (VM.attrib['status'], state[VM.attrib['status']]) + + return outlets + +def connect(opt): + conn = pycurl.Curl() + + ## setup correct URL + if "--ssl-secure" in opt or "--ssl-insecure" in opt: + conn.base_url = "https:" + else: + conn.base_url = "http:" + + conn.base_url += "//" + opt["--ip"] + ":" + str(opt["--ipport"]) + opt["--api-path"] + "/" + + ## send command through pycurl + conn.setopt(pycurl.HTTPHEADER, [ + "Accept: application/*+xml;version=1.5", + ]) + + conn.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC) + conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"]) + + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) + if "--ssl-secure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + elif "--ssl-insecure" in opt: + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) + + headers = {} + try: + result = send_command(conn, "sessions", "POST", headers) + except Exception as e: + logging.debug("Failed: {}".format(e)) + fail(EC_LOGIN_DENIED) + + # set session id for later requests + conn.setopt(pycurl.HTTPHEADER, [ + "Accept: application/*+xml;version=1.5", + "x-vcloud-authorization: {}".format(headers['x-vcloud-authorization']), + ]) + + return conn + +def disconnect(conn): + send_command(conn, "session", "DELETE") + conn.close() + +def parse_headers(data): + headers = {} + data = data.split("\r\n") + for header_line in data[1:]: + if ':' not in header_line: + break + name, value = header_line.split(':', 1) + name = name.strip() + value = value.strip() + name = name.lower() + headers[name] = value + + return headers + +def send_command(conn, command, method="GET", headers={}): + url = conn.base_url + command + + conn.setopt(pycurl.URL, url.encode("ascii")) + + web_buffer = io.BytesIO() + headers_buffer = io.BytesIO() + + if method == "GET": + conn.setopt(pycurl.POST, 0) + elif method == "POST": + conn.setopt(pycurl.POSTFIELDS, "") + elif method == "DELETE": + conn.setopt(pycurl.CUSTOMREQUEST, "DELETE") + + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + conn.setopt(pycurl.HEADERFUNCTION, headers_buffer.write) + + try: + conn.perform() + except Exception as e: + raise(e) + + rc = conn.getinfo(pycurl.HTTP_CODE) + result = web_buffer.getvalue().decode() + headers.update(parse_headers(headers_buffer.getvalue().decode())) + + headers_buffer.close() + web_buffer.close() + + if len(result) > 0: + result = etree.fromstring(result) + + if rc != 200 and rc != 202 and rc != 204: + if len(result) > 0: + raise Exception("{}: {}".format(rc, result["value"]["messages"][0]["default_message"])) + else: + raise Exception("Remote returned {} for request to {}".format(rc, url)) + + logging.debug("url: {}".format(url)) + logging.debug("method: {}".format(method)) + logging.debug("response code: {}".format(rc)) + logging.debug("result: {}\n".format(result)) + + return result + +def define_new_opts(): + all_opt["api_path"] = { + "getopt" : ":", + "longopt" : "api-path", + "help" : "--api-path=[path] The path part of the API URL", + "default" : "/api", + "required" : "0", + "shortdesc" : "The path part of the API URL", + "order" : 2} + +def main(): + device_opt = [ + "ipaddr", + "api_path", + "login", + "passwd", + "ssl", + "notls", + "web", + "port", + ] + + atexit.register(atexit_handler) + define_new_opts() + + all_opt["shell_timeout"]["default"] = "5" + all_opt["power_wait"]["default"] = "1" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for VMware vCloud Director API" + docs["longdesc"] = "fence_vmware_vcloud is an I/O Fencing agent which can be used with VMware vCloud Director API to fence virtual machines." + docs["vendorurl"] = "https://www.vmware.com" + show_docs(options, docs) + + #### + ## Fence operations + #### + run_delay(options) + + conn = connect(options) + atexit.register(disconnect, conn) + + result = fence_action(conn, options, set_power_status, get_power_status, get_list) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/wti/fence_wti.py b/agents/wti/fence_wti.py new file mode 100644 index 0000000..97cc66d --- /dev/null +++ b/agents/wti/fence_wti.py @@ -0,0 +1,240 @@ +#!@PYTHON@ -tt + +##### +## +## The Following Agent Has Been Tested On: +## +## Version Firmware +## +-----------------+---------------------------+ +## WTI RSM-8R4 ?? unable to find out ?? +## WTI MPC-??? ?? unable to find out ?? +## WTI IPS-800-CE v1.40h (no username) ('list' tested) +##### + +import sys, re, pexpect +import atexit +import time +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fspawn, fail, fail_usage, EC_LOGIN_DENIED + +def get_listing(conn, options, listing_command): + listing = "" + + conn.send_eol(listing_command) + + if isinstance(options["--command-prompt"], list): + re_all = list(options["--command-prompt"]) + else: + re_all = [options["--command-prompt"]] + re_next = re.compile("Enter: ", re.IGNORECASE) + re_all.append(re_next) + + result = conn.log_expect(re_all, int(options["--shell-timeout"])) + listing = conn.before + if result == (len(re_all) - 1): + conn.send_eol("") + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + listing += conn.before + + return listing + +def get_plug_status(conn, options): + listing = get_listing(conn, options, "/S") + + plug_section = 0 + plug_index = -1 + name_index = -1 + status_index = -1 + plug_header = list() + outlets = {} + + for line in listing.splitlines(): + if (plug_section == 2) and line.find("|") >= 0 and line.startswith("PLUG") == False: + plug_line = [x.strip().lower() for x in line.split("|")] + if len(plug_line) < len(plug_header): + plug_section = -1 + if ["list", "monitor"].count(options["--action"]) == 0 and \ + options["--plug"].lower() == plug_line[plug_index]: + return plug_line[status_index] + else: + ## We already believe that first column contains plug number + if len(plug_line[0]) != 0: + outlets[plug_line[0]] = (plug_line[name_index], plug_line[status_index]) + elif plug_section == 1: + plug_section = 2 + elif line.upper().startswith("PLUG"): + plug_section = 1 + plug_header = [x.strip().lower() for x in line.split("|")] + plug_index = plug_header.index("plug") + name_index = plug_header.index("name") + status_index = plug_header.index("status") + + if ["list", "monitor"].count(options["--action"]) == 1: + return outlets + else: + return "PROBLEM" + +def get_plug_group_status_from_list(status_list): + for status in status_list: + if status == "on": + return status + return "off" + +def get_plug_group_status(conn, options): + listing = get_listing(conn, options, "/SG") + + outlets = {} + line_index = 0 + status_index = -1 + plug_index = -1 + name_index = -1 + + lines = listing.splitlines() + while line_index < len(lines) and line_index >= 0: + line = lines[line_index] + if line.find("|") >= 0 and line.lstrip().startswith("GROUP NAME") == False: + plug_line = [x.strip().lower() for x in line.split("|")] + if ["list", "monitor"].count(options["--action"]) == 0 and \ + options["--plug"].lower() == plug_line[name_index]: + plug_status = [] + while line_index < len(lines) and line_index >= 0: + plug_line = [x.strip().lower() for x in lines[line_index].split("|")] + if len(plug_line) >= max(name_index, status_index) and \ + len(plug_line[plug_index]) > 0 and \ + (len(plug_line[name_index]) == 0 or options["--plug"].lower() == plug_line[name_index]): + ## Firmware 1.43 does not have a valid value of plug on first line as only name is defined on that line + if not "---" in plug_line[status_index]: + plug_status.append(plug_line[status_index]) + line_index += 1 + else: + line_index = -1 + + return get_plug_group_status_from_list(plug_status) + + else: + ## We already believe that first column contains plug number + if len(plug_line[0]) != 0: + group_name = plug_line[0] + plug_line_index = line_index + 1 + plug_status = [] + while plug_line_index < len(lines) and plug_line_index >= 0: + plug_line = [x.strip().lower() for x in lines[plug_line_index].split("|")] + if len(plug_line[name_index]) > 0: + plug_line_index = -1 + break + if len(plug_line[plug_index]) > 0: + plug_status.append(plug_line[status_index]) + plug_line_index += 1 + else: + plug_line_index = -1 + outlets[group_name] = (group_name, get_plug_group_status_from_list(plug_status)) + line_index += 1 + + elif line.upper().lstrip().startswith("GROUP NAME"): + plug_header = [x.strip().lower() for x in line.split("|")] + name_index = plug_header.index("group name") + plug_index = plug_header.index("plug") + status_index = plug_header.index("status") + line_index += 2 + else: + line_index += 1 + + + if ["list", "monitor"].count(options["--action"]) == 1: + results = {} + for group, status in list(outlets.items()): + results[group] = (group, status[0]) + + return results + else: + return "PROBLEM" + +def get_power_status(conn, options): + if ["list"].count(options["--action"]) == 0: + ret = get_plug_status(conn, options) + + if ret == "PROBLEM": + ret = get_plug_group_status(conn, options) + else: + ret = dict(list(get_plug_status(conn, options).items()) + \ + list(get_plug_group_status(conn, options).items())) + + return ret + +def set_power_status(conn, options): + action = { + 'on' : "/on", + 'off': "/off" + }[options["--action"]] + + conn.send_eol(action + " " + options["--plug"] + ",y") + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +def main(): + device_opt = ["ipaddr", "login", "passwd", "no_login", "no_password", \ + "cmd_prompt", "secure", "port", "telnet"] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = ["RSM>", "MPC>", "IPS>", "TPS>", "NBB>", "NPS>", "VMR>"] + all_opt["login_timeout"]["default"] = "10" + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for WTI" + docs["longdesc"] = "fence_wti is an I/O Fencing agent \ +which can be used with the WTI Network Power Switch (NPS). It logs \ +into an NPS via telnet or ssh and boots a specified plug. \ +Lengthy telnet connections to the NPS should be avoided while a GFS cluster \ +is running because the connection will block any necessary fencing actions." + docs["vendorurl"] = "http://www.wti.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + ## + ## @note: if it possible that this device does not need either login, password or both of them + ##### + if "--ssh" not in options: + try: + if options["--action"] in ["off", "reboot"]: + time.sleep(int(options["--delay"])) + + options["eol"] = "\r\n" + + conn = fspawn(options, options["--telnet-path"]) + conn.send("set binary\n") + conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) + + re_login = re.compile("(login: )|(Login Name: )|(username: )|(User Name :)", re.IGNORECASE) + re_prompt = re.compile("|".join(["(" + x + ")" for x in options["--command-prompt"]]), re.IGNORECASE) + + result = conn.log_expect([re_login, "Password: ", re_prompt], int(options["--shell-timeout"])) + if result == 0: + if "--username" in options: + conn.send_eol(options["--username"]) + result = conn.log_expect([re_login, "Password: ", re_prompt], int(options["--shell-timeout"])) + else: + fail_usage("Failed: You have to set login name") + + if result == 1: + if "--password" in options: + conn.send_eol(options["--password"]) + conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + else: + fail_usage("Failed: You have to enter password or password script") + except pexpect.EOF: + fail(EC_LOGIN_DENIED) + except pexpect.TIMEOUT: + fail(EC_LOGIN_DENIED) + else: + conn = fence_login(options) + + result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) + fence_logout(conn, "/X") + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/xenapi/fence_xenapi.py b/agents/xenapi/fence_xenapi.py new file mode 100644 index 0000000..10c8ee0 --- /dev/null +++ b/agents/xenapi/fence_xenapi.py @@ -0,0 +1,221 @@ +#!@PYTHON@ -tt +# +############################################################################# +# Copyright 2011 Matthew Clark +# This file is part of fence-xenserver +# +# fence-xenserver is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# fence-xenserver is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Please let me know if you are using this script so that I can work out +# whether I should continue support for it. mattjclark0407 at hotmail dot com +############################################################################# + +############################################################################# +# It's only just begun... +# Current status: completely usable. This script is now working well and, +# has a lot of functionality as a result of the fencing.py library and the +# XenAPI libary. + +############################################################################# +# Please let me know if you are using this script so that I can work out +# whether I should continue support for it. mattjclark0407 at hotmail dot com + +import sys +import atexit +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import run_delay +import XenAPI + +EC_BAD_SESSION = 1 +# Find the status of the port given in the -U flag of options. +def get_power_fn(session, options): + if "--verbose" in options: + verbose = True + else: + verbose = False + + try: + # Get a reference to the vm specified in the UUID or vm_name/port parameter + vm = return_vm_reference(session, options) + # Query the VM for its' associated parameters + record = session.xenapi.VM.get_record(vm) + # Check that we are not trying to manipulate a template or a control + # domain as they show up as VM's with specific properties. + if not record["is_a_template"] and not record["is_control_domain"]: + status = record["power_state"] + if verbose: + print("UUID:", record["uuid"], "NAME:", record["name_label"], "POWER STATUS:", record["power_state"]) + # Note that the VM can be in the following states (from the XenAPI document) + # Halted: VM is offline and not using any resources. + # Paused: All resources have been allocated but the VM itself is paused and its vCPUs are not running + # Running: Running + # Paused: VM state has been saved to disk and it is nolonger running. Note that disks remain in-Use while + # We want to make sure that we only return the status "off" if the machine is actually halted as the status + # is checked before a fencing action. Only when the machine is Halted is it not consuming resources which + # may include whatever you are trying to protect with this fencing action. + return status == "Halted" and "off" or "on" + except Exception as exn: + print(str(exn)) + + return "Error" + +# Set the state of the port given in the -U flag of options. +def set_power_fn(session, options): + try: + # Get a reference to the vm specified in the UUID or vm_name/port parameter + vm = return_vm_reference(session, options) + # Query the VM for its' associated parameters + record = session.xenapi.VM.get_record(vm) + # Check that we are not trying to manipulate a template or a control + # domain as they show up as VM's with specific properties. + if not record["is_a_template"] and not record["is_control_domain"]: + if options["--action"] == "on": + # Start the VM + session.xenapi.VM.start(vm, False, True) + elif options["--action"] == "off": + # Force shutdown the VM + session.xenapi.VM.hard_shutdown(vm) + elif options["--action"] == "reboot": + # Force reboot the VM + session.xenapi.VM.hard_reboot(vm) + except Exception as exn: + print(str(exn)) + +# Function to populate an array of virtual machines and their status +def get_outlet_list(session, options): + result = {} + if "--verbose" in options: + verbose = True + else: + verbose = False + + try: + # Return an array of all the VM's on the host + vms = session.xenapi.VM.get_all() + for vm in vms: + # Query the VM for its' associated parameters + record = session.xenapi.VM.get_record(vm) + # Check that we are not trying to manipulate a template or a control + # domain as they show up as VM's with specific properties. + if not record["is_a_template"] and not record["is_control_domain"]: + name = record["name_label"] + uuid = record["uuid"] + status = record["power_state"] + result[uuid] = (name, status) + if verbose: + print("UUID:", record["uuid"], "NAME:", name, "POWER STATUS:", record["power_state"]) + except Exception as exn: + print(str(exn)) + + return result + +# Function to initiate the XenServer session via the XenAPI library. +def connect_and_login(options): + url = options["--session-url"] + username = options["--username"] + password = options["--password"] + + try: + # Create the XML RPC session to the specified URL. + session = XenAPI.Session(url) + # Login using the supplied credentials. + session.xenapi.login_with_password(username, password) + except Exception as exn: + print(str(exn)) + # http://sources.redhat.com/cluster/wiki/FenceAgentAPI says that for no connectivity + # the exit value should be 1. It doesn't say anything about failed logins, so + # until I hear otherwise it is best to keep this exit the same to make sure that + # anything calling this script (that uses the same information in the web page + # above) knows that this is an error condition, not a msg signifying a down port. + sys.exit(EC_BAD_SESSION) + return session + +# return a reference to the VM by either using the UUID or the vm_name/port. If the UUID is set then +# this is tried first as this is the only properly unique identifier. +# Exceptions are not handled in this function, code that calls this must be ready to handle them. +def return_vm_reference(session, options): + if "--verbose" in options: + verbose = True + else: + verbose = False + + # Case where the UUID has been specified + if "--uuid" in options: + uuid = options["--uuid"].lower() + # When using the -n parameter for name, we get an error message (in verbose + # mode) that tells us that we didn't find a VM. To immitate that here we + # need to catch and re-raise the exception produced by get_by_uuid. + try: + return session.xenapi.VM.get_by_uuid(uuid) + except Exception: + if verbose: + print("No VM's found with a UUID of \"%s\"" % uuid) + raise + + # Case where the vm_name/port has been specified + if "--plug" in options: + vm_name = options["--plug"] + vm_arr = session.xenapi.VM.get_by_name_label(vm_name) + # Need to make sure that we only have one result as the vm_name may + # not be unique. Average case, so do it first. + if len(vm_arr) == 1: + return vm_arr[0] + else: + if len(vm_arr) == 0: + if verbose: + print("No VM's found with a name of \"%s\"" % vm_name) + # NAME_INVALID used as the XenAPI throws a UUID_INVALID if it can't find + # a VM with the specified UUID. This should make the output look fairly + # consistent. + raise Exception("NAME_INVALID") + else: + if verbose: + print("Multiple VM's have the name \"%s\", use UUID instead" % vm_name) + raise Exception("MULTIPLE_VMS_FOUND") + + # We should never get to this case as the input processing checks that either the UUID or + # the name parameter is set. Regardless of whether or not a VM is found the above if + # statements will return to the calling function (either by exception or by a reference + # to the VM). + raise Exception("VM_LOGIC_ERROR") + +def main(): + + device_opt = ["login", "passwd", "port", "no_login", "no_password", "session_url", "web"] + + atexit.register(atexit_handler) + + options = check_input(device_opt, process_input(device_opt)) + + docs = {} + docs["shortdesc"] = "Fence agent for Citrix XenServer over XenAPI" + docs["longdesc"] = "\ +fence_cxs is an I/O Fencing agent used on Citrix XenServer hosts. \ +It uses the XenAPI, supplied by Citrix, to establish an XML-RPC session \ +to a XenServer host. Once the session is established, further XML-RPC \ +commands are issued in order to switch on, switch off, restart and query \ +the status of virtual machines running on the host." + docs["vendorurl"] = "http://www.xenproject.org" + show_docs(options, docs) + + run_delay(options) + + xen_session = connect_and_login(options) + result = fence_action(xen_session, options, set_power_fn, get_power_fn, get_outlet_list) + + sys.exit(result) + +if __name__ == "__main__": + main() diff --git a/agents/zvm/fence_zvm.c b/agents/zvm/fence_zvm.c new file mode 100644 index 0000000..6f1469e --- /dev/null +++ b/agents/zvm/fence_zvm.c @@ -0,0 +1,1056 @@ +/* + * fence_zvm.c: SMAPI interface for managing zVM Guests + * + * Copyright (C) 2012 Sine Nomine Associates + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Neale Ferguson <neale@sinenomine.net> + * + */ + +#ifdef __s390__ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <dirent.h> +#include <time.h> +#include <sys/stat.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include <string.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netiucv/iucv.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <getopt.h> +#include <ctype.h> +#include <syslog.h> +#include "fence_zvm.h" + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define DEFAULT_TIMEOUT 300 +#define DEFAULT_DELAY 0 + +#define ACT_OFFON 0 +#define ACT_OFF 1 +#define ACT_ON 2 +#define ACT_METADATA 3 +#define ACT_STATUS 4 +#define ACT_MONITOR 5 +#define ACT_LIST 6 +#define ACT_HELP 7 + +static int zvm_smapi_reportError (void *, void *); + +static struct option longopts[] = { + {"action", required_argument, NULL, 'o'}, + {"delay", required_argument, NULL, 'h'}, + {"help", no_argument, NULL, 'h'}, + {"ip", required_argument, NULL, 'a'}, + {"plug", required_argument, NULL, 'n'}, + {"timeout", required_argument, NULL, 'T'}, + {"zvmsys", required_argument, NULL, 'z'}, + {NULL, 0, NULL, 0} +}; + +static const char *optString = "a:ho:n:T:"; + +static int zvm_metadata (void); +static int usage (void); + +/** + * zvm_smapi_open: + * @zvm: z/VM driver information + * + * Opens a connection with the z/VM SMAPI server + */ +int +zvm_smapi_open (zvm_driver_t * zvm) +{ + int rc = -1, sockaddrlen; + static char iucvprog[9] = "DMSRSRQU\0"; + struct sockaddr_iucv siucv_addr; + const struct sockaddr *siucv_ptr = (void *) &siucv_addr; + + if ((zvm->sd = socket (AF_IUCV, SOCK_STREAM, IPPROTO_IP)) != -1) { + memset (&siucv_addr, 0, sizeof (siucv_addr)); + siucv_addr.siucv_family = AF_IUCV; + siucv_addr.siucv_port = 0; + siucv_addr.siucv_addr = 0; + memset (&siucv_addr.siucv_nodeid, ' ', 8); + memset (&siucv_addr.siucv_user_id, ' ', 8); + memset (&siucv_addr.siucv_name, ' ', 8); + sockaddrlen = sizeof (siucv_addr); + if ((rc = bind (zvm->sd, siucv_ptr, sockaddrlen)) != -1) { + memcpy (&siucv_addr.siucv_user_id, zvm->smapiSrv, + strlen (zvm->smapiSrv)); + memcpy (&siucv_addr.siucv_name, &iucvprog, 8); + memcpy (&siucv_addr.siucv_nodeid, zvm->node, + strlen (zvm->node)); + rc = connect (zvm->sd, + (__CONST_SOCKADDR_ARG) siucv_ptr, + sockaddrlen); + } + if (rc == -1) { + syslog (LOG_ERR, "Error connecting to %s - %m", + zvm->smapiSrv); + close (zvm->sd); + } + } + return (rc); +} + +/** + * zvm_smapi_imageRecycle + * @zvm: z/VM driver information + * + * Deactivates a virtual image + */ +int +zvm_smapi_imageRecycle (zvm_driver_t * zvm) +{ + struct _inPlist + { + int32_t lPlist; + int32_t lFName; + char fName[13]; + int32_t lUser; + int32_t lPass; + int32_t lTarget; + char target[0]; + } __attribute__((__packed__)) * inPlist; + int32_t lInPlist; + struct _outPlist + { + smapiOutHeader_t hdr; + int32_t nActive; + int32_t nInActive; + int32_t lFail; + char failArray[0]; + } *outPlist = NULL; + void *pOut = NULL; + int32_t lRsp; + uint32_t reqId; + int rc; + + /* + * Implement any delay + */ + if (zvm->delay > 0) + sleep (zvm->delay); + + lInPlist = sizeof (*inPlist) + strlen (zvm->target); + inPlist = malloc (lInPlist); + if (inPlist != NULL) { + inPlist->lPlist = lInPlist - sizeof (inPlist->lPlist); + inPlist->lFName = sizeof (inPlist->fName); + memcpy (inPlist->fName, Image_Recycle, + sizeof (inPlist->fName)); + inPlist->lUser = inPlist->lPass = 0; + inPlist->lTarget = strlen (zvm->target); + memcpy (inPlist->target, zvm->target, inPlist->lTarget); + if ((rc = + zvm_smapi_send (zvm, inPlist, &reqId, lInPlist)) != -1) { + if ((rc = zvm_smapi_recv (zvm, &pOut, &lRsp)) != -1) { + outPlist = pOut; + if (outPlist->hdr.rc == 0) { + syslog (LOG_INFO, + "Recycling of %s successful", + zvm->target); + rc = 0; + } + else { + if ((outPlist->hdr.rc == + RCERR_IMAGEOP) & ((outPlist->hdr. + reason == + RS_NOT_ACTIVE) + | (outPlist-> + hdr. + reason == + RS_BEING_DEACT))) + { + syslog (LOG_INFO, + "Recycling of %s successful", + zvm->target); + rc = 0; + } + else { + rc = outPlist->hdr.rc; + zvm->reason = + outPlist->hdr.reason; + (void) zvm_smapi_reportError + (inPlist, outPlist); + } + } + } + } + free (inPlist); + free (outPlist); + } + else { + syslog (LOG_ERR, "%s - cannot allocate parameter list", + __func__); + rc = -1; + } + return (rc); +} + +/** + * zvm_smapi_imageDeactivate + * @zvm: z/VM driver information + * + * Deactivates a virtual image + */ +int +zvm_smapi_imageDeactivate (zvm_driver_t * zvm) +{ + struct _inPlist + { + int32_t lPlist; + int32_t lFName; + char fName[16]; + int32_t lUser; + int32_t lPass; + int32_t lTarget; + char target[0]; + } __attribute__((__packed__)) * inPlist; + struct _deactTime + { + int32_t lForceTime; + char forceTime[5]; + } __attribute__((__packed__)) * deactTime; + int32_t lInPlist; + struct _outPlist + { + smapiOutHeader_t hdr; + int32_t nActive; + int32_t nInActive; + int32_t lFail; + char failArray[0]; + } *outPlist = NULL; + void *pOut = NULL; + int32_t lRsp; + uint32_t reqId; + int rc; + + /* + * Implement any delay + */ + if (zvm->delay > 0) + sleep (zvm->delay); + + lInPlist = + sizeof (*inPlist) + strlen (zvm->target) + + sizeof (*deactTime); + inPlist = malloc (lInPlist); + if (inPlist != NULL) { + inPlist->lPlist = lInPlist - sizeof (inPlist->lPlist); + inPlist->lFName = sizeof (inPlist->fName); + memcpy (inPlist->fName, Image_Deactivate, + sizeof (inPlist->fName)); + deactTime = + (void *) ((intptr_t) inPlist + sizeof (*inPlist) + + strlen (zvm->target)); + deactTime->lForceTime = sizeof (deactTime->forceTime); + memcpy (deactTime->forceTime, "IMMED", + sizeof (deactTime->forceTime)); + inPlist->lUser = inPlist->lPass = 0; + inPlist->lTarget = strlen (zvm->target); + memcpy (inPlist->target, zvm->target, inPlist->lTarget); + if ((rc = + zvm_smapi_send (zvm, inPlist, &reqId, lInPlist)) != -1) { + if ((rc = zvm_smapi_recv (zvm, &pOut, &lRsp)) != -1) { + outPlist = pOut; + if (outPlist->hdr.rc == 0) { + syslog (LOG_INFO, + "Deactivation of %s successful", + zvm->target); + rc = 0; + } + else { + if ((outPlist->hdr.rc == + RCERR_IMAGEOP) & ((outPlist->hdr. + reason == + RS_NOT_ACTIVE) + | (outPlist-> + hdr. + reason == + RS_BEING_DEACT))) + { + syslog (LOG_INFO, + "Deactivation of %s successful", + zvm->target); + rc = 0; + } + else { + rc = outPlist->hdr.rc; + zvm->reason = + outPlist->hdr.reason; + (void) zvm_smapi_reportError + (inPlist, outPlist); + } + } + } + } + free (inPlist); + free (outPlist); + } + else { + syslog (LOG_ERR, "%s - cannot allocate parameter list", + __func__); + rc = -1; + } + return (rc); +} + +/** + * zvm_smapi_imageActivate + * @zvm: z/VM driver information + * + * Deactivates a virtual image + */ +int +zvm_smapi_imageActivate (zvm_driver_t * zvm) +{ + struct _inPlist + { + int32_t lPlist; + int32_t lFName; + char fName[14]; + int32_t lUser; + int32_t lPass; + int32_t lTarget; + char target[0]; + } __attribute__((__packed__)) * inPlist; + int32_t lInPlist; + struct _outPlist + { + smapiOutHeader_t hdr; + int32_t nActive; + int32_t nInActive; + int32_t lFail; + char failArray[0]; + } *outPlist = NULL; + void *pOut = NULL; + int32_t lRsp; + uint32_t reqId; + int rc; + + /* + * Implement any delay + */ + if (zvm->delay > 0) + sleep (zvm->delay); + + lInPlist = sizeof (*inPlist) + strlen (zvm->target); + inPlist = malloc (lInPlist); + if (inPlist != NULL) { + inPlist->lPlist = lInPlist - sizeof (inPlist->lPlist); + inPlist->lFName = sizeof (inPlist->fName); + memcpy (inPlist->fName, Image_Activate, + sizeof (inPlist->fName)); + inPlist->lUser = inPlist->lPass = 0; + inPlist->lTarget = strlen (zvm->target); + memcpy (inPlist->target, zvm->target, inPlist->lTarget); + if ((rc = + zvm_smapi_send (zvm, inPlist, &reqId, lInPlist)) != -1) { + if ((rc = zvm_smapi_recv (zvm, &pOut, &lRsp)) != -1) { + outPlist = pOut; + if (outPlist->hdr.rc == 0) { + syslog (LOG_INFO, + "Activation of %s successful", + zvm->target); + rc = 0; + } + else { + if ((outPlist->hdr.rc == + RCERR_IMAGEOP) & (outPlist->hdr. + reason == + RS_ALREADY_ACTIVE)) + { + syslog (LOG_INFO, + "Activation of %s successful", + zvm->target); + rc = 0; + } + else { + rc = outPlist->hdr.rc; + zvm->reason = + outPlist->hdr.reason; + (void) zvm_smapi_reportError + (inPlist, outPlist); + } + } + } + } + free (inPlist); + free (outPlist); + } + else { + syslog (LOG_ERR, "%s - cannot allocate parameter list", + __func__); + rc = -1; + } + return (rc); +} + +/** + * zvm_smapi_imageQuery + * @zvm: z/VM driver information + * + * Queries the state of a virtual image + */ +int +zvm_smapi_imageQuery (zvm_driver_t * zvm) +{ + struct _inPlist + { + int32_t lPlist; + int32_t lFName; + char fName[18]; + int32_t lUser; + int32_t lPass; + int32_t lTarget; + char target[0]; + } __attribute__((__packed__)) * inPlist; + int32_t lInPlist; + struct _outPlist + { + smapiOutHeader_t hdr; + int32_t lNames; + char nameArray[0]; + } *outPlist = NULL; + void *pOut = NULL; + int32_t lRsp; + uint32_t reqId; + int rc; + + /* + * Implement any delay + */ + if (zvm->delay > 0) + sleep (zvm->delay); + + lInPlist = sizeof (*inPlist) + strlen (zvm->target); + inPlist = malloc (lInPlist); + if (inPlist != NULL) { + inPlist->lPlist = lInPlist - sizeof (inPlist->lPlist); + inPlist->lFName = sizeof (inPlist->fName); + memcpy (inPlist->fName, Image_Status_Query, + sizeof (inPlist->fName)); + inPlist->lUser = inPlist->lPass = 0; + inPlist->lTarget = strlen (zvm->target); + memcpy (inPlist->target, zvm->target, inPlist->lTarget); + if ((rc = + zvm_smapi_send (zvm, inPlist, &reqId, lInPlist)) != -1) { + if ((rc = zvm_smapi_recv (zvm, &pOut, &lRsp)) != -1) { + outPlist = pOut; + if (outPlist->hdr.rc == 0) { + if (outPlist->hdr.reason == 0) { + syslog (LOG_INFO, + "Node %s is active", + zvm->target); + rc = 0; + } + else { + syslog (LOG_INFO, + "Node %s is inactive", + zvm->target); + rc = 2; + } + } + else { + rc = 1; + zvm->reason = outPlist->hdr.reason; + (void) zvm_smapi_reportError (inPlist, + outPlist); + } + } + } + free (inPlist); + free (outPlist); + } + else { + syslog (LOG_ERR, "%s - cannot allocate parameter list", + __func__); + rc = -1; + } + return (rc); +} + +/** + * zvm_smapi_send: + * @zvm: z/VM driver information + * @reqid: Returned request id + * @req: Request parameter list + * @lSend: Length of request + * + * Send a request to the SMAPI server and retrieve the request id + */ +int +zvm_smapi_send (zvm_driver_t * zvm, void *req, uint32_t * reqId, + int32_t lSend) +{ + int rc, nFds; + fd_set readFds; + struct timeval timeout; + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + zvm->reason = -1; + if ((rc = zvm_smapi_open (zvm)) == 0) { + rc = send (zvm->sd, req, lSend, 0); + if (rc != -1) { + FD_ZERO (&readFds); + FD_SET (zvm->sd, &readFds); + nFds = zvm->sd + 1; + + if ((rc = + select (nFds, &readFds, NULL, NULL, + &timeout)) != -1) { + /* + * Get request ID + */ + rc = recv (zvm->sd, reqId, sizeof (*reqId), + 0); + if (rc == -1) + syslog (LOG_ERR, + "Error receiving from SMAPI - %m"); + } + } + else + syslog (LOG_ERR, "Error sending to SMAPI - %m"); + } + return (rc); +} + +/** + * zvm_smapi_recv: + * @zvm: z/VM driver information + * @req: Returned response parameter list + * @lRsp: Length of response + * + * Receive a response from the SMAPI server + */ +int +zvm_smapi_recv (zvm_driver_t * zvm, void **rsp, int32_t * lRsp) +{ + int rc, lRem = 0, nFds; + void *pRecv = rsp; + fd_set readFds; + smapiOutHeader_t *out; + struct timeval timeout; + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + FD_ZERO (&readFds); + FD_SET (zvm->sd, &readFds); + nFds = zvm->sd + 1; + + zvm->reason = -1; + if ((rc = select (nFds, &readFds, NULL, NULL, &timeout)) != -1) { + /* + * Get response length + */ + if ((rc = recv (zvm->sd, lRsp, sizeof (*lRsp), 0)) != -1) { + lRem = *lRsp; + if (*rsp == NULL) + *rsp = malloc (*lRsp + sizeof (out->outLen)); + out = *rsp; + out->outLen = *lRsp; + pRecv = &out->reqId; + while (lRem > 0) { + if ((rc = + recv (zvm->sd, pRecv, lRem, 0)) != -1) { + lRem -= rc; + pRecv = (void *) ((uintptr_t) pRecv + + rc); + } + else + syslog (LOG_ERR, + "Error receiving from SMAPI - %m"); + (void) zvm_smapi_close (zvm); + return (rc); + } + zvm->reason = out->reason; + } + } + else + syslog (LOG_ERR, "Error receiving from SMAPI - %m"); + + (void) zvm_smapi_close (zvm); + + return (rc); +} + +/** + * zvm_smapi_close: + * @zvm: z/VM driver information + * + * Close a connection with the z/VM SMAPI server + */ +int +zvm_smapi_close (zvm_driver_t * zvm) +{ + close (zvm->sd); + return (0); +} + +/** + * zvm_smapi_reportError + * @inHdr - Input parameter list header + * @outHdr - Output parameter list header + * + * Report an error from the SMAPI server + */ +static int +zvm_smapi_reportError (void *inHdr, void *oHdr) +{ + struct _inParm + { + int32_t lPlist; + int32_t lFName; + char fName[0]; + } *inParm = inHdr; + smapiOutHeader_t *outHdr = oHdr; + char fName[64]; + + memset (fName, 0, sizeof (fName)); + memcpy (fName, inParm->fName, inParm->lFName); + syslog (LOG_ERR, "%s - returned (%d,%d)", + fName, outHdr->rc, outHdr->reason); + return (-1); +} + + +/** + * trim - Trim spaces from string + * @str - Pointer to string + * + */ +static int +trim (char *str) +{ + char *p; + int len; + + if (!str) + return (0); + + len = strlen (str); + + while (len--) { + if (isspace (str[len])) { + str[len] = 0; + } + else { + break; + } + } + + for (p = str; *p && isspace (*p); p++); + + memmove (str, p, strlen (p) + 1); + + return (strlen (str)); +} + +/** + * zvm_metadata - Show fence metadata + * @self - Path to this executable + * + */ +static int +zvm_metadata () +{ + fprintf (stdout, "<?xml version=\"1.0\" ?>\n"); + fprintf (stdout, "<resource-agent name=\"fence_zvm\""); + fprintf (stdout, + " shortdesc=\"Fence agent for use with z/VM Virtual Machines\">\n"); + fprintf (stdout, "<longdesc>"); + fprintf (stdout, + "The fence_zvm agent is intended to be used with with z/VM SMAPI service."); + fprintf (stdout, "</longdesc>\n"); + fprintf (stdout, "<vendor-url>http://www.ibm.com</vendor-url>\n"); + + fprintf (stdout, "<parameters>\n"); + + fprintf (stdout, + "\t<parameter name=\"port\" unique=\"1\" required=\"1\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-n, --plug\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Name of the Virtual Machine to be fenced"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, + "\t<parameter name=\"ipaddr\" unique=\"1\" required=\"1\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-a, --ip\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Name of the SMAPI IUCV Server Virtual Machine"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, + "\t<parameter name=\"zvmsys\" unique=\"1\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"--zvmsys\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Node of the SMAPI IUCV Server Virtual Machine"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, + "\t<parameter name=\"action\" unique=\"1\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-o, --action\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" default=\"off\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Fencing action"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, + "\t<parameter name=\"delay\" unique=\"1\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"--delay\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" default=\"0\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Time to delay fencing action in seconds"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, + "\t<parameter name=\"usage\" unique=\"1\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-h, --help\" />\n"); + fprintf (stdout, "\t\t<content type=\"boolean\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Print usage"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "</parameters>\n"); + + fprintf (stdout, "<actions>\n"); + fprintf (stdout, "\t<action name=\"off\" />\n"); + fprintf (stdout, "\t<action name=\"on\" automatic=\"0\" />\n"); + fprintf (stdout, "\t<action name=\"list\" />\n"); + fprintf (stdout, "\t<action name=\"metadata\" />\n"); + fprintf (stdout, "\t<action name=\"monitor\" />\n"); + fprintf (stdout, "\t<action name=\"reboot\" />\n"); + fprintf (stdout, "\t<action name=\"status\" />\n"); + fprintf (stdout, "</actions>\n"); + + fprintf (stdout, "</resource-agent>\n"); + + return (0); + +} + +/** + * get_options_stdin - get options from stdin + * @zvm - Pointer to driver information + * + */ +static int +get_options_stdin (zvm_driver_t * zvm) +{ + char buf[1024], *endPtr, *opt, *arg; + int32_t lSrvName, lSrvNode, lTarget; + int fence = ACT_OFFON; + + while (fgets (buf, sizeof (buf), stdin) != 0) { + if (trim (buf) == 0) { + continue; + } + if (buf[0] == '#') { + continue; + } + + opt = buf; + + if ((arg = strchr (opt, '=')) != 0) { + *arg = 0; + arg++; + } + else { + continue; + } + + if (trim (arg) == 0) + continue; + + if (!strcasecmp (opt, "action")) { + if (strcasecmp (arg, "reboot") == 0) { + fence = ACT_OFFON; + } + else if (strcasecmp (arg, "off") == 0) { + fence = ACT_OFF; + } + else if (strcasecmp (arg, "on") == 0) { + fence = ACT_ON; + } + else if (strcasecmp (arg, "metadata") == 0) { + fence = ACT_METADATA; + } + else if (strcasecmp (arg, "status") == 0) { + fence = ACT_STATUS; + } + else if (strcasecmp (arg, "monitor") == 0) { + fence = ACT_MONITOR; + } + else if (strcasecmp (arg, "list") == 0) { + fence = ACT_LIST; + } + else { + fence = ACT_HELP; + } + } + else if (!strcasecmp (opt, "ipaddr")) { + lSrvName = MIN (strlen (arg), sizeof (zvm->smapiSrv)); + memcpy (zvm->smapiSrv, arg, lSrvName); + continue; + } + else if (!strcasecmp (opt, "port")) { + lTarget = + MIN (strlen (arg), sizeof (zvm->target) - 1); + strncpy (zvm->target, arg, lTarget); + continue; + } + else if (!strcasecmp (opt, "timeout")) { + zvm->timeOut = strtoul (arg, &endPtr, 10); + if (*endPtr != 0) { + syslog (LOG_WARNING, + "Invalid timeout value specified %s " + "defaulting to %d", arg, + DEFAULT_DELAY); + zvm->timeOut = DEFAULT_DELAY; + } + } + else if (!strcasecmp (opt, "zvmsys")) { + lSrvNode = MIN (strlen (arg), sizeof (zvm->node)); + memcpy (zvm->node, arg, lSrvNode); + continue; + } + else if (!strcasecmp (opt, "delay")) { + zvm->delay = strtoul (arg, &endPtr, 10); + if (*endPtr != 0) { + syslog (LOG_WARNING, + "Invalid delay value specified %s " + "defaulting to %d", arg, + DEFAULT_DELAY); + zvm->delay = DEFAULT_DELAY; + } + } + else if (!strcasecmp (opt, "help")) { + fence = ACT_HELP; + } + } + return (fence); +} + +/** + * get_options - get options from the command line + * @argc - Count of arguments + * @argv - Array of character strings + * @zvm - Pointer to driver information + * + */ +static int +get_options (int argc, char **argv, zvm_driver_t * zvm) +{ + int c, fence = ACT_OFFON; + int32_t lSrvName, lSrvNode, lTarget; + char *endPtr; + + while ((c = + getopt_long (argc, argv, optString, longopts, NULL)) != -1) { + switch (c) { + case 'n': + lTarget = MIN (strlen (optarg), sizeof (zvm->target)); + memcpy (zvm->target, optarg, lTarget); + break; + case 'o': + if (strcasecmp (optarg, "reboot") == 0) { + fence = ACT_OFFON; + } + else if (strcasecmp (optarg, "off") == 0) { + fence = ACT_OFF; + } + else if (strcasecmp (optarg, "on") == 0) { + fence = ACT_ON; + } + else if (strcasecmp (optarg, "metadata") == 0) { + fence = ACT_METADATA; + } + else if (strcasecmp (optarg, "status") == 0) { + fence = ACT_STATUS; + } + else if (strcasecmp (optarg, "monitor") == 0) { + fence = ACT_MONITOR; + } + else if (strcasecmp (optarg, "list") == 0) { + fence = ACT_LIST; + } + else { + fence = ACT_HELP; + } + break; + case 'a': + lSrvName = + MIN (strlen (optarg), sizeof (zvm->smapiSrv)); + memcpy (zvm->smapiSrv, optarg, lSrvName); + break; + case 'T': + zvm->timeOut = strtoul (optarg, &endPtr, 10); + if (*endPtr != 0) { + syslog (LOG_WARNING, + "Invalid timeout value specified: %s - " + "defaulting to %d", optarg, + DEFAULT_TIMEOUT); + zvm->timeOut = DEFAULT_TIMEOUT; + } + break; + case 'd': + zvm->delay = strtoul (optarg, &endPtr, 10); + if (*endPtr != 0) { + syslog (LOG_WARNING, + "Invalid delay value specified: %s - " + "defaulting to %d", optarg, + DEFAULT_DELAY); + zvm->delay = DEFAULT_DELAY; + } + break; + case 'z': + lSrvNode = MIN (strlen (optarg), sizeof (zvm->node)); + memcpy (zvm->node, optarg, lSrvNode); + break; + default: + fence = ACT_HELP; + } + } + return (fence); +} + +/** + * usage - display command syntax and parameters + * + */ +static int +usage () +{ + printf ("Usage: fence_zvm [options]\n\n" + "\tWhere [options] =\n" + "\t-o --action [action] - \"off\", \"on\", \"list\", \"metadata\", " + "\"monitor\", \"reboot\", \"status\"\n" + "\t--delay [seconds] - Time to delay fencing action in seconds\n" + "\t-n --plug [target] - Name of virtual machine to fence\n" + "\t-a --ip [server] - Name of SMAPI IUCV Request server\n" + "\t-T --timeout [secs] - Time to wait for fence in seconds - currently ignored\n" + "\t--zvmsys [node] - z/VM Node on which SMAPI server lives\n" + "\t-h --help - Display this usage information\n"); + return (0); +} + +/** + * check_param - Check that mandatory parameters have been specified + * @zvm - Pointer to driver information + * + */ +static int +check_parm (zvm_driver_t * zvm) +{ + int rc; + + if (zvm->smapiSrv[0] != 0) { + if (zvm->target[0] != 0) { + rc = 0; + } + else { + syslog (LOG_ERR, "Missing fence target name"); + rc = 2; + } + } + else { + syslog (LOG_ERR, "Missing SMAPI server name"); + rc = 1; + } + return (rc); +} + +int +main (int argc, char **argv) +{ + zvm_driver_t zvm; + int fence, rc = 0; + + openlog ("fence_zvm", LOG_CONS | LOG_PID, LOG_DAEMON); + memset (&zvm, 0, sizeof (zvm)); + zvm.timeOut = DEFAULT_TIMEOUT; + zvm.delay = DEFAULT_DELAY; + + if (argc > 1) + fence = get_options (argc, argv, &zvm); + else + fence = get_options_stdin (&zvm); + + switch (fence) { + case ACT_OFFON: // OFFON + if ((rc = check_parm (&zvm)) == 0) + rc = zvm_smapi_imageRecycle (&zvm); + break; + case ACT_OFF: // OFF + if ((rc = check_parm (&zvm)) == 0) + rc = zvm_smapi_imageDeactivate (&zvm); + break; + case ACT_ON: // ON + if ((rc = check_parm (&zvm)) == 0) + rc = zvm_smapi_imageActivate (&zvm); + break; + case ACT_METADATA: // METADATA + rc = zvm_metadata (); + break; + case ACT_STATUS: // STATUS + if ((rc = check_parm (&zvm)) == 0) + rc = zvm_smapi_imageQuery (&zvm); + break; + case ACT_MONITOR: // MONITOR + rc = 0; + break; + case ACT_LIST: // LIST + printf ("N/A"); + rc = 0; + break; + case ACT_HELP: + rc = usage (); + } + closelog (); + return (rc); +} +#else +#include <syslog.h> +int +main (int argc, char **argv) +{ + openlog ("fence_zvm", LOG_CONS | LOG_PID, LOG_DAEMON); + syslog (LOG_ERR, + "Fencing of a z/VM agent is not possible on this platform\n"); + closelog (); + return (-1); +} +#endif diff --git a/agents/zvm/fence_zvm.h b/agents/zvm/fence_zvm.h new file mode 100644 index 0000000..ca18e4d --- /dev/null +++ b/agents/zvm/fence_zvm.h @@ -0,0 +1,583 @@ +/* + * fence_zvm.h: SMAPI interface for z/VM Guests + * + * Copyright (C) 2012 Sine Nomine Associates + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Neale Ferguson <neale@sinenomine.net> + * + */ + +#ifndef FENCE_ZVM_H +# define FENCE_ZVM_H + +# include <sys/types.h> + +# define SMAPI_TARGET "OVIRTADM" +# define SMAPI_MAXCPU 96 + +/* + * Return codes + */ +# define RC_OK 0 /* Request successful */ +# define RC_WNG 4 /* Warning */ +# define RC_ERR 8 /* Error */ +# define RCERR_SYNTAX 24 /* Function parameter syntax error */ +# define RCERR_FILE_NOT_FOUND 28 /* File not found */ +# define RCERR_FILE_CANNOT_BE_UPDATED 36 /* Name list file cannot be updated */ +# define RCERR_AUTH 100 /* Request not authorized by ESM */ +# define RCERR_NO_AUTHFILE 104 /* Authorization file not found */ +# define RCERR_AUTHFILE_RO 106 /* Authorization file cannot be updated */ +# define RCERR_EXISTS 108 /* Authorization file entry already exists */ +# define RCERR_NO_ENTRY 112 /* Authorization file entry does not exist */ +# define RCERR_USER_PW_BAD 120 /* Authentication error: Userid or pwd invalid */ +# define RCERR_PW_EXPIRED 128 /* Authentication error: password expired */ +# define RCERR_ESM 188 /* ESM failure */ +# define RCERR_PW_CHECK 192 /* Internal error: can't authenticate user or pwd */ +# define RCERR_DMSCSL 196 /* Internal Callable Services error */ +# define RCERR_IMAGEOP 200 /* Image Operation error */ +# define RCERR_LIST 200 /* Bad rc for list or list function */ +# define RCERR_IMAGEDEVU 204 /* Image Device Usage error */ +# define RCERR_IMAGEDISKU 208 /* Image Disk Usage error */ +# define RCERR_IMAGECONN 212 /* Image Connectivity Definition error */ +# define RCERR_IMAGECPU 216 /* Image CPU definition error */ +# define RCERR_VOLUME 300 /* Image Volume function error */ +# define RCERR_INTERNAL 396 /* Internal product-specific error */ +# define RCERR_IMAGE_NAME 400 /* Image Name error */ +# define RCERR_IMAGEDEF 400 /* Image Definition error */ +# define RCERR_IMAGEDEVD 404 /* Image Device Definition error */ +# define RCERR_IMAGEDISKD 408 /* Image Disk Definition error */ +# define RCERR_IMAGECONND 412 /* Image Connectivity Definition error */ +# define RCERR_PROTODEF 416 /* Prototype Definition error */ +# define RCERR_DASD_DM 420 /* Volume/region name already defined or region in group */ +# define RCERR_SEGMENT_DM 424 /* Segment definition errors */ +# define RCERR_NOTIFY 428 /* Notification subscription errors */ +# define RCERR_TAG 432 /* Local tag definition errors */ +# define RCERR_PROFILED 436 /* Profile definition errors */ +# define RCERR_POLICY_PW 444 /* Password policy error */ +# define RCERR_POLICY_ACCT 448 /* Account number policy error */ +# define RCERR_TASK 452 /* Task error */ +# define RCERR_SCSI 456 /* SCSI error */ +# define RCERR_DM 500 /* Directory Manager error */ +# define RCERR_LIST_DM 504 /* Directory Manager list error */ +# define RCERR_ASYNC_DM 592 /* Asynchronous Operation error */ +# define RCERR_INTERNAL_DM 596 /* Internal Directory Manager error */ +# define RCERR_SHSTOR 600 /* Shared Memory function error */ +# define RCERR_VIRTUALNETWORKD 620 /* Vswitch function error */ +# define RCERR_VMRM 800 /* Error from VMRM functions */ +# define RCERR_SERVER 900 /* Socket-Server error */ + +/* + * Syntax error reason codes + */ +# define RS_NONE 0 +# define RS_TOOMANY 0 +# define RS_TANY 0 +# define RS_TBIN 2 +# define RS_UNSIGNEDINT 10 +# define RS_TNUM 10 +# define RS_UNSUPPORTED 11 +# define RS_SHORT 14 +# define RS_LESSTHANMIN 15 +# define RS_HEX 16 +# define RS_THEX 16 +# define RS_THEXHY 17 +# define RS_LONG 13 +# define RS_MORETHANMAX 18 +# define RS_UNRECOG 19 +# define RS_CONFLICTING 23 +# define RS_UNSPECIFIED 24 +# define RS_EXTRANEOUS 25 +# define RS_ALPHABETIC 26 +# define RS_TALPHA 26 +# define RS_FUNCTIONNAME 27 +# define RS_TALPHA_ 27 +# define RS_ALPHANUMERIC 36 +# define RS_TNUMALPHA 36 +# define RS_ALPHANUMERIC_ 37 +# define RS_TNUMALPHAHY 37 +# define RS_TLIST 38 +# define RS_DIRMAINTFILE 42 +# define RS_TFILE 42 +# define RS_DIRMAINTFILE_ 43 +# define RS_TFILE_ 43 +# define RS_DIRMAINTFILE_EQ 44 +# define RS_TFILE_EQ 44 +# define RS_UNEXPECTED_END 88 +# define RS_NON_BREAKING_CHAR 99 +# define RS_TNONBLANK 99 + +/* + * Non-syntax related reason codes + */ +# define RS_NONE 0 /* Request successful */ +# define RS_INVALID_USER 2 /* Invalid user */ +# define RS_INVALID_DEVICE 2 /* invalid device */ +# define RS_NO_OSAS 4 /* No OSAs exist */ +# define RS_INVALID_OP 3 /* Invalid LAN operation */ +# define RS_INVALID_PRO 4 /* Invalid LAN promiscuity */ +# define RS_NO_DEV 4 /* No IPL device */ +# define RS_DEFERRED_SERVER 4 /* Authorization deferred to server */ +# define RS_DUP_NAME 4 /* Duplicate tag name */ +# define RS_EXISTS 4 /* Device already exists*/ +# define RS_IN_USE 4 /* Image Disk already in use */ +# define RS_IVS_NAME_USED 4 /* Group/region/volume already defined */ +# define RS_LOADDEV_NOT_FOUND 4 /* LOADDEV statement not found */ +# define RS_NO_PARTNER 4 /* Partner image not found */ +# define RS_NO_UPDATES 4 /* Directory manager not accepting update*/ +# define RS_NOT_FOUND 4 /* Image/Task Not Found */ +# define RS_NOTIFY_DUPLICATE 4 /* Duplicate subscription */ +# define RS_SEG_NAME_DUPLICATE 4 /* Segment name already used */ +# define RS_AFFINITY_SUPPRESSED 4 /* CPU defined but affinity suppressed */ +# define RS_WORK_OUTSTANDING 4 /* Image_Defintion_* asynch */ +# define RS_UNRESTRICTED_LAN 5 /* LAN is unrestricted */ +# define RS_NO_USERS 6 /* No users authorized for LAN */ +# define RS_ADAPTER_NOT_EXIST 8 /* Adapter does not exist */ +# define RS_ALREADY_ACTIVE 8 /* Image already active */ +# define RS_AUTHERR_CONNECT 8 /* Not authorized to connect */ +# define RS_AUTHERR_ESM 8 /* Request not authorized by an ESM */ +# define RS_BAD_RANGE 8 /* Bad page range */ +# define RS_DEV_NOT_FOUND 8 /* Device not found */ +# define RS_IVS_NAME_NOT_USED 8 /* Group/region/volume is not defined */ +# define RS_NAME_EXISTS 8 /* Image Name already defined */ +# define RS_NO_MEASUREMENT_DATA 8 /* No VMRM measurement query data */ +# define RS_NOT_AVAILABLE 8 /* Directory manager not available */ +# define RS_NOT_DEFINED 8 /* Image Device/Volume/Region/Group/Tag name not defined */ +# define RS_NOT_EXIST 8 /* Device does not exist */ +# define RS_NOTIFY_NOT_FOUND 8 /* No matching entries */ +# define RS_NOT_IN_USE 8 /* Image disk not in use */ +# define RS_OFFLINE 8 /* Successful; Object directory offline */ +# define RS_SEG_NAME_NOT_FOUND 8 /* Segment name not used */ +# define RS_WORKER_NOT_FOUND 8 /* Worker server not found */ +# define RS_DEV_NOT_AVAIL_TO_ATTACH 10 /* Device not found */ +# define RS_TOO_MANY_PARM 10 /* Too many parms in parameter list */ +# define RS_TOO_FEW_PARM 11 /* Too few parms in parameter list */ +# define RS_ALREADY_LOCKED 12 /* Image definition already locked */ +# define RS_AUTHERR_DM 12 /* Request not authorized by Directory Manager */ +# define RS_BUSY 12 /* Image device is busy */ +# define RS_DUP_ORDINAL 12 /* Duplicate tag ordinal */ +# define RS_FUNCTION_NOT_VALID 12 /* Not a valid SMAPI function */ +# define RS_IVS_NAME_NOT_INCLUDED 12 /* Name not included (ISR,ISQ)*/ +# define RS_LAN_NOT_EXIST 12 /* LAN does not exist */ +# define RS_LOCKED 12 /* Image definition is locked */ +# define RS_NAMESAVE_EXISTS 12 /* Namesave statementt already in directory*/ +# define RS_NEW_LIST 12 /* Successful new list created */ +# define RS_NOT_ACTIVE 12 /* Image not active */ +# define RS_NOT_INCLUDED 12 /* Region not included in group */ +# define RS_NOT_LOGGED_ON 12 /* User not logged on */ +# define RS_DEV_NOT_VOLUME 12 /* Device not a volume */ +# define RS_UPDATE_SYNTAX_ERROR 12 /* Errors in configuration update buffer */ +# define RS_FREE_MODE_NOT_AVAIL 14 /* Free mode not available */ +# define RS_AUTHERR_SERVER 16 /* Request not authorized by server */ +# define RS_BEING_DEACT 16 /* Image being deactivated */ +# define RS_CANNOT_ACCESS_DATA 16 /* Cannot access configuration or VMRM measurement data */ +# define RS_CANNOT_DELETE 16 /* Cannot delete image definition */ +# define RS_CANNOT_REVOKE 16 /* Cannot revoke tag definition */ +# define RS_CANNOT_SHARE 16 /* Image disk cannot be shared */ +# define RS_DEV_NOT_ONLINE 16 /* Device not online */ +# define RS_LIST_DESTROYED 16 /* Successful no more entries: list destroyed */ +# define RS_NO_MATCH 16 /* Parameters don't match existing directory statement */ +# define RS_NO_SHARING 16 /* Image disk sharing not allowed by target image definition */ +# define RS_NOSAVE 16 /* Could not save segment */ +# define RS_PTS_ENTRY_NOT_VALID 16 /* Parser entry not valid */ +# define RS_TAG_LONG 16 /* Tag too long */ +# define RS_VOLID_NOT_FOUND 18 /* Volid not found */ +# define RS_IS_CONNECTED 20 /* Device already connected */ +# define RS_NOT_AUTHORIZED 20 /* Not authorized for function */ +# define RS_OWNER_NOT_ACTIVE 20 /* Owner of reqested LAN not active */ +# define RS_PARM_LIST_NOT_VALID 20 /* Parameter list not valid */ +# define RS_PW_FORMAT_NOT_SUPPORTED 20 /* Directory manager does not support password format */ +# define RS_SHARE_DIFF_MODE 20 /* Image disk shared in different mode */ +# define RS_VOLID_IN_USE 20 /* Volid is in use */ +# define RS_TARGET_IMG_NOT_AUTH 20 /* Target Image not authorized to issue the command */ +# define RS_PDISKS_SAME 22 /* Parm disk 1 and 2 are same */ +# define RS_CONFLICTING_PARMS 24 /* Conflicting storage parameters */ +# define RS_LAN_NAME_EXISTS 24 /* Same name as an existing LAN */ +# define RS_LIST_NOT_FOUND 24 /* List not found */ +# define RS_NO_SPACE 24 /* Image disk space not available */ +# define RS_NOT_LOCKED 24 /* Image name is not locked */ +# define RS_PARM_DISK_LINK_ERR 24 /* Error linking parm disk (1 or 2)*/ +# define RS_SFS_ERROR 24 /* Shared File System error */ +# define RS_TYPE_NOT_SAME 24 /* Image device type not same as source */ +# define RS_UPDATE_WRITE_ERROR 24 /* Configuration update could not write files */ +# define RS_TAPE_NOT_ASSIGNED 24 /* Tape not assigned */ +# define RS_VCPU_ALREADY_EXISTS 24 /* Virtual CPU already defined */ +# define RS_VCPU_OUT_OF_RANGE 28 /* CPU beyond range defined in directory */ +# define RS_DEV_INCOMPATIBLE 28 /* Incorrect device type */ +# define RS_EMPTY 28 /* Return buffer is empty */ +# define RS_FILE_NOT_FOUND 28 /* File not found */ +# define RS_NO_MATCH_ON_SEARCH 28 /* No entries match search criteria */ +# define RS_NOT_ALL 28 /* Some images in list not activated */ +# define RS_OUTPUT_NOT_VALID 28 /* Output from function not valid */ +# define RS_PARM_DISK_NOT_RW 28 /* Parm Disk (1 or 2) not R/W */ +# define RS_PW_NEEDED 28 /* Image Disk does not have required password */ +# define RS_SEGMENT_NOT_FOUND 28 /* Shared Storage Segment not found */ +# define RS_SIZE_NOT_SAME 28 /* Image device size not same as source */ +# define RS_DEV_NOT_SHARED 28 /* Device not shared */ +# define RS_BAD_PW 32 /* Incorrect password specified for image disk */ +# define RS_NOT_CONNECTED 32 /* Device not connected */ +# define RS_NOT_IN_LIST 32 /* Name was not in list */ +# define RS_SOME_NOT_DEACT 32 /* Some Images in list not deactivated */ +# define RS_UPDATE_PROCESS_ERROR 32 /* Configuration update internal processer */ +# define RS_SYS_CONF_NOT_FOUND 32 /* System configuration file not found on PARM disk */ +# define RS_DEV_NOT_RESERVED 32 /* Device not reserved */ +# define RS_REQRESP_NOT_VALID 32 /* Internal request error */ +# define RS_SYS_CONF_BAD_DATA 34 /* Syntax Errors with original system configuration */ +# define RS_IVS_NAME_NOT_DASD 36 /* Name not DASD (for ISD) */ +# define RS_LENGTH_NOT_VALID 36 /* Length on input/output not valid */ +# define RS_NAME_IN_LIST 36 /* Name is already in list */ +# define RS_NO_VOLUME 36 /* No such DASD vol mounted on system; Unable to determine dev type */ +# define RS_SOME_NOT_RECYC 36 /* Some images in list not recycled */ +# define RS_SYS_CONF_SYNTX_ERR 36 /* Syntax errors with system configuration update*/ +# define RS_TIME_NOT_VALID 36 /* Force time for deactvation not valid */ +# define RS_VSWITCH_EXISTS 36 /* VSwitch already exists */ +# define RS_DEV_IO_ERROR 36 /* Device I/O error */ +# define RS_NO_DIR_AUTH_TO_LINK 36 /* No directory authority to link */ +# define RS_CPDISK_MODE_NOT_AVAIL 38 /* CP disk modes not available */ +# define RS_PARM_DISK_FULL 40 /* Parm Disk (1 or 2) is full */ +# define RS_VSWITCH_NOT_EXISTS 40 /* VSwitch doesn't exist */ +# define RS_NWDEV_NOT_DETACHED 40 /* Device not detached */ +# define RS_MULTIPLE 40 /* Multiple - multiple what? */ +# define RS_SOCKET 40 /* Socket error */ +# define RS_TYPE_NOT_SUPPORTED 40 /* CPU type not supported on your system */ +# define RS_PDISK_ACC_NOT_ALLOWED 42 /* Parm Disk 1 or 2 - access not allowed */ +# define RS_ALREADY_AUTH 44 /* Image already granted */ +# define RS_PDISK_PW_NOT_SUPPLIED 44 /* Parm Disk (1 or 2) password not supplied */ +# define RS_DASD_IN_USE 44 /* DASD in use */ +# define RS_IS_DISCONNECTED 48 /* Disconnected */ +# define RS_PDISK_PW_INCORRECT 46 /* Parm Disk (1 or 2) password is incorrect */ +# define RS_PARM_DISK_NOT_IN_SRVR_DIR 48 /* Parm Disk (1 or 2) is not in server's user directory */ +# define RS_VLAN_NOT_FOUND 48 /* vLAN not found */ +# define RS_MAX_CONN 52 /* Max connections reached */ +# define RS_CPRELEASE_ERROR 50 /* CPRELEASE error for Parm Disk (1 or 2) */ +# define RS_CPACCESS_ERROR 52 /* CPACCESS error for Parm Disk (1 or 2) */ +# define RS_DEF_VSWITCH_EXISTS 54 /* DEFINE exists in System Config */ +# define RS_GRANT_EXISTS 56 /* GRANT exists in System Config */ +# define RS_REVOKE_FAILED 58 /* MODIFY does not exist in System Config */ +# define RS_DEF_VSWITCH_NOT_EXIST 60 /* DEFINE does not exist in System config */ +# define RS_VSWITCH_CONFLICT 62 /* VSwitch conflict for set API */ +# define RS_DEF_MOD_MULTI_FOUND 64 /* Multiple Define or Modify statements found */ +# define RS_DEF_MOD_MULTI_ERASED 66 /* Multiple Define or Modify statements erased */ +# define RS_DATABASE 68 /* Unable to access database */ +# define RS_UNKNOWN 96 /* Connect request failed for unknown reason */ +# define RS_RETRY 99 /* Suggest retry API call */ +# define RS_ASYNC_OP_SUCCEEDED 100 /* Asynch operation succeeded */ +# define RS_ASYNC_OP_IN_PROGRESS 104 /* Asynch operation in progress */ +# define RS_ASYNC_OP_FAILED 108 /* Asynch operation failed */ +# define RS_CLASS_S_ALREADY_DEFINED 299 /* DEFSEG class S file exists */ +# define RS_NOT_YET_AVAILABLE 999 /* Function not yet available */ +# define RS_DEVNO_REQUIRES_FREE_DISK 1157 /* DEVNO parameter requires the device to be a free volume*/ +# define RS_INVALID_LANID 2783 /* invalid LAN id */ +# define RS_INVALID_LAN_PARM 2795 /* LAN parameter for this LAN id */ +# define RS_RELOCATION_ERRORS 3000 /* Relocation error(s) encountered */ +# define RS_NO_RELOCATION_ACTIVE 3001 /* No active relocations found */ +# define RS_INVALID_PARAMETER 3002 /* Invalid parameter name */ +# define RS_INVALID_OPERAND 3003 /* Invalid parameter operand */ +# define RS_MISSING_PARAMETER 3004 /* Missing parameter */ +# define RS_NOT_IN_SSI 3005 /* System not in an SSI */ +# define RS_SSI_UNSTABLE 3006 /* SSI is not in a stable state */ +# define RS_SSI_CPOWNED_CONFLICT 3007 /* The volume or slot is not on all systems in SSI */ +# define RS_NOT_SSI_MEMBER 3008 /* Not a member of an SSI cluster */ +# define RS_REPAIR_IPL_PARAM 3009 /* IPLed with the REPAIR IPL param */ +# define RS_RELOCATION_MODIFY_ERROR 3010 /* VMRELOCATE Modify error */ +# define RS_NO_SLOTS_AVAILABLE 3011 /* No unique CP_OWNED slot available on system and in config */ +# define RS_VOLUME_NOT_FOUND 3012 /* VOLUME cannot be found */ +# define RS_VOLUME_OFFLINE 3013 /* The volume is offline */ +# define RS_SHARE_UNSUPPORTED 3014 /* Volume does not support sharing */ + +/* + * API functional level + */ +# define RS_530 0 /* 5.3.0 level */ +# define RS_540 540 /* 5.4.0 level */ +# define RS_610 610 /* 6.1.0 level */ +# define RS_611 611 /* 6.1.1 level */ +# define RS_620 620 /* 6.2.0 level */ +# define RS_621 621 /* 6.2.1 level */ +# define RS_630 630 /* 6.3.0 level */ + +/* + * SMAPI Operations + */ +# define Asynchronous_Notification_Disable_DM "Asynchronous_Notification_Disable_DM" +# define Asynchronous_Notification_Enable_DM "Asynchronous_Notification_Enable_DM" +# define Asynchronous_Notification_Query_DM "Asynchronous_Notification_Query_DM" +# define Authorization_List_Add "Authorization_List_Add" +# define Authorization_List_Query "Authorization_List_Query" +# define Authorization_List_Remove "Authorization_List_Remove" +# define Check_Authentication "Check_Authentication" +# define Delete_ABEND_Dump "Delete_ABEND_Dump" +# define Directory_Manager_Local_Tag_Define_DM "Directory_Manager_Local_Tag_Define_DM" +# define Directory_Manager_Local_Tag_Delete_DM "Directory_Manager_Local_Tag_Delete_DM" +# define Directory_Manager_Local_Tag_Query_DM "Directory_Manager_Local_Tag_Query_DM" +# define Directory_Manager_Local_Tag_Set_DM "Directory_Manager_Local_Tag_Set_DM" +# define Directory_Manager_Search_DM "Directory_Manager_Search_DM" +# define Directory_Manager_Task_Cancel_DM "Directory_Manager_Task_Cancel_DM" +# define Event_Stream_Add "Event_Stream_Add" +# define Event_Subscribe "Event_Subscribe" +# define Event_Unsubscribe "Event_Unsubscribe" +# define Image_Activate "Image_Activate" +# define Image_Active_Configuration_Query "Image_Active_Configuration_Query" +# define Image_CPU_Define "Image_CPU_Define" +# define Image_CPU_Define_DM "Image_CPU_Define_DM" +# define Image_CPU_Delete "Image_CPU_Delete" +# define Image_CPU_Delete_DM "Image_CPU_Delete_DM" +# define Image_CPU_Query "Image_CPU_Query" +# define Image_CPU_Query_DM "Image_CPU_Query_DM" +# define Image_CPU_Set_Maximum_DM "Image_CPU_Set_Maximum_DM" +# define Image_Create_DM "Image_Create_DM" +# define Image_Deactivate "Image_Deactivate" +# define Image_Definition_Async_Updates "Image_Definition_Async_Updates" +# define Image_Definition_Create_DM "Image_Definition_Create_DM" +# define Image_Definition_Delete_DM "Image_Definition_Delete_DM" +# define Image_Definition_Query_DM "Image_Definition_Query_DM" +# define Image_Definition_Update_DM "Image_Definition_Update_DM" +# define Image_Delete_DM "Image_Delete_DM" +# define Image_Device_Dedicate "Image_Device_Dedicate" +# define Image_Device_Dedicate_DM "Image_Device_Dedicate_DM" +# define Image_Device_Reset "Image_Device_Reset" +# define Image_Device_Undedicate "Image_Device_Undedicate" +# define Image_Device_Undedicate_DM "Image_Device_Undedicate_DM" +# define Image_Disk_Copy "Image_Disk_Copy" +# define Image_Disk_Copy_DM "Image_Disk_Copy_DM" +# define Image_Disk_Create "Image_Disk_Create" +# define Image_Disk_Create_DM "Image_Disk_Create_DM" +# define Image_Disk_Delete "Image_Disk_Delete" +# define Image_Disk_Delete_DM "Image_Disk_Delete_DM" +# define Image_Disk_Query "Image_Disk_Query" +# define Image_Disk_Share "Image_Disk_Share" +# define Image_Disk_Share_DM "Image_Disk_Share_DM" +# define Image_Disk_Unshare "Image_Disk_Unshare" +# define Image_Disk_Unshare_DM "Image_Disk_Unshare_DM" +# define Image_IPL_Delete_DM "Image_IPL_Delete_DM" +# define Image_IPL_Query_DM "Image_IPL_Query_DM" +# define Image_IPL_Set_DM "Image_IPL_Set_DM" +# define Image_Lock_DM "Image_Lock_DM" +# define Image_Name_Query_DM "Image_Name_Query_DM" +# define Image_Password_Set_DM "Image_Password_Set_DM" +# define Image_Query_Activate_Time "Image_Query_Activate_Time" +# define Image_Query_DM "Image_Query_DM" +# define Image_Recycle "Image_Recycle" +# define Image_Replace_DM "Image_Replace_DM" +# define Image_SCSI_Characteristics_Define_DM "Image_SCSI_Characteristics_Define_DM" +# define Image_SCSI_Characteristics_Query_DM "Image_SCSI_Characteristics_Query_DM" +# define Image_Status_Query "Image_Status_Query" +# define Image_Unlock_DM "Image_Unlock_DM" +# define Image_Volume_Add "Image_Volume_Add" +# define Image_Volume_Delete "Image_Volume_Delete" +# define Image_Volume_Share "Image_Volume_Share" +# define Image_Volume_Space_Define_DM "Image_Volume_Space_Define_DM" +# define Image_Volume_Space_Define_Extended_DM "Image_Volume_Space_Define_Extended_DM" +# define Image_Volume_Space_Query_DM "Image_Volume_Space_Query_DM" +# define Image_Volume_Space_Query_Extended_DM "Image_Volume_Space_Query_Extended_DM" +# define Image_Volume_Space_Remove_DM "Image_Volume_Space_Remove_DM" +# define Metadata_Delete "Metadata_Delete" +# define Metadata_Get "Metadata_Get" +# define Metadata_Set "Metadata_Set" +# define Name_List_Add "Name_List_Add" +# define Name_List_Destroy "Name_List_Destroy" +# define Name_List_Query "Name_List_Query" +# define Name_List_Remove "Name_List_Remove" +# define Page_or_Spool_Volume_Add "Page_or_Spool_Volume_Add" +# define Process_ABEND_Dump "Process_ABEND_Dump" +# define Profile_Create_DM "Profile_Create_DM" +# define Profile_Delete_DM "Profile_Delete_DM" +# define Profile_Lock_DM "Profile_Lock_DM" +# define Profile_Query_DM "Profile_Query_DM" +# define Profile_Replace_DM "Profile_Replace_DM" +# define Profile_Unlock_DM "Profile_Unlock_DM" +# define Prototype_Create_DM "Prototype_Create_DM" +# define Prototype_Delete_DM "Prototype_Delete_DM" +# define Prototype_Name_Query_DM "Prototype_Name_Query_DM" +# define Prototype_Query_DM "Prototype_Query_DM" +# define Prototype_Replace_DM "Prototype_Replace_DM" +# define Query_ABEND_Dump "Query_ABEND_Dump" +# define Query_All_DM "Query_All_DM" +# define Query_API_Functional_Level "Query_API_Functional_Level" +# define Query_Asynchronous_Operation_DM "Query_Asynchronous_Operation_DM" +# define Query_Directory_Manager_Level_DM "Query_Directory_Manager_Level_DM" +# define Response_Recovery "Response_Recovery" +# define Shared_Memory_Access_Add_DM "Shared_Memory_Access_Add_DM" +# define Shared_Memory_Access_Query_DM "Shared_Memory_Access_Query_DM" +# define Shared_Memory_Access_Remove_DM "Shared_Memory_Access_Remove_DM" +# define Shared_Memory_Create "Shared_Memory_Create" +# define Shared_Memory_Delete "Shared_Memory_Delete" +# define Shared_Memory_Query "Shared_Memory_Query" +# define Shared_Memory_Replace "Shared_Memory_Replace" +# define SSI_Query "SSI_Query" +# define Static_Image_Changes_Activate_DM "Static_Image_Changes_Activate_DM" +# define Static_Image_Changes_Deactivate_DM "Static_Image_Changes_Deactivate_DM" +# define Static_Image_Changes_Immediate_DM "Static_Image_Changes_Immediate_DM" +# define System_Config_Syntax_Check "System_Config_Syntax_Check" +# define System_Disk_Accessibility "System_Disk_Accessibility" +# define System_Disk_Add "System_Disk_Add" +# define System_Disk_Query "System_Disk_Query" +# define System_FCP_Free_Query "System_FCP_Free_Query" +# define System_Performance_Threshold_Disable "System_Performance_Threshold_Disable" +# define System_Performance_Threshold_Enable "System_Performance_Threshold_Enable" +# define System_SCSI_Disk_Add "System_SCSI_Disk_Add" +# define System_SCSI_Disk_Delete "System_SCSI_Disk_Delete" +# define System_SCSI_Disk_Query "System_SCSI_Disk_Query" +# define System_WWPN_Query "System_WWPN_Query" +# define Virtual_Channel_Connection_Create "Virtual_Channel_Connection_Create" +# define Virtual_Channel_Connection_Create_DM "Virtual_Channel_Connection_Create_DM" +# define Virtual_Channel_Connection_Delete "Virtual_Channel_Connection_Delete" +# define Virtual_Channel_Connection_Delete_DM "Virtual_Channel_Connection_Delete_DM" +# define Virtual_Network_Adapter_Connect_LAN "Virtual_Network_Adapter_Connect_LAN" +# define Virtual_Network_Adapter_Connect_LAN_DM "Virtual_Network_Adapter_Connect_LAN_DM" +# define Virtual_Network_Adapter_Connect_Vswitch "Virtual_Network_Adapter_Connect_Vswitch" +# define Virtual_Network_Adapter_Connect_Vswitch_DM "Virtual_Network_Adapter_Connect_Vswitch_DM" +# define Virtual_Network_Adapter_Connect_Vswitch_Extended "Virtual_Network_Adapter_Connect_Vswitch_Extended" +# define Virtual_Network_Adapter_Create "Virtual_Network_Adapter_Create" +# define Virtual_Network_Adapter_Create_DM "Virtual_Network_Adapter_Create_DM" +# define Virtual_Network_Adapter_Create_Extended "Virtual_Network_Adapter_Create_Extended" +# define Virtual_Network_Adapter_Create_Extended_DM "Virtual_Network_Adapter_Create_Extended_DM" +# define Virtual_Network_Adapter_Delete "Virtual_Network_Adapter_Delete" +# define Virtual_Network_Adapter_Delete_DM "Virtual_Network_Adapter_Delete_DM" +# define Virtual_Network_Adapter_Disconnect "Virtual_Network_Adapter_Disconnect" +# define Virtual_Network_Adapter_Disconnect_DM "Virtual_Network_Adapter_Disconnect_DM" +# define Virtual_Network_Adapter_Query "Virtual_Network_Adapter_Query" +# define Virtual_Network_LAN_Access "Virtual_Network_LAN_Access" +# define Virtual_Network_LAN_Access_Query "Virtual_Network_LAN_Access_Query" +# define Virtual_Network_LAN_Create "Virtual_Network_LAN_Create" +# define Virtual_Network_LAN_Delete "Virtual_Network_LAN_Delete" +# define Virtual_Network_LAN_Query "Virtual_Network_LAN_Query" +# define Virtual_Network_OSA_Query "Virtual_Network_OSA_Query" +# define Virtual_Network_VLAN_Query_Stats "Virtual_Network_VLAN_Query_Stats" +# define Virtual_Network_Vswitch_Create "Virtual_Network_Vswitch_Create" +# define Virtual_Network_Vswitch_Create_Extended "Virtual_Network_Vswitch_Create_Extended" +# define Virtual_Network_Vswitch_Delete "Virtual_Network_Vswitch_Delete" +# define Virtual_Network_Vswitch_Delete_Extended "Virtual_Network_Vswitch_Delete_Extended" +# define Virtual_Network_Vswitch_Query "Virtual_Network_Vswitch_Query" +# define Virtual_Network_Vswitch_Query_Extended "Virtual_Network_Vswitch_Query_Extended" +# define Virtual_Network_Vswitch_Query_Stats "Virtual_Network_Vswitch_Query_Stats" +# define Virtual_Network_Vswitch_Set "Virtual_Network_Vswitch_Set" +# define Virtual_Network_Vswitch_Set_Extended "Virtual_Network_Vswitch_Set_Extended" +# define VMRELOCATE "VMRELOCATE" +# define VMRELOCATE_Image_Attributes "VMRELOCATE_Image_Attributes" +# define VMRELOCATE_Modify "VMRELOCATE_Modify" +# define VMRELOCATE_Status "VMRELOCATE_Status" +# define VMRM_Configuration_Query "VMRM_Configuration_Query" +# define VMRM_Configuration_Update "VMRM_Configuration_Update" +# define VMRM_Measurement_Query "VMRM_Measurement_Query" + +# define FORCE_IMMED "IMMED" +# define FORCE_WITHIN "WITHIN 99999" + +/* + * Standard fields in a response from SMAPI server + */ +typedef struct { + uint32_t outLen; /* Length of output data */ + uint32_t reqId; /* Request ID to which response refers */ + uint32_t rc; /* Return code */ + uint32_t reason; /* Reason code */ +} smapiOutHeader_t; + +typedef struct { + smapiOutHeader_t hdr; /* Output header */ + uint32_t lArray; /* Length of array output */ + char array[0]; /* Start of array output */ +} smapiArrayHeader_t; + +/* + * Structures returned from Image_Active_Configuration_Query + */ +typedef struct { + smapiOutHeader_t hdr; + int32_t memSize; + uint8_t memUnit; +# define SMAPI_MEMUNIT_KB 1 +# define SMAPI_MEMUNIT_MB 2 +# define SMAPI_MEMUNIT_GB 3 + uint8_t shareType; +# define SMAPI_SHRTYPE_R 1 +# define SMAPI_SHRTYPE_A 2 + int32_t lShare; + char share[0]; +} __attribute__ ((__packed__)) zvm_actImgHdr_t; + +typedef struct { + char share[5]; +} zvm_actImgShr_t; + +typedef struct { + int32_t nCPU; + int32_t lCPUArray; + char cpuArray[0]; +} zvm_actImgCPUArr_t; + +typedef struct { + int32_t lCPUStruct; + char cpuStruct[0]; +} zvm_actImgCPUHdr_t; + +typedef struct { + int32_t cpuNumber; + int32_t lCPUId; + char cpuId[16]; +} zvm_actImgCPUId_t; + +typedef struct { + uint8_t cpuState; +# define SMAPI_CPUSTATE_BASE 1 +# define SMAPI_CPUSTATE_STOPPED 2 +# define SMAPI_CPUSTATE_CHECK 3 +# define SMAPI_CPUSTATE_ACTIVE 4 + int32_t lDevArray; + char devArray[0]; +} __attribute__ ((__packed__)) zvm_actImgCPUState_t; + +typedef struct { + int32_t lDevStruct; + char devStruct[0]; +} zvm_actImgDevHdr_t; + +typedef struct { + uint8_t devType; +# define SMAPI_DEVTYPE_CONS 1 +# define SMAPI_DEVTYPE_RDR 2 +# define SMAPI_DEVTYPE_PUN 3 +# define SMAPI_DEVTYPE_PRT 4 +# define SMAPI_DEVTYPE_DASD 5 + int32_t lDevAddr; + uint8_t devAddr[4]; +} __attribute__ ((__packed__)) zvm_actImgDev_t; + +typedef struct { + int sd; + int reason; + uint32_t timeOut; + uint32_t delay; + char target[9]; + char authUser[9]; + char authPass[9]; + char node[9]; + char smapiSrv[128]; +} zvm_driver_t; + +int zvm_smapi_open(zvm_driver_t *); +int zvm_smapi_send(zvm_driver_t *, void *, uint32_t *, int32_t); +int zvm_smapi_recv(zvm_driver_t *, void **, int32_t *); +int zvm_smapi_close(zvm_driver_t *); +int zvm_smapi_imageActivate(zvm_driver_t *); +int zvm_smapi_imageActiveQuery(zvm_driver_t *); +int zvm_smapi_imageDeactivate(zvm_driver_t *); +int zvm_smapi_imageRecycle(zvm_driver_t *); +int zvm_smapi_imageQuery(zvm_driver_t *); + +#endif /* FENCE_ZVM_H */ diff --git a/agents/zvm/fence_zvm_man_page b/agents/zvm/fence_zvm_man_page new file mode 100644 index 0000000..057cc6d --- /dev/null +++ b/agents/zvm/fence_zvm_man_page @@ -0,0 +1,88 @@ +.TH fence_zvm 8 + +.SH NAME +fence_zvm - Power Fencing agent for GFS on System z z/VM Clusters + +.SH SYNOPSIS +.B +fence_zvm +[\fIOPTION\fR]... + +.SH DESCRIPTION +fence_zvm is a Power Fencing agent used on a GFS virtual machine in a System z z/VM cluster. +It uses the SMAPI interface to recycle an active image. + +fence_zvm accepts options on the command line as well as from stdin. +fence_node sends the options through stdin when it execs the agent. +fence_zvm can be run by itself with command line options which is useful +for testing. + +Vendor URL: http://www.sinenomine.net + +.SH OPTIONS +.TP +\fB-o --action\fP +Fencing action: "off" - deactivate virtual machine; "on" - activate virtual machine; "metadata" - display device metadata" - describe fence agent parameters; "status" - state of virtual machine +.TP +\fB--delay\fP \fIseconds\fP +Time to delay fencing action in seconds +.TP +\fB-n --plug\fP \fItarget\fP +Name of virtual machine to recycle. +.TP +\fB-h --help\fP +Print out a help message describing available options, then exit. +.TP +\fB-a --ip\fP \fIsmapi Server\fP +\fBName\fP of SMAPI server virtual machine. To be consistent with other fence agents this name is a little misleading: it is the name of the virtual machine not its IP address or hostname. +.TP +\fB--zvmsys\fP \fIz/VM System\fP +\fBName\fP of z/VM on which the SMAPI server virtual machine resides. Optional - defaults to system on which the node is running. +.TP +\fB-h --help\fP +Display usage information +.TP +\fI-t --timeout = < shutdown timeout >\fP +Amount of \fIgrace\fP time to give the virtual machine to shutdown cleanly before being +forcibly terminated. Currently, this option is ignored. + +.SH STDIN PARAMETERS +.TP +\fIagent = < param >\fP +This option is used by fence_node(8) and is ignored by fence_zvm. +.TP +\fIaction = < action >\fP +Fencing action: "off" - fence off device; "metadata" - display device metadata; "status" - state of device +.TP +\fIport = < target >\fP +Name of virtual machine to recycle. +.TP +\fIipaddr= < server name >\fP +\fBName\fP of SMAPI server virtual machine. To be consistent with other fence agents thisname is a little misleading: it is the name of the virtual machine not its IP address or hostname. +.TP +\fItimeout = < shutdown timeout >\fP +Amount of \fIgrace\fP time to give the virtual machine to shutdown cleanly before being +forcibly terminated. Currently, this option is ignored. + +.SH SEE ALSO +fence(8), fenced(8), fence_node(8) + +.SH NOTES +To use this agent the z/VM SMAPI service needs to be configured to allow the virtual +machine running this agent to connect to it and issue the image_recycle operation. +This involves updating the VSMWORK1 AUTHLIST VMSYS:VSMWORK1. file. The entry should look +something similar to this: + +.nf +Column 1 Column 66 Column 131 +| | | +V V V +XXXXXXXX ALL IMAGE_CHARACTERISTICS +.fi + +Where XXXXXXX is the name of the virtual machine used in the authuser field of the request. This virtual machine also has to be authorized +to access the system's directory manager. + +In addition, the VM directory entry that defines this virtual machine requires the +IUCV ANY statement (or IUCV <userid of SMAPI Server>). This authorizes use of IUCV +to connect to the SMAPI server. diff --git a/agents/zvm/fence_zvmip.c b/agents/zvm/fence_zvmip.c new file mode 100644 index 0000000..b16de48 --- /dev/null +++ b/agents/zvm/fence_zvmip.c @@ -0,0 +1,1001 @@ +/* + * fence_zvmip.c: SMAPI interface for managing zVM Guests + * + * Copyright (C) 2012 Sine Nomine Associates + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Neale Ferguson <neale@sinenomine.net> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <sys/types.h> +#include <dirent.h> +#include <time.h> +#include <sys/stat.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include <string.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netiucv/iucv.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <getopt.h> +#include <ctype.h> +#include <syslog.h> +#include "fence_zvm.h" + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define DEFAULT_TIMEOUT 300 +#define DEFAULT_DELAY 0 + +#define ACT_OFFON 0 +#define ACT_OFF 1 +#define ACT_ON 2 +#define ACT_METADATA 3 +#define ACT_STATUS 4 +#define ACT_MONITOR 5 +#define ACT_LIST 6 +#define ACT_HELP 7 + +static int zvm_smapi_reportError(void *, void *); + +static struct option longopts[] = { + {"action", required_argument, NULL, 'o'}, + {"delay", required_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {"ipaddr", required_argument, NULL, 'a'}, + {"password", required_argument, NULL, 'p'}, + {"plug", required_argument, NULL, 'n'}, + {"timeout", required_argument, NULL, 't'}, + {"username", required_argument, NULL, 'u'}, + {NULL, 0, NULL, 0} +}; + +static const char *optString = "a:o:hn:p:t:u:"; + +static int zvm_metadata(void); +static int usage(void); + +/** + * zvm_smapi_open: + * @zvm: z/VM driver information + * + * Opens a connection with the z/VM SMAPI server + */ +int +zvm_smapi_open(zvm_driver_t *zvm) +{ + int rc = -1, + option = SO_REUSEADDR, + optVal = 1, + lOption = sizeof(optVal); + struct addrinfo hints, *ai; + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_TCP; + if ((rc = getaddrinfo(zvm->smapiSrv, "44444", &hints, &ai)) == 0) { + if ((zvm->sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) != -1) { + rc = setsockopt(zvm->sd,SOL_SOCKET,option,&optVal,lOption); + + if ((rc = connect(zvm->sd, ai->ai_addr, ai->ai_addrlen)) == -1) { + syslog(LOG_ERR, "Error connecting to %s - %m", zvm->smapiSrv); + close(zvm->sd); + } + } else { + syslog(LOG_ERR, "Error creating socket - %m"); + } + } else { + syslog(LOG_ERR, "Error resolving server address: %s", gai_strerror(rc)); + } + return(rc); +} + +/** + * zvm_smapi_imageRecycle + * @zvm: z/VM driver information + * + * Deactivates a virtual image + */ +int +zvm_smapi_imageRecycle(zvm_driver_t *zvm) +{ + struct _inPlist { + int32_t lPlist; + int32_t lFName; + char fName[13]; + } __attribute__ ((packed)) *inPlist; + struct _authUser { + int32_t lAuthUser; + char userId[0]; + } __attribute__ ((packed)) *authUser; + struct _authPass { + int32_t lAuthPass; + char password[0]; + } __attribute__ ((packed)) *authPass; + struct _image { + int32_t lTarget; + char target[0]; + } __attribute__ ((packed)) *image; + int32_t lInPlist; + struct _outPlist { + smapiOutHeader_t hdr; + int32_t nActive; + int32_t nInActive; + int32_t lFail; + char failArray[0]; + } *outPlist = NULL; + void *pOut = NULL; + int32_t lRsp; + uint32_t reqId; + int rc; + + /* + * Implement any delay + */ + if (zvm->delay > 0) + sleep(zvm->delay); + + lInPlist = sizeof(*inPlist) + sizeof(*authUser) + strlen(zvm->authUser) + + sizeof(*authPass) + strlen(zvm->authPass) + sizeof(*image) + + + strlen(zvm->target); + inPlist = malloc(lInPlist); + if (inPlist != NULL) { + authUser = (void *) ((uintptr_t) inPlist + sizeof(*inPlist)); + authPass = (void *) ((uintptr_t) authUser + sizeof(*authUser) + + strlen(zvm->authUser)); + image = (void *) ((uintptr_t) authPass + sizeof(*authPass) + + strlen(zvm->authPass)); + inPlist->lPlist = lInPlist - sizeof(inPlist->lPlist); + inPlist->lFName = sizeof(inPlist->fName); + memcpy(inPlist->fName, Image_Recycle, sizeof(inPlist->fName)); + authUser->lAuthUser = strlen(zvm->authUser); + memcpy(authUser->userId, zvm->authUser, strlen(zvm->authUser)); + authPass->lAuthPass = strlen(zvm->authPass); + memcpy(authPass->password, zvm->authPass, strlen(zvm->authPass)); + image->lTarget = strlen(zvm->target); + strncpy(image->target, zvm->target, strlen(zvm->target)); + if ((rc = zvm_smapi_send(zvm, inPlist, &reqId, lInPlist)) != -1) { + if ((rc = zvm_smapi_recv(zvm, &pOut, &lRsp)) != -1) { + outPlist = pOut; + if (outPlist->hdr.rc == 0) { + syslog(LOG_INFO, "Recycling of %s successful", + zvm->target); + rc = 0; + } else { + if ((ntohl(outPlist->hdr.rc) == RCERR_IMAGEOP) & + ((ntohl(outPlist->hdr.reason) == RS_NOT_ACTIVE) | + (ntohl(outPlist->hdr.reason) == RS_BEING_DEACT))) { + syslog(LOG_INFO, "Recycling of %s successful", + zvm->target); + rc = 0; + } else { + rc = ntohl(outPlist->hdr.rc); + zvm->reason = ntohl(outPlist->hdr.reason); + (void) zvm_smapi_reportError(inPlist, outPlist); + } + } + } + } + free(inPlist); + free(outPlist); + } else { + syslog(LOG_ERR, "%s - cannot allocate parameter list", __func__); + rc = -1; + } + return(rc); +} + +/** + * zvm_smapi_imageDeactivate + * @zvm: z/VM driver information + * + * Deactivates a virtual image + */ +int +zvm_smapi_imageDeactivate(zvm_driver_t *zvm) +{ + struct _inPlist { + int32_t lPlist; + int32_t lFName; + char fName[16]; + } __attribute__ ((packed)) *inPlist; + struct _authUser { + int32_t lAuthUser; + char userId[0]; + } __attribute__ ((packed)) *authUser; + struct _authPass { + int32_t lAuthPass; + char password[0]; + } __attribute__ ((packed)) *authPass; + struct _image { + int32_t lTarget; + char target[0]; + } __attribute__ ((packed)) *image; + struct _deactTime { + int32_t lForceTime; + char forceTime[5]; + } __attribute__ ((__packed__)) *deactTime; + int32_t lInPlist; + struct _outPlist { + smapiOutHeader_t hdr; + int32_t nActive; + int32_t nInActive; + int32_t lFail; + char failArray[0]; + } *outPlist = NULL; + void *pOut = NULL; + int32_t lRsp; + uint32_t reqId; + int rc; + + /* + * Implement any delay + */ + if (zvm->delay > 0) + sleep(zvm->delay); + + lInPlist = sizeof(*inPlist) + sizeof(*authUser) + strlen(zvm->authUser) + + sizeof(*authPass) + strlen(zvm->authPass) + sizeof(*image) + + sizeof(*deactTime) + strlen(zvm->target); + inPlist = malloc(lInPlist); + if (inPlist != NULL) { + authUser = (void *) ((uintptr_t) inPlist + sizeof(*inPlist)); + authPass = (void *) ((uintptr_t) authUser + sizeof(*authUser) + + strlen(zvm->authUser)); + image = (void *) ((uintptr_t) authPass + sizeof(*authPass) + + strlen(zvm->authPass)); + deactTime = (void *) ((intptr_t) image + sizeof(*image) + + strlen(zvm->target)); + inPlist->lPlist = lInPlist - sizeof(inPlist->lPlist); + inPlist->lFName = sizeof(inPlist->fName); + memcpy(inPlist->fName, Image_Deactivate, sizeof(inPlist->fName)); + authUser->lAuthUser = strlen(zvm->authUser); + memcpy(authUser->userId, zvm->authUser, strlen(zvm->authUser)); + authPass->lAuthPass = strlen(zvm->authPass); + memcpy(authPass->password, zvm->authPass, strlen(zvm->authPass)); + image->lTarget = strlen(zvm->target); + memcpy(image->target, zvm->target, strlen(zvm->target)); + deactTime->lForceTime = sizeof(deactTime->forceTime); + memcpy(deactTime->forceTime, "IMMED", sizeof(deactTime->forceTime)); + if ((rc = zvm_smapi_send(zvm, inPlist, &reqId, lInPlist)) != -1) { + if ((rc = zvm_smapi_recv(zvm, &pOut, &lRsp)) != -1) { + outPlist = pOut; + if (outPlist->hdr.rc == 0) { + syslog(LOG_INFO, "Deactivation of %s successful", + zvm->target); + rc = 0; + } else { + if ((outPlist->hdr.rc == RCERR_IMAGEOP) & + ((outPlist->hdr.reason == RS_NOT_ACTIVE) | + (outPlist->hdr.reason == RS_BEING_DEACT))) { + syslog(LOG_INFO, "Deactivation of %s successful", + zvm->target); + rc = 0; + } else { + rc = outPlist->hdr.rc; + zvm->reason = outPlist->hdr.reason; + (void) zvm_smapi_reportError(inPlist, outPlist); + } + } + } + } + free(inPlist); + free(outPlist); + } else { + syslog(LOG_ERR, "%s - cannot allocate parameter list", __func__); + rc = -1; + } + return(rc); +} + +/** + * zvm_smapi_imageActivate + * @zvm: z/VM driver information + * + * Deactivates a virtual image + */ +int +zvm_smapi_imageActivate(zvm_driver_t *zvm) +{ + struct _inPlist { + int32_t lPlist; + int32_t lFName; + char fName[14]; + } __attribute__ ((packed)) *inPlist; + struct _authUser { + int32_t lAuthUser; + char userId[0]; + } __attribute__ ((packed)) *authUser; + struct _authPass { + int32_t lAuthPass; + char password[0]; + } __attribute__ ((packed)) *authPass; + struct _image { + int32_t lTarget; + char target[0]; + } __attribute__ ((packed)) *image; + int32_t lInPlist; + struct _outPlist { + smapiOutHeader_t hdr; + int32_t nActive; + int32_t nInActive; + int32_t lFail; + char failArray[0]; + } *outPlist = NULL; + void *pOut = NULL; + int32_t lRsp; + uint32_t reqId; + int rc; + + /* + * Implement any delay + */ + if (zvm->delay > 0) + sleep(zvm->delay); + + lInPlist = sizeof(*inPlist) + sizeof(*authUser) + strlen(zvm->authUser) + + sizeof(*authPass) + strlen(zvm->authPass) + sizeof(*image) + + strlen(zvm->target); + inPlist = malloc(lInPlist); + if (inPlist != NULL) { + authUser = (void *) ((uintptr_t) inPlist + sizeof(*inPlist)); + authPass = (void *) ((uintptr_t) authUser + sizeof(*authUser) + + strlen(zvm->authUser)); + image = (void *) ((uintptr_t) authPass + sizeof(*authPass) + + strlen(zvm->authPass)); + inPlist->lPlist = lInPlist - sizeof(inPlist->lPlist); + inPlist->lFName = sizeof(inPlist->fName); + memcpy(inPlist->fName, Image_Activate, sizeof(inPlist->fName)); + authUser->lAuthUser = strlen(zvm->authUser); + memcpy(authUser->userId, zvm->authUser, strlen(zvm->authUser)); + authPass->lAuthPass = strlen(zvm->authPass); + memcpy(authPass->password, zvm->authPass, strlen(zvm->authPass)); + image->lTarget = strlen(zvm->target); + memcpy(image->target, zvm->target, strlen(zvm->target)); + if ((rc = zvm_smapi_send(zvm, inPlist, &reqId, lInPlist)) != -1) { + if ((rc = zvm_smapi_recv(zvm, &pOut, &lRsp)) != -1) { + outPlist = pOut; + if (outPlist->hdr.rc == 0) { + syslog(LOG_INFO, "Activation of %s successful", + zvm->target); + rc = 0; + } else { + if ((outPlist->hdr.rc == RCERR_IMAGEOP) & + (outPlist->hdr.reason == RS_ALREADY_ACTIVE)) { + syslog(LOG_INFO, "Activation of %s successful", + zvm->target); + rc = 0; + } else { + rc = outPlist->hdr.rc; + zvm->reason = outPlist->hdr.reason; + (void) zvm_smapi_reportError(inPlist, outPlist); + } + } + } + } + free(inPlist); + free(outPlist); + } else { + syslog(LOG_ERR, "%s - cannot allocate parameter list", __func__); + rc = -1; + } + return(rc); +} + +/** + * zvm_smapi_imageQuery + * @zvm: z/VM driver information + * + * Queries the state of a virtual image + */ +int +zvm_smapi_imageQuery(zvm_driver_t *zvm) +{ + struct _inPlist { + int32_t lPlist; + int32_t lFName; + char fName[18]; + int32_t lUser; + int32_t lPass; + int32_t lTarget; + char target[0]; + } __attribute__ ((__packed__)) *inPlist; + int32_t lInPlist; + struct _outPlist { + smapiOutHeader_t hdr; + int32_t lNames; + char nameArray[0]; + } *outPlist = NULL; + void *pOut = NULL; + int32_t lRsp; + uint32_t reqId; + int rc; + + /* + * Implement any delay + */ + if (zvm->delay > 0) + sleep(zvm->delay); + + lInPlist = sizeof(*inPlist) + strlen(zvm->target); + inPlist = malloc(lInPlist); + if (inPlist != NULL) { + inPlist->lPlist = lInPlist - sizeof(inPlist->lPlist); + inPlist->lFName = sizeof(inPlist->fName); + memcpy(inPlist->fName, Image_Status_Query, sizeof(inPlist->fName)); + inPlist->lUser = inPlist->lPass = 0; + inPlist->lTarget = strlen(zvm->target); + memcpy(inPlist->target, zvm->target, inPlist->lTarget); + if ((rc = zvm_smapi_send(zvm, inPlist, &reqId, lInPlist)) != -1) { + if ((rc = zvm_smapi_recv(zvm, &pOut, &lRsp)) != -1) { + outPlist = pOut; + if (outPlist->hdr.rc == 0) { + if (outPlist->hdr.reason == 0) { + syslog(LOG_INFO, "Node %s is active", + zvm->target); + rc = 0; + } else { + syslog(LOG_INFO, "Node %s is inactive", + zvm->target); + rc = 2; + } + } else { + rc = 1; + zvm->reason = outPlist->hdr.reason; + (void) zvm_smapi_reportError(inPlist, outPlist); + } + } + } + free(inPlist); + free(outPlist); + } else { + syslog(LOG_ERR, "%s - cannot allocate parameter list", __func__); + rc = -1; + } + return(rc); +} + +/** + * zvm_smapi_send: + * @zvm: z/VM driver information + * @reqid: Returned request id + * @req: Request parameter list + * @lSend: Length of request + * + * Send a request to the SMAPI server and retrieve the request id + */ +int +zvm_smapi_send(zvm_driver_t *zvm, void *req, uint32_t *reqId, int32_t lSend) +{ + int rc, + nFds; + fd_set readFds; + struct timeval timeout; + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + zvm->reason = -1; + if ((rc = zvm_smapi_open(zvm)) == 0) { + rc = send(zvm->sd,req,lSend,0); + if (rc != -1) { + FD_ZERO(&readFds); + FD_SET(zvm->sd,&readFds); + nFds = zvm->sd + 1; + + if ((rc = select(nFds,&readFds,NULL,NULL,&timeout)) != -1) { + /* + * Get request ID + */ + rc = recv(zvm->sd,reqId,sizeof(*reqId),0); + if (rc == -1) + syslog(LOG_ERR, "Error receiving from SMAPI - %m"); + } + } else + syslog(LOG_ERR, "Error sending to SMAPI - %m"); + } + return(rc); +} + +/** + * zvm_smapi_recv: + * @zvm: z/VM driver information + * @req: Returned response parameter list + * @lRsp: Length of response + * + * Receive a response from the SMAPI server + */ +int +zvm_smapi_recv(zvm_driver_t *zvm, void **rsp, int32_t *lRsp) +{ + int rc, + lRem = 0, + nFds; + void *pRecv = rsp; + fd_set readFds; + smapiOutHeader_t *out; + struct timeval timeout; + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + FD_ZERO(&readFds); + FD_SET(zvm->sd,&readFds); + nFds = zvm->sd + 1; + + zvm->reason = -1; + if ((rc = select(nFds,&readFds,NULL,NULL,&timeout)) != -1) { + /* + * Get response length + */ + if ((rc = recv(zvm->sd,lRsp,sizeof(*lRsp),0)) != -1) { + *lRsp = ntohl(*lRsp); + lRem = *lRsp; + if (*rsp == NULL) + *rsp = malloc(*lRsp + sizeof(out->outLen)); + out = *rsp; + out->outLen = *lRsp; + pRecv = &out->reqId; + while (lRem > 0) { + if ((rc = recv(zvm->sd,pRecv,lRem,0)) != -1) { + lRem -= rc; + pRecv = (void *) ((uintptr_t) pRecv + rc); + } else + syslog(LOG_ERR, "Error receiving from SMAPI - %m"); + (void) zvm_smapi_close(zvm); + return(rc); + } + zvm->reason = out->reason; + } + } else + syslog(LOG_ERR, "Error receiving from SMAPI - %m"); + + (void) zvm_smapi_close(zvm); + + return(rc); +} + +/** + * zvm_smapi_close: + * @zvm: z/VM driver information + * + * Close a connection with the z/VM SMAPI server + */ +int +zvm_smapi_close(zvm_driver_t *zvm) +{ + close(zvm->sd); + return(0); +} + +/** + * zvm_smapi_reportError + * @inHdr - Input parameter list header + * @outHdr - Output parameter list header + * + * Report an error from the SMAPI server + */ +static int +zvm_smapi_reportError(void *inHdr, void *oHdr) +{ + struct _inParm { + int32_t lPlist; + int32_t lFName; + char fName[0]; + } *inParm = inHdr; + smapiOutHeader_t *outHdr = oHdr; + char fName[64]; + + memset(fName, 0, sizeof(fName)); + memcpy(fName, inParm->fName, inParm->lFName); + syslog(LOG_ERR, "%s - returned (%d,%d)", + fName, ntohl(outHdr->rc), ntohl(outHdr->reason)); + return(-1); +} + + +/** + * trim - Trim spaces from string + * @str - Pointer to string + * + */ +static int +trim(char *str) +{ + char *p; + int len; + + if (!str) + return (0); + + len = strlen (str); + + while (len--) { + if (isspace (str[len])) { + str[len] = 0; + } else { + break; + } + } + + for (p = str; *p && isspace (*p); p++); + + memmove(str, p, strlen (p) + 1); + + return (strlen (str)); +} + +/** + * get_options_stdin - get options from stdin + * @zvm - Pointer to driver information + * + */ +static int +get_options_stdin (zvm_driver_t *zvm) +{ + char buf[1024], + *endPtr, + *opt, + *arg; + int32_t lSrvName, + lTarget; + int fence = ACT_OFFON; + + while (fgets (buf, sizeof (buf), stdin) != 0) { + if (trim(buf) == 0) { + continue; + } + if (buf[0] == '#') { + continue; + } + + opt = buf; + + if ((arg = strchr(opt, '=')) != 0) { + *arg = 0; + arg++; + } else { + continue; + } + + if (trim(arg) == 0) + continue; + + if (!strcasecmp (opt, "action")) { + if (strcasecmp(arg, "reboot") == 0) { + fence = ACT_OFFON; + } else if (strcasecmp(arg, "off") == 0) { + fence = ACT_OFF; + } else if (strcasecmp(arg, "on") == 0) { + fence = ACT_ON; + } else if (strcasecmp(arg, "metadata") == 0) { + fence = ACT_METADATA; + } else if (strcasecmp(arg, "status") == 0) { + fence = ACT_STATUS; + } else if (strcasecmp(arg, "monitor") == 0) { + fence = ACT_MONITOR; + } else if (strcasecmp(arg, "list") == 0) { + fence = ACT_LIST; + } else { + fence = ACT_HELP; + } + } else if (!strcasecmp (opt, "ipaddr")) { + lSrvName = MIN(strlen(arg), sizeof(zvm->smapiSrv)-1); + memcpy(zvm->smapiSrv, arg, lSrvName); + continue; + } else if (!strcasecmp (opt, "login")) { + lSrvName = MIN(strlen(arg), sizeof(zvm->authUser)-1); + memcpy(zvm->authUser, arg, lSrvName); + continue; + } else if (!strcasecmp (opt, "passwd")) { + lSrvName = MIN(strlen(arg), sizeof(zvm->authPass)-1); + memcpy(zvm->authPass, arg, lSrvName); + continue; + } else if (!strcasecmp (opt, "port")) { + lTarget = MIN(strlen(arg), sizeof(zvm->target)-1); + strncpy(zvm->target, arg, lTarget); + continue; + } if (!strcasecmp (opt, "timeout")) { + zvm->timeOut = strtoul(arg, &endPtr, 10); + if (*endPtr != 0) { + syslog(LOG_WARNING, "Invalid timeout value specified %s " + "defaulting to %d", + arg, DEFAULT_TIMEOUT); + zvm->timeOut = DEFAULT_TIMEOUT; + } + } else if (!strcasecmp (opt, "help")) { + fence = ACT_HELP; + } + } + return(fence); +} + +/** + * get_options - get options from the command line + * @argc - Count of arguments + * @argv - Array of character strings + * @zvm - Pointer to driver information + * + */ +static int +get_options(int argc, char **argv, zvm_driver_t *zvm) +{ + int c, + fence = ACT_OFFON; + int32_t lSrvName, + lTarget; + char *endPtr; + + while ((c = getopt_long(argc, argv, optString, longopts, NULL)) != -1) { + switch (c) { + case 'a' : + lSrvName = MIN(strlen(optarg), sizeof(zvm->smapiSrv)-1); + memcpy(zvm->smapiSrv, optarg, lSrvName); + break; + case 'n' : + lTarget = MIN(strlen(optarg), sizeof(zvm->target)-1); + memcpy(zvm->target, optarg, lTarget); + break; + case 'o' : + if (strcasecmp(optarg, "reboot") == 0) { + fence = ACT_OFFON; + } else if (strcasecmp(optarg, "off") == 0) { + fence = ACT_OFF; + } else if (strcasecmp(optarg, "on") == 0) { + fence = ACT_ON; + } else if (strcasecmp(optarg, "metadata") == 0) { + fence = ACT_METADATA; + } else if (strcasecmp(optarg, "status") == 0) { + fence = ACT_STATUS; + } else if (strcasecmp(optarg, "monitor") == 0) { + fence = ACT_MONITOR; + } else if (strcasecmp(optarg, "list") == 0) { + fence = ACT_LIST; + } else { + fence = ACT_HELP; + } + break; + case 'p' : + lSrvName = MIN(strlen(optarg), 8); + memcpy(zvm->authPass, optarg, lSrvName); + break; + case 'u' : + lSrvName = MIN(strlen(optarg), 8); + memcpy(zvm->authUser, optarg, lSrvName); + break; + case 't' : + zvm->timeOut = strtoul(optarg, &endPtr, 10); + if (*endPtr != 0) { + syslog(LOG_WARNING, "Invalid timeout value specified: %s - " + "defaulting to %d", + optarg, DEFAULT_TIMEOUT); + zvm->timeOut = DEFAULT_TIMEOUT; + } + break; + case 'd' : + zvm->delay = strtoul(optarg, &endPtr, 10); + if (*endPtr != 0) { + syslog(LOG_WARNING, "Invalid delay value specified: %s - " + "defaulting to %d", + optarg, DEFAULT_DELAY); + zvm->delay = DEFAULT_DELAY; + } + break; + default : + fence = ACT_HELP; + } + } + return(fence); +} + +/** + * zvm_metadata - Show fence metadata + * @self - Path to this executable + * + */ +static int +zvm_metadata() +{ + fprintf (stdout, "<?xml version=\"1.0\" ?>\n"); + fprintf (stdout, "<resource-agent name=\"fence_zvmip\""); + fprintf (stdout, " shortdesc=\"Fence agent for use with z/VM Virtual Machines\">\n"); + fprintf (stdout, "<longdesc>"); + fprintf (stdout, "The fence_zvm agent is intended to be used with with z/VM SMAPI service via TCP/IP"); + fprintf (stdout, "</longdesc>\n"); + fprintf (stdout, "<vendor-url>http://www.ibm.com</vendor-url>\n"); + + fprintf (stdout, "<parameters>\n"); + + fprintf (stdout, "\t<parameter name=\"port\" unique=\"1\" required=\"1\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-n, --plug\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Name of the Virtual Machine to be fenced"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"ipaddr\" unique=\"1\" required=\"1\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-i, --ip\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "IP Name or Address of SMAPI Server"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"login\" unique=\"1\" required=\"1\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-u, --username\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Name of authorized SMAPI user"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"passwd\" unique=\"1\" required=\"1\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-p, --password\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Password of authorized SMAPI user"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"action\" unique=\"1\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-o, --action\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" default=\"off\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Fencing action"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"delay\" unique=\"1\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"--delay\" />\n"); + fprintf (stdout, "\t\t<content type=\"string\" default=\"0\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Time to delay fencing action in seconds"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "\t<parameter name=\"usage\" unique=\"1\" required=\"0\">\n"); + fprintf (stdout, "\t\t<getopt mixed=\"-h, --help\" />\n"); + fprintf (stdout, "\t\t<content type=\"boolean\" />\n"); + fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n", + "Print usage"); + fprintf (stdout, "\t</parameter>\n"); + + fprintf (stdout, "</parameters>\n"); + + fprintf (stdout, "<actions>\n"); + fprintf (stdout, "\t<action name=\"off\" />\n"); + fprintf (stdout, "\t<action name=\"on\" automatic=\"0\" />\n"); + fprintf (stdout, "\t<action name=\"list\" />\n"); + fprintf (stdout, "\t<action name=\"metadata\" />\n"); + fprintf (stdout, "\t<action name=\"monitor\" />\n"); + fprintf (stdout, "\t<action name=\"status\" />\n"); + fprintf (stdout, "\t<action name=\"reboot\" />\n"); + fprintf (stdout, "</actions>\n"); + + fprintf (stdout, "</resource-agent>\n"); + + return(0); + +} + +/** + * usage - display command syntax and parameters + * + */ +static int +usage() +{ + fprintf(stderr,"Usage: fence_zvmip [options]\n\n" + "\tWhere [options] =\n" + "\t-o --action [action] - \"off\", \"on\", \"list\", \"metadata\", " + "\"monitor\", \"reboot\", \"status\"\n" + "\t--delay [seconds] - Time to delay fencing action in seconds\n" + "\t-n --plug [target] - Name of virtual machine to fence\n" + "\t-a --ip [server] - IP Name/Address of SMAPI Server\n" + "\t-u --username [user] - Name of autorized SMAPI user\n" + "\t-p --password [pass] - Password of autorized SMAPI user\n" + "\t-t --timeout [secs] - Time to wait for fence in seconds - currently ignored\n" + "\t-h --help - Display this usage information\n"); + return(1); +} + +/** + * check_param - Check that mandatory parameters have been specified + * @zvm - Pointer to driver information + * + */ +static int +check_parm(zvm_driver_t *zvm) +{ + int rc; + + if (zvm->smapiSrv[0] != 0) { + if (zvm->target[0] != 0) { + if (zvm->authUser[0] != 0) { + if (zvm->authPass[0] != 0) { + rc = 0; + } else { + syslog(LOG_ERR, "Missing authorized password"); + rc = 4; + } + } else { + syslog(LOG_ERR, "Missing authorized user name"); + rc = 3; + } + } else { + syslog(LOG_ERR, "Missing fence target name"); + rc = 2; + } + } else { + syslog(LOG_ERR, "Missing SMAPI server name"); + rc = 1; + } + return(rc); +} + +int +main(int argc, char **argv) +{ + zvm_driver_t zvm; + int fence = 1, + rc = 0; + + openlog ("fence_zvmip", LOG_CONS|LOG_PID, LOG_DAEMON); + memset(&zvm, 0, sizeof(zvm)); + zvm.timeOut = DEFAULT_TIMEOUT; + zvm.delay = DEFAULT_DELAY; + + if (argc > 1) + fence = get_options(argc, argv, &zvm); + else + fence = get_options_stdin(&zvm); + + switch(fence) { + case ACT_OFFON : // OFFON + if ((rc = check_parm(&zvm)) == 0) + rc = zvm_smapi_imageRecycle(&zvm); + break; + case ACT_OFF : // OFF + if ((rc = check_parm(&zvm)) == 0) + rc = zvm_smapi_imageDeactivate(&zvm); + break; + case ACT_ON : // ON + if ((rc = check_parm(&zvm)) == 0) + rc = zvm_smapi_imageActivate(&zvm); + break; + case ACT_METADATA : // METADATA + rc = zvm_metadata(); + break; + case ACT_STATUS : // STATUS + if ((rc = check_parm(&zvm)) == 0) + rc = zvm_smapi_imageQuery(&zvm); + break; + case ACT_MONITOR : // MONITOR + rc = 0; + break; + case ACT_LIST : + printf("N/A"); + break; + case ACT_HELP : + rc = usage(); + } + closelog(); + return (rc); +} diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py new file mode 100644 index 0000000..4f538e1 --- /dev/null +++ b/agents/zvm/fence_zvmip.py @@ -0,0 +1,226 @@ +#!@PYTHON@ -tt + +import sys +import atexit +import socket +import struct +import logging +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * +from fencing import fail, fail_usage, run_delay, EC_LOGIN_DENIED, EC_TIMED_OUT + +INT4 = 4 + +def open_socket(options): + try: + if "--inet6-only" in options: + protocol = socket.AF_INET6 + elif "--inet4-only" in options: + protocol = socket.AF_INET + else: + protocol = 0 + (_, _, _, _, addr) = socket.getaddrinfo( \ + options["--ip"], options["--ipport"], protocol, + 0, socket.IPPROTO_TCP, socket.AI_PASSIVE + )[0] + except socket.gaierror: + fail(EC_LOGIN_DENIED) + + if "--ssl-secure" in options or "--ssl-insecure" in options: + import ssl + sock = socket.socket() + sslcx = ssl.create_default_context() + if "--ssl-insecure" in options: + sslcx.check_hostname = False + sslcx.verify_mode = ssl.CERT_NONE + conn = sslcx.wrap_socket(sock, server_hostname=options["--ip"]) + else: + conn = socket.socket() + conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + conn.settimeout(float(options["--shell-timeout"]) or None) + try: + conn.connect(addr) + except socket.error as e: + logging.debug(e) + fail(EC_LOGIN_DENIED) + + return conn + +def smapi_pack_string(string): + return struct.pack("!i%ds" % (len(string)), len(string), string.encode("UTF-8")) + +def prepare_smapi_command(options, smapi_function, additional_args): + packet_size = 3*INT4 + len(smapi_function) + len(options["--username"]) + len(options["--password"]) + for arg in additional_args: + packet_size += INT4 + len(arg) + + command = struct.pack("!i", packet_size) + command += smapi_pack_string(smapi_function) + command += smapi_pack_string(options["--username"]) + command += smapi_pack_string(options["--password"]) + for arg in additional_args: + command += smapi_pack_string(arg) + + return command + +def get_power_status(conn, options): + del conn + + if options.get("--original-action", None) == "monitor": + (return_code, reason_code, images_active) = \ + get_list_of_images(options, "Check_Authentication", None) + + logging.debug("Check_Authenticate (%d,%d)", return_code, reason_code) + if return_code == 0: + return {} + else: + fail(EC_LOGIN_DENIED) + + if options["--action"] == "list": + # '*' = list all active images + options["--plug"] = "*" + + (return_code, reason_code, images_active) = \ + get_list_of_images(options, "Image_Status_Query", options["--plug"]) + logging.debug("Image_Status_Query results are (%d,%d)", return_code, reason_code) + + if not options["--action"] == "list": + if (return_code == 0) and (reason_code == 0): + return "on" + elif (return_code == 0) and (reason_code == 12): + # We are running always with --missing-as-off because we can not check if image + # is defined or not (look at rhbz#1188750) + return "off" + else: + return "unknown" + else: + (return_code, reason_code, images_defined) = \ + get_list_of_images(options, "Image_Name_Query_DM", options["--username"]) + logging.debug("Image_Name_Query_DM results are (%d,%d)", return_code, reason_code) + + return dict([(i, ("", "on" if i in images_active else "off")) for i in images_defined]) + +def set_power_status(conn, options): + conn = open_socket(options) + + packet = None + if options["--action"] == "on": + packet = prepare_smapi_command(options, "Image_Activate", [options["--plug"]]) + elif options["--action"] == "off": + packet = prepare_smapi_command(options, "Image_Deactivate", [options["--plug"], "IMMED"]) + conn.send(packet) + + request_id = struct.unpack("!i", conn.recv(INT4))[0] + (output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4)) + logging.debug("Image_(De)Activate results are (%d,%d)", return_code, reason_code) + + conn.close() + return + +def get_list_of_images(options, command, data_as_plug): + conn = open_socket(options) + + if data_as_plug is None: + packet = prepare_smapi_command(options, command, []) + else: + packet = prepare_smapi_command(options, command, [data_as_plug]) + + conn.send(packet) + + try: + request_id = struct.unpack("!i", conn.recv(INT4))[0] + (output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4)) + except struct.error: + logging.debug(sys.exc_info()) + fail_usage("Failed: Unable to connect to {} port: {} SSL: {} \n".format(options["--ip"], options["--ipport"], bool("--ssl" in options))) + + images = set() + + if output_len > 3*INT4: + recvflag = socket.MSG_WAITALL if "--ssl-secure" not in options and "--ssl-insecure" not in options else 0 + array_len = struct.unpack("!i", conn.recv(INT4))[0] + data = "" + + while True: + read_data = conn.recv(1024, recvflag).decode("UTF-8") + data += read_data + if array_len == len(data): + break + elif not read_data: + logging.error("Failed: Not enough data read from socket") + fail(EC_TIMED_OUT) + + parsed_len = 0 + while parsed_len < array_len: + string_len = struct.unpack("!i", data[parsed_len:parsed_len+INT4].encode("UTF-8"))[0] + parsed_len += INT4 + image_name = struct.unpack("!%ds" % (string_len), data[parsed_len:parsed_len+string_len].encode("UTF-8"))[0].decode("UTF-8") + parsed_len += string_len + images.add(image_name) + + conn.close() + return (return_code, reason_code, images) + +def define_new_opts(): + all_opt["disable_ssl"] = { + "getopt" : "", + "longopt" : "disable-ssl", + "help" : "--disable-ssl Don't use SSL connection", + "required" : "0", + "shortdesc" : "Don't use SSL", + "order": 2 + } + +def main(): + device_opt = ["ipaddr", "login", "passwd", "port", "method", "missing_as_off", + "inet4_only", "inet6_only", "ssl", "disable_ssl"] + + atexit.register(atexit_handler) + define_new_opts() + + all_opt["ssl"]["help"] = "-z, --ssl Use SSL connection with verifying certificate (Default)" + + all_opt["ipport"]["default"] = "44444" + all_opt["shell_timeout"]["default"] = "5" + all_opt["missing_as_off"]["default"] = "1" + all_opt["ssl"]["default"] = "1" + options = check_input(device_opt, process_input(device_opt), other_conditions=True) + + if "--disable-ssl" in options or options["--ssl"] == "0": + for k in ["--ssl", "--ssl-secure", "--ssl-insecure"]: + if k in options: + del options[k] + + if len(options.get("--plug", "")) > 8: + fail_usage("Failed: Name of image can not be longer than 8 characters") + + if options["--action"] == "validate-all": + sys.exit(0) + + docs = {} + docs["shortdesc"] = "Fence agent for use with z/VM Virtual Machines" + docs["longdesc"] = """The fence_zvm agent is intended to be used with with z/VM SMAPI service via TCP/IP + +To use this agent the z/VM SMAPI service needs to be configured to allow the virtual machine running this agent to connect to it and issue +the image_recycle operation. This involves updating the VSMWORK1 AUTHLIST VMSYS:VSMWORK1. file. The entry should look something similar to +this: + +Column 1 Column 66 Column 131 + + | | | + V V V + +XXXXXXXX ALL IMAGE_CHARACTERISTICS + +Where XXXXXXX is the name of the virtual machine used in the authuser field of the request. This virtual machine also has to be authorized +to access the system's directory manager. +""" + docs["vendorurl"] = "http://www.ibm.com" + show_docs(options, docs) + + run_delay(options) + result = fence_action(None, options, set_power_status, get_power_status, get_power_status) + sys.exit(result) + +if __name__ == "__main__": + main() |