From 4d3c53a1d14229940de04f7392548de666b4c2c3 Mon Sep 17 00:00:00 2001 From: "Paul C. Buetow" Date: Tue, 15 Apr 2014 09:17:21 +0200 Subject: add initial docs --- src/fapi | 473 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/fapi.py | 473 ------------------------------------------------------------ 2 files changed, 473 insertions(+), 473 deletions(-) create mode 100755 src/fapi delete mode 100755 src/fapi.py (limited to 'src') diff --git a/src/fapi b/src/fapi new file mode 100755 index 0000000..6b67323 --- /dev/null +++ b/src/fapi @@ -0,0 +1,473 @@ +#!/usr/bin/env python + +# 2014 (c) Paul C. Buetow + +import argparse +import base64 +import bigsuds +import getpass +import pprint +import socket +import sys +import re + +from os.path import expanduser +from inspect import isfunction + +import ConfigParser + +__program__ = 'fapi' +__version__ = 'VERSION_DEVEL' # Replaced by a Makefile tsubet +__prompt__ = '>>>' # Default prompt + + +def print_synopsis(): + ''' Prints the full Synopsis string ''' + + print "\n".join([ + 'This is %s version %s' % (__program__, __version__), + '', + 'Synopsis:', + ' fapi monitor', + ' fapi monitor MONITORNAME get desc|state', + ' fapi node', + ' fapi node NODENAME create|delete', + ' fapi node NODENAME get detail|status', + ' fapi pool', + ' fapi pool POOLNAME add member MEMBERNAME:PORT', + ' fapi pool POOLNAME add monitor MONITORNAME', + ' fapi pool POOLNAME create [LIST,OF,POOL,MEMBERS:PORT]', + ' fapi pool POOLNAME delete', + ' fapi pool POOLNAME del member MEMBERNAME:PORT', + ' fapi pool POOLNAME del monitors', + ' fapi pool POOLNAME get detail|lbmethod|members|monitor|status', + ' fapi pool POOLNAME set lbmethod LBMETHOD', + ' fapi vserver', + ' fapi vserver VSERVERNAME create [protocol] [profile] [poolname] [mask]', + ' fapi vserver VSERVERNAME delete', + ' fapi vserver VSERVERNAME get brief|detail|status', + ' fapi vserver VSERVERNAME set nat|pat disabled|enabled', + ' fapi vserver VSERVERNAME set pool POOLNAME', + ' fapi vserver VSERVERNAME set snat none', + ]) + + + +class Fapi(object): + ''' The main F5 API Tool Object ''' + + def __init__(self, args): + ''' Initialize the config file, username and password ''' + + self._args = args + self._config = ConfigParser.ConfigParser() + self._config.read(args.C) + self._partition = self._config.get('fapi', 'partition') + + + def __login(self): + ''' Logs into the F5 BigIP SOAP API and changes the partition''' + + c = self._config + a = self._args + + if c.has_option('fapi', 'username'): + username = c.get('fapi', 'username') + else: + username = getpass.getuser() + if c.has_option('fapi', 'password64'): + password = base64.decodestring(c.get('fapi', 'password64')) + else: + prompt = 'Enter API password for user %s: ' % username + password = getpass.getpass(prompt) + self.info('Login to BigIP API with user %s' % username) + + # Try a comma separated lists of F5 boxes, use the first one + err = None + for hostname in c.get('fapi', 'hostnames').split(','): + try: + self.info('Trying to login to \'%s\'' % hostname) + self._f5 = bigsuds.BIGIP(hostname = hostname, + username = username, + password = password) + self._f5.Management.Partition.set_active_partition(self._partition) + self.info('Set partition to \'%s\'' % self._partition) + err = None + break + except Exception, e: + err = '%s:%s' % (hostname, e) + pass + + if err: + self.info(err) + sys.exit(2) + + + def info(self, message): + ''' Prints an informational message to stderr ''' + + if self._args.v: print >> sys.stderr, '%s %s' % (__prompt__, message) + + + def out(self, result): + ''' Prints an iControl result to stdout ''' + + if result != None: + pp = pprint.PrettyPrinter(indent=4) + pp.pprint(result) + + + def lookup(self, what): + ''' Does a DNS lookup to fetch the FQDN and all the IPs ''' + + tmp = what.split(':') + if 1 == len(tmp): tmp.append('80') + what = tmp[0] + port = tmp[1] + try: + data = socket.gethostbyname_ex(what) + except Exception, e: + self.info('Can\'t resolve \'%s\': %s' % (what, e)) + sys.exit(2) + fqdn = data[0] + ips = data[2] + if len(ips) > 1: + self.info('\'%s\' resolves to multiple ips \'%s\'' % (fqdn, ips)) + sys.exit(2) + return (fqdn, ips[0], port) + + def __do_node(self, f5): + ''' Do stuff concerning nodes ''' + + a = self._args + + if not a.name: + return lambda: f5().get_list() + + if a.sub == 'get': + if a.sub2 == 'detail': + def detail(f5): + d = {} + d['connection_limit'] = f5().get_connection_limit([a.name]) + d['default_node_monitor'] = f5().get_default_node_monitor() + d['description'] = f5().get_description([a.name]) + d['dynamic_ratio'] = f5().get_dynamic_ratio_v2([a.name]) + d['monitor_instance'] = f5().get_monitor_instance([a.name]) + d['monitor_rule'] = f5().get_monitor_rule([a.name]) + d['monitor_status'] = f5().get_monitor_status([a.name]) + d['object_status'] = f5().get_object_status([a.name]) + d['rate_limit'] = f5().get_rate_limit([a.name]) + d['ratio'] = f5().get_ratio([a.name]) + d['session_status'] = f5().get_session_status([a.name]) + return d + return lambda: detail(f5) + if a.sub2 == 'status': + return lambda: f5().get_monitor_status([a.name]) + + elif a.sub == 'create': + try: + data = socket.gethostbyname_ex(a.name) + except Exception, e: + self.info('Can\'t resolve \'%s\': %s' % (a.name, e)) + sys.exit(2) + fqdn, ip, _ = self.lookup(a.name) + return lambda: f5().create([fqdn],[ip],[0]) + + elif a.sub == 'delete': + return lambda: f5().delete_node_address([a.name]) + + + def __do_monitor(self, f5): + ''' Do stuff concerning monitor templates ''' + + a = self._args + + if not a.name: + return lambda: f5().get_template_list() + + if a.sub == 'get': + monitorname = a.sub3 + if a.sub2 == 'desc': + return lambda: f5().get_description([monitorname]) + if a.sub2 == 'state': + return lambda: f5().get_template_state([monitorname]) + + + def __do_pool(self, f5): + ''' Do stuff concerning pools ''' + + a = self._args + + if not a.name: + return lambda: f5().get_list() + + if a.sub == 'get': + if a.sub2 == 'detail': + def detail(f5): + d = {} + d['allow_nat_state'] = f5().get_allow_nat_state([a.name]) + d['allow_snat_state'] = f5().get_allow_snat_state([a.name]) + d['description'] = f5().get_description([a.name]) + d['lb_method'] = f5().get_lb_method([a.name]) + d['member'] = f5().get_member_v2([a.name]) + d['object_status'] = f5().get_object_status([a.name]) + d['profile'] = f5().get_profile([a.name]) + return d + return lambda: detail(f5) + elif a.sub2 == 'lbmethod': + return lambda: f5().get_lb_method([a.name]) + elif a.sub2 == 'members': + return lambda: f5().get_member_v2([a.name]) + elif a.sub2 == 'monitor': + return lambda: f5().get_monitor_instance([a.name]) + elif a.sub2 == 'status': + return lambda: f5().get_object_status([a.name]) + + elif a.sub == 'set': + if a.sub2 == 'lbmethod': + lbmethod = a.sub3 + return lambda: f5().set_lb_method([a.name], [lbmethod]) + + elif a.sub == 'create': + poolmembers = [] + method = a.m + if a.sub3: + for x in a.sub3.split(','): + fqdn, ip, port = self.lookup(x) + pm = { 'address' : fqdn, 'port' : port } + poolmembers.append(pm) + return lambda: f5().create_v2([a.name],[method],[poolmembers]) + + elif a.sub == 'delete': + return lambda: f5().delete_pool([a.name]) + + elif a.sub == 'add': + if a.sub2 == 'member': + fqdn, _, port = self.lookup(a.sub3) + member = [{ 'address' : fqdn, 'port' : port }] + return lambda: f5().add_member_v2([a.name], [member]) + elif a.sub2 == 'monitor': + monitorname = a.sub3 + rule = { + 'type': 'MONITOR_RULE_TYPE_SINGLE', + 'quorum': long(0), + 'monitor_templates': [ monitorname ], + } + association = { 'pool_name': a.name, 'monitor_rule': rule } + return lambda: f5().set_monitor_association([association]) + + elif a.sub == 'del': + if a.sub2 == 'member': + fqdn, _, port = self.lookup(a.sub3) + member = [{ 'address' : fqdn, 'port' : port }] + return lambda: f5().remove_member_v2([a.name], [member]) + elif a.sub2 == 'monitors': + # Removes all monitor associations, not just one + return lambda: f5().remove_monitor_association([a.name]) + + + def __do_vserver(self, f5): + ''' Do stuff concerning virtual servers ''' + + a = self._args + + if not a.name: + return lambda: f5().get_list() + + # Check for Pattern like /partition/foo-bar.example.com_443 + m = re.match('^(.*)_(\d+)$', a.name) + if m: + fqdn = m.group(1) + port = m.group(2) + _, ip, _ = self.lookup(fqdn) + else: + fqdn, ip, port = self.lookup(a.name) + + name = fqdn + '_' + port + + if a.sub == 'get': + if a.sub2 == 'detail': + def detail(f5): + d = {} + d['actual_hardware_acceleration'] = f5().get_actual_hardware_acceleration([name]) + d['auto_lasthop'] = f5().get_auto_lasthop([name]) + d['bw_controller_policy'] = f5().get_bw_controller_policy([name]) + d['clone_pool'] = f5().get_clone_pool([name]) + d['connection_limit'] = f5().get_connection_limit([name]) + d['default_pool_name'] = f5().get_default_pool_name([name]) + d['description'] = f5().get_description([name]) + d['destination'] = f5().get_destination_v2([name]) + d['enabled_state'] = f5().get_enabled_state([name]) + d['fallback_persistence_profile'] = f5().get_fallback_persistence_profile([name]) + d['gtm_score'] = f5().get_gtm_score([name]) + d['last_hop_pool'] = f5().get_last_hop_pool([name]) + d['object_status'] = f5().get_object_status([name]) + d['persistence_profile'] = f5().get_persistence_profile([name]) + d['profile'] = f5().get_profile([name]) + d['protocol'] = f5().get_protocol([name]) + d['rule'] = f5().get_rule([name]) + d['snat_pool'] = f5().get_snat_pool([name]) + d['snat_type'] = f5().get_snat_type([name]) + d['source_address'] = f5().get_source_address([name]) + d['source_address_translation_lsn_pool'] = f5().get_source_address_translation_lsn_pool([name]) + d['source_address_translation_snat_pool'] = f5().get_source_address_translation_snat_pool([name]) + d['source_address_translation_type'] = f5().get_source_address_translation_type([name]) + d['source_port_behavior'] = f5().get_source_port_behavior([name]) + d['translate_address_state'] = f5().get_translate_address_state([name]) + d['translate_port_state'] = f5().get_translate_port_state([name]) + d['type'] = f5().get_type([name]) + d['vlan'] = f5().get_vlan([name]) + return d + return lambda: detail(f5) + elif a.sub2 == 'brief': + def brief(f5): + d = {} + d['actual_hardware_acceleration'] = f5().get_actual_hardware_acceleration([name]) + d['default_pool_name'] = f5().get_default_pool_name([name]) + d['destination'] = f5().get_destination_v2([name]) + d['enabled_state'] = f5().get_enabled_state([name]) + d['object_status'] = f5().get_object_status([name]) + d['persistence_profile'] = f5().get_persistence_profile([name]) + d['profile'] = f5().get_profile([name]) + d['protocol'] = f5().get_protocol([name]) + d['translate_address_state'] = f5().get_translate_address_state([name]) + d['translate_port_state'] = f5().get_translate_port_state([name]) + d['type'] = f5().get_type([name]) + return d + return lambda: brief(f5) + elif a.sub2 == 'status': + return lambda: f5().get_object_status([name]) + + elif a.sub == 'create': + protocol = a.sub2 if a.sub2 else 'PROTOCOL_TCP' + if a.sub3: + profile = a.sub3 + elif protocol == 'PROTOCOL_UDP': + profile = 'udp' + else: + profile = 'tcp' + poolname = a.sub4 + netmask = a.sub5 if a.sub5 else '255.255.255.255' + vserver = { + 'name': name, + 'address': ip, + 'port': port, + 'protocol': protocol, + } + resource = { 'type': 'RESOURCE_TYPE_POOL' } + if poolname: resource['default_pool_name'] = poolname + profile = { + 'profile_context': 'PROFILE_CONTEXT_TYPE_ALL', + 'profile_name': profile, + } + self.info("vserver:%s netmask:%s resource:%s, profile:%s" + % (vserver, netmask, resource, profile)) + def vserver_create(): + f5().create([vserver], [netmask], [resource], [[profile]]) + # Auto disable NAT and PAT if nPath + if profile['profile_name'] == 'nPath': + f5().set_translate_address_state([name], ['STATE_DISABLED']) + f5().set_translate_port_state([name], ['STATE_DISABLED']) + return lambda: vserver_create() + + elif a.sub == 'delete': + return lambda: f5().delete_virtual_server([name]) + + elif a.sub == 'set': + if a.sub2 == 'pool': + poolname = a.sub3 + return lambda: f5().set_default_pool_name([name], [poolname]) + elif a.sub2 == 'nat': + if a.sub3 == 'disabled': + return lambda: f5().set_translate_address_state([name], ['STATE_DISABLED']) + elif a.sub3 == 'enabled': + return lambda: f5().set_translate_address_state([name], ['STATE_ENABLED']) + elif a.sub2 == 'pat': + if a.sub3 == 'disabled': + return lambda: f5().set_translate_port_state([name], ['STATE_DISABLED']) + elif a.sub3 == 'enabled': + return lambda: f5().set_translate_port_state([name], ['STATE_ENABLED']) + elif a.sub2 == 'snat': + if a.sub3 == 'none': + return lambda: f5().set_source_address_translation_none([name]) + + + + def run(self): + ''' Do the actual stuff. + We are doning some lazy evaluation stuff here. The command line + tool does not do anything with the slow F5 API until it is clear + what to do and that there is no semantic or syntax error. ''' + + a = self._args + lazy = None + + if a.name: + # Remove the /partition/ prefix, setting default partition after + # login instead + a.name = re.sub(self._partition, '', a.name) + a.name = re.sub('^/+', '', a.name) + + if a.what == 'node': + lazy = self.__do_node(lambda: self._f5.LocalLB.NodeAddressV2) + elif a.what == 'monitor': + lazy = self.__do_monitor(lambda: self._f5.LocalLB.Monitor) + elif a.what == 'pool': + lazy = self.__do_pool(lambda: self._f5.LocalLB.Pool) + elif a.what == 'vserver': + lazy = self.__do_vserver(lambda: self._f5.LocalLB.VirtualServer) + + if isfunction(lazy): + self.info('Doing some stuf via the API, it may take a while') + self.__login() + self.out(lazy()) + else: + print_synopsis() + sys.exit(1) + + + +if __name__ == '__main__': + ''' The main function, here we will have Popcorn for free! ''' + + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument('-h', action='store_true', help='Help') + parser.add_argument('-v', action='store_true', help='Verbose') + parser.add_argument('-V', action='store_true', help='Print version') + parser.add_argument('-m', action='store', help='The default lbmethod', + default='LB_METHOD_ROUND_ROBIN') + parser.add_argument('-C', action='store', help='Config file', + default=expanduser('~') + '/.fapi.conf') + + parser.add_argument('what', nargs='?', help='node|pool|monitor|vserver|...') + parser.add_argument('name', nargs='?', help='The object name to operate on') + parser.add_argument('sub', nargs='?', help='First sub command') + parser.add_argument('sub2', nargs='?', help='Second sub command') + parser.add_argument('sub3', nargs='?', help='Third sub command') + parser.add_argument('sub4', nargs='?', help='Fourth sub command') + parser.add_argument('sub5', nargs='?', help='Fith sub command') + + args = parser.parse_args() + + if args.h: + parser.print_help() + print '' + print_synopsis() + sys.exit(0) + + if args.V: + sys.exit(0) + + fapi = Fapi(args) + + fapi.run() + +# try: +# if not fapi.run(): +# fapi.info('Don\'t know what to do') +# sys.exit(1) +# except Exception, e: +# fapi.info(e) +# sys.exit(2) + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/src/fapi.py b/src/fapi.py deleted file mode 100755 index 6b67323..0000000 --- a/src/fapi.py +++ /dev/null @@ -1,473 +0,0 @@ -#!/usr/bin/env python - -# 2014 (c) Paul C. Buetow - -import argparse -import base64 -import bigsuds -import getpass -import pprint -import socket -import sys -import re - -from os.path import expanduser -from inspect import isfunction - -import ConfigParser - -__program__ = 'fapi' -__version__ = 'VERSION_DEVEL' # Replaced by a Makefile tsubet -__prompt__ = '>>>' # Default prompt - - -def print_synopsis(): - ''' Prints the full Synopsis string ''' - - print "\n".join([ - 'This is %s version %s' % (__program__, __version__), - '', - 'Synopsis:', - ' fapi monitor', - ' fapi monitor MONITORNAME get desc|state', - ' fapi node', - ' fapi node NODENAME create|delete', - ' fapi node NODENAME get detail|status', - ' fapi pool', - ' fapi pool POOLNAME add member MEMBERNAME:PORT', - ' fapi pool POOLNAME add monitor MONITORNAME', - ' fapi pool POOLNAME create [LIST,OF,POOL,MEMBERS:PORT]', - ' fapi pool POOLNAME delete', - ' fapi pool POOLNAME del member MEMBERNAME:PORT', - ' fapi pool POOLNAME del monitors', - ' fapi pool POOLNAME get detail|lbmethod|members|monitor|status', - ' fapi pool POOLNAME set lbmethod LBMETHOD', - ' fapi vserver', - ' fapi vserver VSERVERNAME create [protocol] [profile] [poolname] [mask]', - ' fapi vserver VSERVERNAME delete', - ' fapi vserver VSERVERNAME get brief|detail|status', - ' fapi vserver VSERVERNAME set nat|pat disabled|enabled', - ' fapi vserver VSERVERNAME set pool POOLNAME', - ' fapi vserver VSERVERNAME set snat none', - ]) - - - -class Fapi(object): - ''' The main F5 API Tool Object ''' - - def __init__(self, args): - ''' Initialize the config file, username and password ''' - - self._args = args - self._config = ConfigParser.ConfigParser() - self._config.read(args.C) - self._partition = self._config.get('fapi', 'partition') - - - def __login(self): - ''' Logs into the F5 BigIP SOAP API and changes the partition''' - - c = self._config - a = self._args - - if c.has_option('fapi', 'username'): - username = c.get('fapi', 'username') - else: - username = getpass.getuser() - if c.has_option('fapi', 'password64'): - password = base64.decodestring(c.get('fapi', 'password64')) - else: - prompt = 'Enter API password for user %s: ' % username - password = getpass.getpass(prompt) - self.info('Login to BigIP API with user %s' % username) - - # Try a comma separated lists of F5 boxes, use the first one - err = None - for hostname in c.get('fapi', 'hostnames').split(','): - try: - self.info('Trying to login to \'%s\'' % hostname) - self._f5 = bigsuds.BIGIP(hostname = hostname, - username = username, - password = password) - self._f5.Management.Partition.set_active_partition(self._partition) - self.info('Set partition to \'%s\'' % self._partition) - err = None - break - except Exception, e: - err = '%s:%s' % (hostname, e) - pass - - if err: - self.info(err) - sys.exit(2) - - - def info(self, message): - ''' Prints an informational message to stderr ''' - - if self._args.v: print >> sys.stderr, '%s %s' % (__prompt__, message) - - - def out(self, result): - ''' Prints an iControl result to stdout ''' - - if result != None: - pp = pprint.PrettyPrinter(indent=4) - pp.pprint(result) - - - def lookup(self, what): - ''' Does a DNS lookup to fetch the FQDN and all the IPs ''' - - tmp = what.split(':') - if 1 == len(tmp): tmp.append('80') - what = tmp[0] - port = tmp[1] - try: - data = socket.gethostbyname_ex(what) - except Exception, e: - self.info('Can\'t resolve \'%s\': %s' % (what, e)) - sys.exit(2) - fqdn = data[0] - ips = data[2] - if len(ips) > 1: - self.info('\'%s\' resolves to multiple ips \'%s\'' % (fqdn, ips)) - sys.exit(2) - return (fqdn, ips[0], port) - - def __do_node(self, f5): - ''' Do stuff concerning nodes ''' - - a = self._args - - if not a.name: - return lambda: f5().get_list() - - if a.sub == 'get': - if a.sub2 == 'detail': - def detail(f5): - d = {} - d['connection_limit'] = f5().get_connection_limit([a.name]) - d['default_node_monitor'] = f5().get_default_node_monitor() - d['description'] = f5().get_description([a.name]) - d['dynamic_ratio'] = f5().get_dynamic_ratio_v2([a.name]) - d['monitor_instance'] = f5().get_monitor_instance([a.name]) - d['monitor_rule'] = f5().get_monitor_rule([a.name]) - d['monitor_status'] = f5().get_monitor_status([a.name]) - d['object_status'] = f5().get_object_status([a.name]) - d['rate_limit'] = f5().get_rate_limit([a.name]) - d['ratio'] = f5().get_ratio([a.name]) - d['session_status'] = f5().get_session_status([a.name]) - return d - return lambda: detail(f5) - if a.sub2 == 'status': - return lambda: f5().get_monitor_status([a.name]) - - elif a.sub == 'create': - try: - data = socket.gethostbyname_ex(a.name) - except Exception, e: - self.info('Can\'t resolve \'%s\': %s' % (a.name, e)) - sys.exit(2) - fqdn, ip, _ = self.lookup(a.name) - return lambda: f5().create([fqdn],[ip],[0]) - - elif a.sub == 'delete': - return lambda: f5().delete_node_address([a.name]) - - - def __do_monitor(self, f5): - ''' Do stuff concerning monitor templates ''' - - a = self._args - - if not a.name: - return lambda: f5().get_template_list() - - if a.sub == 'get': - monitorname = a.sub3 - if a.sub2 == 'desc': - return lambda: f5().get_description([monitorname]) - if a.sub2 == 'state': - return lambda: f5().get_template_state([monitorname]) - - - def __do_pool(self, f5): - ''' Do stuff concerning pools ''' - - a = self._args - - if not a.name: - return lambda: f5().get_list() - - if a.sub == 'get': - if a.sub2 == 'detail': - def detail(f5): - d = {} - d['allow_nat_state'] = f5().get_allow_nat_state([a.name]) - d['allow_snat_state'] = f5().get_allow_snat_state([a.name]) - d['description'] = f5().get_description([a.name]) - d['lb_method'] = f5().get_lb_method([a.name]) - d['member'] = f5().get_member_v2([a.name]) - d['object_status'] = f5().get_object_status([a.name]) - d['profile'] = f5().get_profile([a.name]) - return d - return lambda: detail(f5) - elif a.sub2 == 'lbmethod': - return lambda: f5().get_lb_method([a.name]) - elif a.sub2 == 'members': - return lambda: f5().get_member_v2([a.name]) - elif a.sub2 == 'monitor': - return lambda: f5().get_monitor_instance([a.name]) - elif a.sub2 == 'status': - return lambda: f5().get_object_status([a.name]) - - elif a.sub == 'set': - if a.sub2 == 'lbmethod': - lbmethod = a.sub3 - return lambda: f5().set_lb_method([a.name], [lbmethod]) - - elif a.sub == 'create': - poolmembers = [] - method = a.m - if a.sub3: - for x in a.sub3.split(','): - fqdn, ip, port = self.lookup(x) - pm = { 'address' : fqdn, 'port' : port } - poolmembers.append(pm) - return lambda: f5().create_v2([a.name],[method],[poolmembers]) - - elif a.sub == 'delete': - return lambda: f5().delete_pool([a.name]) - - elif a.sub == 'add': - if a.sub2 == 'member': - fqdn, _, port = self.lookup(a.sub3) - member = [{ 'address' : fqdn, 'port' : port }] - return lambda: f5().add_member_v2([a.name], [member]) - elif a.sub2 == 'monitor': - monitorname = a.sub3 - rule = { - 'type': 'MONITOR_RULE_TYPE_SINGLE', - 'quorum': long(0), - 'monitor_templates': [ monitorname ], - } - association = { 'pool_name': a.name, 'monitor_rule': rule } - return lambda: f5().set_monitor_association([association]) - - elif a.sub == 'del': - if a.sub2 == 'member': - fqdn, _, port = self.lookup(a.sub3) - member = [{ 'address' : fqdn, 'port' : port }] - return lambda: f5().remove_member_v2([a.name], [member]) - elif a.sub2 == 'monitors': - # Removes all monitor associations, not just one - return lambda: f5().remove_monitor_association([a.name]) - - - def __do_vserver(self, f5): - ''' Do stuff concerning virtual servers ''' - - a = self._args - - if not a.name: - return lambda: f5().get_list() - - # Check for Pattern like /partition/foo-bar.example.com_443 - m = re.match('^(.*)_(\d+)$', a.name) - if m: - fqdn = m.group(1) - port = m.group(2) - _, ip, _ = self.lookup(fqdn) - else: - fqdn, ip, port = self.lookup(a.name) - - name = fqdn + '_' + port - - if a.sub == 'get': - if a.sub2 == 'detail': - def detail(f5): - d = {} - d['actual_hardware_acceleration'] = f5().get_actual_hardware_acceleration([name]) - d['auto_lasthop'] = f5().get_auto_lasthop([name]) - d['bw_controller_policy'] = f5().get_bw_controller_policy([name]) - d['clone_pool'] = f5().get_clone_pool([name]) - d['connection_limit'] = f5().get_connection_limit([name]) - d['default_pool_name'] = f5().get_default_pool_name([name]) - d['description'] = f5().get_description([name]) - d['destination'] = f5().get_destination_v2([name]) - d['enabled_state'] = f5().get_enabled_state([name]) - d['fallback_persistence_profile'] = f5().get_fallback_persistence_profile([name]) - d['gtm_score'] = f5().get_gtm_score([name]) - d['last_hop_pool'] = f5().get_last_hop_pool([name]) - d['object_status'] = f5().get_object_status([name]) - d['persistence_profile'] = f5().get_persistence_profile([name]) - d['profile'] = f5().get_profile([name]) - d['protocol'] = f5().get_protocol([name]) - d['rule'] = f5().get_rule([name]) - d['snat_pool'] = f5().get_snat_pool([name]) - d['snat_type'] = f5().get_snat_type([name]) - d['source_address'] = f5().get_source_address([name]) - d['source_address_translation_lsn_pool'] = f5().get_source_address_translation_lsn_pool([name]) - d['source_address_translation_snat_pool'] = f5().get_source_address_translation_snat_pool([name]) - d['source_address_translation_type'] = f5().get_source_address_translation_type([name]) - d['source_port_behavior'] = f5().get_source_port_behavior([name]) - d['translate_address_state'] = f5().get_translate_address_state([name]) - d['translate_port_state'] = f5().get_translate_port_state([name]) - d['type'] = f5().get_type([name]) - d['vlan'] = f5().get_vlan([name]) - return d - return lambda: detail(f5) - elif a.sub2 == 'brief': - def brief(f5): - d = {} - d['actual_hardware_acceleration'] = f5().get_actual_hardware_acceleration([name]) - d['default_pool_name'] = f5().get_default_pool_name([name]) - d['destination'] = f5().get_destination_v2([name]) - d['enabled_state'] = f5().get_enabled_state([name]) - d['object_status'] = f5().get_object_status([name]) - d['persistence_profile'] = f5().get_persistence_profile([name]) - d['profile'] = f5().get_profile([name]) - d['protocol'] = f5().get_protocol([name]) - d['translate_address_state'] = f5().get_translate_address_state([name]) - d['translate_port_state'] = f5().get_translate_port_state([name]) - d['type'] = f5().get_type([name]) - return d - return lambda: brief(f5) - elif a.sub2 == 'status': - return lambda: f5().get_object_status([name]) - - elif a.sub == 'create': - protocol = a.sub2 if a.sub2 else 'PROTOCOL_TCP' - if a.sub3: - profile = a.sub3 - elif protocol == 'PROTOCOL_UDP': - profile = 'udp' - else: - profile = 'tcp' - poolname = a.sub4 - netmask = a.sub5 if a.sub5 else '255.255.255.255' - vserver = { - 'name': name, - 'address': ip, - 'port': port, - 'protocol': protocol, - } - resource = { 'type': 'RESOURCE_TYPE_POOL' } - if poolname: resource['default_pool_name'] = poolname - profile = { - 'profile_context': 'PROFILE_CONTEXT_TYPE_ALL', - 'profile_name': profile, - } - self.info("vserver:%s netmask:%s resource:%s, profile:%s" - % (vserver, netmask, resource, profile)) - def vserver_create(): - f5().create([vserver], [netmask], [resource], [[profile]]) - # Auto disable NAT and PAT if nPath - if profile['profile_name'] == 'nPath': - f5().set_translate_address_state([name], ['STATE_DISABLED']) - f5().set_translate_port_state([name], ['STATE_DISABLED']) - return lambda: vserver_create() - - elif a.sub == 'delete': - return lambda: f5().delete_virtual_server([name]) - - elif a.sub == 'set': - if a.sub2 == 'pool': - poolname = a.sub3 - return lambda: f5().set_default_pool_name([name], [poolname]) - elif a.sub2 == 'nat': - if a.sub3 == 'disabled': - return lambda: f5().set_translate_address_state([name], ['STATE_DISABLED']) - elif a.sub3 == 'enabled': - return lambda: f5().set_translate_address_state([name], ['STATE_ENABLED']) - elif a.sub2 == 'pat': - if a.sub3 == 'disabled': - return lambda: f5().set_translate_port_state([name], ['STATE_DISABLED']) - elif a.sub3 == 'enabled': - return lambda: f5().set_translate_port_state([name], ['STATE_ENABLED']) - elif a.sub2 == 'snat': - if a.sub3 == 'none': - return lambda: f5().set_source_address_translation_none([name]) - - - - def run(self): - ''' Do the actual stuff. - We are doning some lazy evaluation stuff here. The command line - tool does not do anything with the slow F5 API until it is clear - what to do and that there is no semantic or syntax error. ''' - - a = self._args - lazy = None - - if a.name: - # Remove the /partition/ prefix, setting default partition after - # login instead - a.name = re.sub(self._partition, '', a.name) - a.name = re.sub('^/+', '', a.name) - - if a.what == 'node': - lazy = self.__do_node(lambda: self._f5.LocalLB.NodeAddressV2) - elif a.what == 'monitor': - lazy = self.__do_monitor(lambda: self._f5.LocalLB.Monitor) - elif a.what == 'pool': - lazy = self.__do_pool(lambda: self._f5.LocalLB.Pool) - elif a.what == 'vserver': - lazy = self.__do_vserver(lambda: self._f5.LocalLB.VirtualServer) - - if isfunction(lazy): - self.info('Doing some stuf via the API, it may take a while') - self.__login() - self.out(lazy()) - else: - print_synopsis() - sys.exit(1) - - - -if __name__ == '__main__': - ''' The main function, here we will have Popcorn for free! ''' - - parser = argparse.ArgumentParser(add_help=False) - parser.add_argument('-h', action='store_true', help='Help') - parser.add_argument('-v', action='store_true', help='Verbose') - parser.add_argument('-V', action='store_true', help='Print version') - parser.add_argument('-m', action='store', help='The default lbmethod', - default='LB_METHOD_ROUND_ROBIN') - parser.add_argument('-C', action='store', help='Config file', - default=expanduser('~') + '/.fapi.conf') - - parser.add_argument('what', nargs='?', help='node|pool|monitor|vserver|...') - parser.add_argument('name', nargs='?', help='The object name to operate on') - parser.add_argument('sub', nargs='?', help='First sub command') - parser.add_argument('sub2', nargs='?', help='Second sub command') - parser.add_argument('sub3', nargs='?', help='Third sub command') - parser.add_argument('sub4', nargs='?', help='Fourth sub command') - parser.add_argument('sub5', nargs='?', help='Fith sub command') - - args = parser.parse_args() - - if args.h: - parser.print_help() - print '' - print_synopsis() - sys.exit(0) - - if args.V: - sys.exit(0) - - fapi = Fapi(args) - - fapi.run() - -# try: -# if not fapi.run(): -# fapi.info('Don\'t know what to do') -# sys.exit(1) -# except Exception, e: -# fapi.info(e) -# sys.exit(2) - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 -- cgit v1.2.3