a little nicer wrt pep8
[sfa.git] / sfatables / sfatables
index 8762a50..924c905 100755 (executable)
@@ -1,20 +1,21 @@
-#!/usr/bin/python 
-# SFAtables is a tool for restricting access to an SFA aggregate in a generic
-# and extensible way. 
+#!/usr/bin/env python3
 
-# It is modeled using abstractions in iptables. Specifically, 'matches' specify
-# criteria for matching certain requests, 'targets' specify actions that treat
-# requests in a certain way, and 'chains' are used to group related
-# match-action pairs.
+# This file parses an sfatables command and generates XML files that parameterize
+# matches and targets. Each such XML file defines a rule. Rules are dropped in directories
+# that represent 'chains.' SFA loads rules from various chains and invokes them at certain
+# 'hook points.' For example, it invokes rules in the 'OUTGOING' chain before returning
+# the output of 'get_resources.'
 
 import sys
 import os
-import pdb
-from optparse import OptionParser
+import glob
 
-from sfatables import commands, matches, targets
+from optparse import OptionParser
+from sfatables import commands
+from sfatables.xmlextension import Xmlextension
+from sfatables.globals import target_dir, match_dir
 
-def load_extensions(module, list):
+def load_commands(module, list):
     command_dict={}
 
     for command_name in list:
@@ -24,17 +25,41 @@ def load_extensions(module, list):
 
     return command_dict
 
+def load_xml_extensions(module, ext_dir):
+    ext_dict={}
+
+    exts = glob.glob(ext_dir + os.path.sep + "*")
+    for ext in exts:
+        module = Xmlextension(ext)
+        # get the filename and get rid of the ".xml" extension
+        ext_name = os.path.extsep.join(os.path.splitext(os.path.basename(ext))[:-1])
+        ext_dict[ext_name]=module
+
+    return ext_dict
+
+
 def create_parser(command_dict):
     parser = OptionParser(usage="sfatables [command] [chain] [match] [target]",
                              description='See "man sfatables" for more detail.')
     
-    for k in command_dict.keys():
+    for k in list(command_dict.keys()):
         command = command_dict[k]
         for (short_option,long_option) in command.options:
             parser.add_option(short_option,long_option,dest=command.type,action=command.action,const=k,help=command.help,metavar="CHAIN")
 
     return parser
 
+def create_parser_xml_ext(ext_dict):
+    parser = OptionParser(usage="sfatables [command] [chain] [match] [target]",
+                             description='See "man sfatables" for more detail.')
+    
+    for k in list(ext_dict.keys()):
+        command = ext_dict[k]
+        for arg in command.arguments:
+            parser.add_option('',"--"+arg['name'],dest=arg['name'],help=arg['help'],metavar=arg['target'])
+
+    return parser
+
 
 def partition(sep, lst):
     ret = []
@@ -51,31 +76,57 @@ def partition(sep, lst):
 
 
 def main():
-    # Segment command line into three blobs, one each for the command, match and target respectively.
-    
+    # sfatables <command> -- <match> -- <target>
     pargs = partition('--', sys.argv[1:])
 
-    command_dict = load_extensions("sfatables.commands",commands.all)
+    command_dict = load_commands("sfatables.commands",commands.all)
     command_parser = create_parser(command_dict)
-    (options, args) = command_parser.parse_args()
+    (options, args) = command_parser.parse_args(pargs[0])
+    setattr(options, 'args', args)
 
     command = command_dict[options.command]
 
     if (command.matches):
         if (len(pargs)<2):
             raise Exception("Must specify match for this command")
-        match_dict = load_extensions("sfatables.matches",matches.all)
-        match_parser = create_parser(match_dict)
+        match_dict = load_xml_extensions("sfatables.matches",match_dir)
+        match_parser = create_parser_xml_ext(match_dict)
+        matches_str = ",".join(list(match_dict.keys()))
+        match_parser.add_option('-m','--match',dest='name',help='Match name (one of %s)'%matches_str, metavar = 'MATCH')
+        match_parser.add_option('-n','--negate',dest='negate',help='Negate result',action='store_true')
         (match_options, args) = match_parser.parse_args(pargs[1])
+        try:
+            name = match_options.name
+        except Exception:
+            print("Must specify match name with -m")
+
+        if (name in match_dict):
+            setattr(match_options, 'arguments', match_dict[name].arguments)
+        else:
+            raise Exception('Match %s not found'%name)
+
     else:
         match_options=None
 
     if (command.targets):
         if (len(pargs)<3):
             raise Exception("Must specify a target for this command")
-        match_dict = load_extensions("sfatables.targets",targets.all)
-        target_parser = create_parser(match_dict)
+        target_dict = load_xml_extensions("sfatables.targets",target_dir)
+        target_parser = create_parser_xml_ext(target_dict)
+        targets_str = ",".join(list(target_dict.keys()))
+        target_parser.add_option('-j','--jump',dest='name',help='Target name (one of %s)'%targets_str, metavar = 'TARGET')
+        target_parser.add_option('-e','--element',dest='element',help='Element name', metavar = 'ELEMENT')
         (target_options, args) = target_parser.parse_args(pargs[2])
+        try:
+            name = target_options.name
+        except Exception:
+            print("Must specify target name with -j")
+
+        if (name in target_dict):
+            setattr(target_options, 'arguments', target_dict[name].arguments)
+        else:
+            raise Exception('Target %s not found'%name)
+
     else:
         target_options = None