a little nicer wrt pep8
[sfa.git] / sfatables / sfatables
1 #!/usr/bin/env python3
2
3 # This file parses an sfatables command and generates XML files that parameterize
4 # matches and targets. Each such XML file defines a rule. Rules are dropped in directories
5 # that represent 'chains.' SFA loads rules from various chains and invokes them at certain
6 # 'hook points.' For example, it invokes rules in the 'OUTGOING' chain before returning
7 # the output of 'get_resources.'
8
9 import sys
10 import os
11 import glob
12
13 from optparse import OptionParser
14 from sfatables import commands
15 from sfatables.xmlextension import Xmlextension
16 from sfatables.globals import target_dir, match_dir
17
18 def load_commands(module, list):
19     command_dict={}
20
21     for command_name in list:
22         command_module = __import__(".".join([module,command_name]),fromlist=[module])
23         command = getattr(command_module, command_name)
24         command_dict[command_name]=command()
25
26     return command_dict
27
28 def load_xml_extensions(module, ext_dir):
29     ext_dict={}
30
31     exts = glob.glob(ext_dir + os.path.sep + "*")
32     for ext in exts:
33         module = Xmlextension(ext)
34         # get the filename and get rid of the ".xml" extension
35         ext_name = os.path.extsep.join(os.path.splitext(os.path.basename(ext))[:-1])
36         ext_dict[ext_name]=module
37
38     return ext_dict
39
40
41 def create_parser(command_dict):
42     parser = OptionParser(usage="sfatables [command] [chain] [match] [target]",
43                              description='See "man sfatables" for more detail.')
44     
45     for k in list(command_dict.keys()):
46         command = command_dict[k]
47         for (short_option,long_option) in command.options:
48             parser.add_option(short_option,long_option,dest=command.type,action=command.action,const=k,help=command.help,metavar="CHAIN")
49
50     return parser
51
52 def create_parser_xml_ext(ext_dict):
53     parser = OptionParser(usage="sfatables [command] [chain] [match] [target]",
54                              description='See "man sfatables" for more detail.')
55     
56     for k in list(ext_dict.keys()):
57         command = ext_dict[k]
58         for arg in command.arguments:
59             parser.add_option('',"--"+arg['name'],dest=arg['name'],help=arg['help'],metavar=arg['target'])
60
61     return parser
62
63
64 def partition(sep, lst):
65     ret = []
66     curpart = []
67     for item in lst:
68         if (item==sep):
69             ret.append(curpart)
70             curpart=[]
71         else:
72             curpart.append(item)
73     ret.append(curpart)
74
75     return ret
76
77
78 def main():
79     # sfatables <command> -- <match> -- <target>
80     pargs = partition('--', sys.argv[1:])
81
82     command_dict = load_commands("sfatables.commands",commands.all)
83     command_parser = create_parser(command_dict)
84     (options, args) = command_parser.parse_args(pargs[0])
85     setattr(options, 'args', args)
86
87     command = command_dict[options.command]
88
89     if (command.matches):
90         if (len(pargs)<2):
91             raise Exception("Must specify match for this command")
92         match_dict = load_xml_extensions("sfatables.matches",match_dir)
93         match_parser = create_parser_xml_ext(match_dict)
94         matches_str = ",".join(list(match_dict.keys()))
95         match_parser.add_option('-m','--match',dest='name',help='Match name (one of %s)'%matches_str, metavar = 'MATCH')
96         match_parser.add_option('-n','--negate',dest='negate',help='Negate result',action='store_true')
97         (match_options, args) = match_parser.parse_args(pargs[1])
98         try:
99             name = match_options.name
100         except Exception:
101             print("Must specify match name with -m")
102
103         if (name in match_dict):
104             setattr(match_options, 'arguments', match_dict[name].arguments)
105         else:
106             raise Exception('Match %s not found'%name)
107
108     else:
109         match_options=None
110
111     if (command.targets):
112         if (len(pargs)<3):
113             raise Exception("Must specify a target for this command")
114         target_dict = load_xml_extensions("sfatables.targets",target_dir)
115         target_parser = create_parser_xml_ext(target_dict)
116         targets_str = ",".join(list(target_dict.keys()))
117         target_parser.add_option('-j','--jump',dest='name',help='Target name (one of %s)'%targets_str, metavar = 'TARGET')
118         target_parser.add_option('-e','--element',dest='element',help='Element name', metavar = 'ELEMENT')
119         (target_options, args) = target_parser.parse_args(pargs[2])
120         try:
121             name = target_options.name
122         except Exception:
123             print("Must specify target name with -j")
124
125         if (name in target_dict):
126             setattr(target_options, 'arguments', target_dict[name].arguments)
127         else:
128             raise Exception('Target %s not found'%name)
129
130     else:
131         target_options = None
132
133     command(options, match_options, target_options)
134
135 if __name__=='__main__':
136     main()