#!/usr/bin/python
# Copyright 2015 VMware, Inc.  All rights reserved. -- VMware Confidential
# -*- mode: Python; coding: utf-8 -*-
'''
For VMware Appliances not using appliancesh

see https://www.vmware.com/support/developer/vcli/vcli41/doc/reference/vicfg-snmp.html
    https://pubs.vmware.com/vsphere-51/index.jsp?topic=%2Fcom.vmware.vcli.ref.doc%2Fvicfg-snmp.html
vicfg-snmp [<connection_options>]
        [--communities <comm_list> |
        --disable |
        --enable |
        --help |
        --port <port_number> |
        --reset |
        --show |
        --notraps |
        --targets <targets> |
        --test |

esxcli system snmp set cmd options:
  -a|--authentication=<str>
                        Set default authentication protocol. Values: none, MD5, SHA1
  -c|--communities=<str>
                        Set up to ten communities each no more than 64 characters. Format is: community1[,community2,...] (this overwrites previous settings)
  -e|--enable           Start or stop SNMP service. Values: [yes|no, true|false, 0|1]
  -E|--engineid=<str>   Set SNMPv3 engine id. Must be at least 10 to 32 hexadecimal characters. 0x or 0X is stripped if found as well as colons (:)
  -y|--hwsrc=<str>      Where to source hardware events from IPMI sensors or CIM Indications. One of: indications|sensors
  -s|--largestorage     Support large storage for hrStorageAllocationUnits * hrStorageSize. Values: [yes|no, true|false, 0|1]. Control how the agent reports hrStorageAllocationUnits, hrStorageSize and hrStorageUsed in hrStorageTable. Setting this directive
                        to 1 to support large storage with small allocation units, the agent re-calculates these values so they all fit Integer32 and hrStorageAllocationUnits * hrStorageSize gives real size of the storage ( Note: hrStorageAllocationUnits
                        will not be real allocation units if real hrStorageSize won't fit into Integer32 ). Setting this directive to 0 turns off this calculation and the agent reports real hrStorageAllocationUnits, but it might report wrong hrStorageSize
                        for large storage because the value won't fit into Integer32.
  -l|--loglevel=<str>   System Agent syslog logging level: debug|info|warning|error
  -n|--notraps=<str>    Comma separated list of trap oids for traps not to be sent by agent. Use value 'reset' to clear setting
  -p|--port=<long>      Set UDP port to poll snmp agent on. The default is udp/161
  -x|--privacy=<str>    Set default privacy protocol. Values: none, AES128
  -R|--remote-users=<str>
                        Set up to five inform user ids. Format is: user/auth-proto/-|auth-hash/priv-proto/-|priv-hash/engine-id[,...] Where user is 32 chars max. auth-proto is none|MD5|SHA1, priv-proto is none|AES. '-' indicates no hash. engine-id is hex
                        string '0x0-9a-f' up to 32 chars max.
  -r|--reset            Return agent configuration to factory defaults
  -C|--syscontact=<str> System contact string as presented in sysContact.0. Up to 255 characters
  -L|--syslocation=<str>
                        System location string as presented in sysLocation.0. Up to 255 characters.
  -t|--targets=<str>    Set up to three targets to send SNMPv1 traps to. Format is: ip-or-hostname[@port]/community[,...] The default port is udp/162. (this overwrites previous settings)
  -u|--users=<str>      Set up to five local users. Format is: user/-|auth-hash/-|priv-hash/model[,...] Where user is 32 chars max. '-' indicates no hash. Model is one of (none|auth|priv).
  -i|--v3targets=<str>  Set up to three SNMPv3 notification targets. Format is: ip-or-hostname[@port]/remote-user/security-level/trap|inform[,...].
'''
__author__ = "VMware, Inc."

import sys
sys.path.append('/usr/lib/applmgmt/base/py')
sys.path.append('/usr/lib/applmgmt/snmp/py/vmware/appliance')
sys.path.append('/usr/lib/python2.7/site-packages')
from optparse import OptionParser
import logging
import datetime
import time
from vmware.vherd.base import pint
from snmp import cfg

def get_options():
    """
    Supports the command-line arguments listed below
    """

    parser = OptionParser()
    parser.add_option("-c", "--communities",
                      help="Specifies communities, separated by commas. The settings specified using this option overwrite any previous settings. The settings specified using this flag overwrite any previous settings. ")
    parser.add_option("-D", "--disable",
                      action="store_true",
                      help="Stops the SNMP service on the host.")
    parser.add_option("-e", "--enable",
                      action="store_true",
                      help="Starts the SNMP service on the host.")
    parser.add_option("-p", "--port",
                      help="Sets the port used by the SNMP agent. The default is UDP 161. This is the port that the SNMP service uses to listen on for polling requests, such as GET requests. You can also configure the port that the SNMP agent sends data to on the target system using the --targets option. That port is UDP 162 by default.")
    parser.add_option("-l", "--loglevel",
                      help="System Agent syslog logging level: debug|info|warning|error|info|debug")
    parser.add_option("-r", "--reset",
                      action="store_true",
                      help="Clears all previously-specified communities and targets.")
    parser.add_option("-s", "--show",
                      action="store_true",
                      help="Displays the current SNMP configuration.")
    parser.add_option("-S", "--stats",
                      action="store_true",
                      help="Displays the current SNMP agent runtime performance metrics.")
    parser.add_option("-t", "--targets",
                      help="Sets the destination for (notifications) traps. You can specify multiple targets, separated by commas. The settings specified using this flag overwrite any previous settings. ")
    parser.add_option("-n", "--notraps",
                      help="Comma separated list of trap oids for traps not to be sent by agent. Use value 'reset' to clear setting.")
    parser.add_option("-C", "--syscontact",
                      help="System contact string as presented in sysContact.0. Up to 255 characters")
    parser.add_option("-L", "--syslocation",
                      help="System location string as presented in sysLocation.0. Up to 255 characters.")
    parser.add_option("-E", "--engineid",
                      help="System location string as presented in sysLocation.0. Up to 255 characters.")
    parser.add_option("-a", "--authentication",
                      help="Set default authentication protocol. Values: none, MD5, SHA1")
    parser.add_option("-x", "--privacy",
                      help="Set default privacy protocol. Values: none, AES128")
    parser.add_option("-u", "--users",
                      help="Set up to five local users. Format is: user/-|auth-hash/-|priv-hash/model[,...] Where user is 32 chars max. '-' indicates no hash. Model is one of (none|auth|priv).")
    parser.add_option("-i", "--v3targets",
                      help="Set up to three SNMPv3 notification targets. Format is: ip-or-hostname[@port]/remote-user/security-level/trap|inform[,...].")
    parser.add_option("-T", "--test",
                      action="store_true",
                      help="Sends a test notification that can be used to validate the SNMP configuration to the configured target or targets.");
    parser.add_option("-g", "--debug",
                      action="store_true",
                      help="turn on pdb debugger, for technical support only.")
    (options, _) = parser.parse_args()
    return options;

def main():
   opts = get_options()
   if opts.debug:
      import pdb
      pdb.set_trace()

   if opts.show:
      kvp = cfg.show()
      # todo match esxcli output format
      print("Current SNMP agent setting")
      print("Enabled                 : %s" %  kvp['enable'])
      print("UDP port                : %s" % kvp['port'])
      print("Communities             : %s" % ' '.join(kvp['communities']))
      print("V1 Notification targets : %s" % ' '.join(kvp['targets']))
      if 'EventFilter' in kvp:
         print("Notification filter oids: %s" % ' '.join(kvp['EventFilter']))
      if 'v3targets' in kvp:
         print("V3 Notification targets : %s" % ' '.join(kvp['v3targets']))
      print("Contact                 : %s" % kvp['syscontact'])
      print("Location                : %s" % kvp['syslocation'])
      print("Engine ID               : %s" % kvp['engineid'])
      print("Auth Protocol           : %s" % kvp['authProtocol'])
      print("Priv Protocol           : %s" % kvp['privProtocol'])
      print("V3 Users                : %s" % ' '.join(kvp['v3users']))
      print("Log level               : %s" % kvp['loglevel'])
      print("Process ID              : %s" % kvp['state'])
      #print "V3 Notification targets" % kvp['v3targets']
      print("INFO: listing complete.")
   elif opts.stats:
       stats = cfg.stats()
       try:
          stats.sysUpTime = stats.sysUpTime.split()[0] / 100
       except:
           stats.sysUptime = 0
       try:
          the_date = int(stats.worstrtimelast)
       except:
          the_date = 0
       if the_date == 0:
          the_date = "n/a";
       else:
          try:
              the_date = datetime.fromtimestamp(the_date)
          except:
              the_date = time.gmtime(int(the_date))
              the_date = time.strftime("%FT%TZ", the_date)
       stats.worstrtimelast = the_date
       print("SNMP agent protocol statistics")
       keys = sorted(stats.__dict__['_contents'])
       for item in keys:
          print("%-28s : %s" % (item, stats.__dict__['_contents'][item]))
   elif opts.enable:
    cfg.enable_agent()
   elif opts.disable:
    cfg.disable_agent()
   elif opts.syscontact:
    cfg.set_contact(opts.syscontact)
   elif opts.syslocation:
    cfg.set_location(opts.syslocation)
   elif opts.engineid:
    cfg.set_engineid(opts.engineid)
   elif opts.authentication:
    cfg.set_authentication(opts.authentication)
   elif opts.privacy:
    cfg.set_privacy(opts.privacy)
   elif opts.users:
    cfg.set_users(opts.users)
   elif opts.v3targets:
    cfg.set_v3targets(opts.v3targets)
   elif opts.communities:
    cfg.set_communities(opts.communities)
   elif opts.targets:
    cfg.set_targets(opts.targets)
   elif opts.loglevel:
    cfg.set_loglevel(opts.loglevel)
   elif opts.notraps:
    cfg.set_filter(opts.notraps)
   elif opts.port:
    cfg.set_port(opts.port)
   elif opts.reset:
      cfg.reset()
   elif opts.test:
      results = cfg.test()
      keys = sorted(results)
      for item in keys:
          print("%-28s : %s" % (item, results[item]))
      rc = 0
      if results['success'] == False:
         rc = 1
      sys.exit(rc)

# Start program
if __name__ == "__main__":
   try:
      logging.basicConfig()
      main()
   except SystemExit as err:
       sys.exit(err)
   except Exception as msg:
      print("ERROR: %s " % msg)
      sys.exit(1)
# end of file
