4 from os.path import join
15 class HostConfig(object):
16 """Holder for config info from the configuration file"""
18 self.config = { 'version' : 0,
25 _translation = [chr(_x) for _x in range(256)]
26 def _translate(s, altchars):
27 translation = _translation[:]
28 for k, v in altchars.items():
29 translation[ord(k)] = v
30 return s.translate(''.join(translation))
32 def urlsafe_b64encode(s):
35 encoded = binascii.b2a_base64(s)[:-1]
36 if altchars is not None:
37 return _translate(encoded, {'+': altchars[0], '/': altchars[1]})
40 def gen_dirtree(path):
53 # 2009-03-09: MM's web app ignores the statfiles dict. So don't bother generating it.
56 for dirpath, dirnames, filenames in os.walk(path):
58 if path.endswith('/'):
59 short_path = dirpath[len(path):]
61 short_path = dirpath[len(path)+1:]
62 if len(short_path) > 0:
63 dirtree[short_path] = statfiles
65 dirtree[''] = statfiles
69 def errorprint(error):
70 sys.stderr.write(error+'\n')
72 class MissingOption(Exception):
75 def check_required_options(conf, section, required_options):
76 for o in required_options:
77 if not conf.has_option(section, o):
78 errorprint('missing required option %s in config [%s]' % (o, section))
82 def parse_value(value):
83 """Split multi-line values into a list"""
84 if value.find('\n') > -1:
88 def parse_section(conf, section, item, required_options, optional_options=[]):
89 if conf.has_option(section, 'enabled'):
90 if conf.get(section, 'enabled') != '1' and section.lower() in item.config:
91 print 'removing disabled section %s' % (section)
92 del item.config[section.lower()]
95 if not check_required_options(conf, section, required_options):
98 if not section.lower() in item.config:
99 item.config[section.lower()] = {}
101 for o in required_options:
102 item.config[section.lower()][o] = parse_value(conf.get(section, o))
103 for o in optional_options:
104 if conf.has_option(section, o):
105 item.config[section.lower()][o] = parse_value(conf.get(section, o))
109 def parse_global(conf, section, item):
110 required_options = [ 'enabled', 'server' ]
111 if not parse_section(conf, section, item, required_options):
112 errorprint('missing required options (server AND enabled) in [%s] section' % (section))
116 def parse_site(conf, section, item):
117 required_options = [ 'enabled', 'name', 'password' ]
118 return parse_section(conf, section, item, required_options)
120 def parse_host(conf, section, item):
121 required_options = [ 'enabled', 'name' ]
122 optional_options = [ 'user_active' ]
123 return parse_section(conf, section, item, required_options, optional_options=optional_options)
125 def get_stats(conf, section):
126 if conf.has_option(section, 'enabled'):
127 if conf.get(section, 'enabled') != '1':
130 for name, value in conf.items(section):
131 if name == 'enabled':
133 filenames = parse_value(conf.get(section, name))
134 if type(filenames) != list:
135 filenames = [ filenames ]
139 contents = contents + f.readlines()
140 statsdata[name] = pickle.dumps(contents, -1)
146 def parse_category(conf, section, item, crawl):
147 required_options = [ 'enabled', 'path' ]
148 if not parse_section(conf, section, item, required_options):
152 dirtree = gen_dirtree(conf.get(section, 'path'))
153 item.config[section.lower()]['dirtree'] = dirtree
154 # database doesn't need to know the disk path
155 del item.config[section.lower()]['path']
157 def config(cfg, item, crawl=True):
159 conf = ConfigParser.ConfigParser()
160 files = conf.read(cfg)
162 errorprint('Configuration file %s not found' % (cfg))
167 # don't grab parse_stats here
168 for section, parsefunc in [ ('global', parse_global), ('site', parse_site),
169 ('host', parse_host)]:
170 if conf.has_section(section):
171 if not parsefunc(conf, section, item):
174 errorprint('Invalid configuration - missing section [%s]' % (section))
177 for section in conf.sections():
178 if section in [ 'global', 'site', 'host', 'stats']:
180 parse_category(conf, section, item, crawl)
182 except MissingOption:
183 errorprint('Invalid configuration - Exiting')
191 from optparse import OptionParser
192 parser = OptionParser(usage= sys.argv[0] + " [options]")
193 parser.add_option("-c", "--config",
195 default='/etc/mirrormanager-client/report_mirror.conf',
196 help='Configuration filename (required)')
197 parser.add_option("-s", "--stats",
202 parser.add_option("-i", "--input",
205 help="Input filename (for debugging)")
206 parser.add_option("-o", "--output",
209 help="Output filename (for debugging)")
210 parser.add_option("-n", "--no-send",
214 help="Don't send data to the server.")
215 parser.add_option("-d", "--debug",
219 help='Enable debugging output')
222 (options, args) = parser.parse_args()
225 infile = open(options.input, 'rb')
226 item.config = pickle.load(infile)
228 if not config(options.config, item, crawl=False):
231 if not config(options.config, item, crawl=True):
234 p = pickle.dumps(item.config, -1)
237 pp = pprint.PrettyPrinter(indent=4)
238 pp.pprint(item.config)
240 if options.output is not None:
241 outfile = open(options.output, 'wb')
246 statdata = get_stats(conf, 'stats')
248 # upload p and statsdata here
249 if not item.config.has_key('global') or not item.config['global'].has_key('enabled') or item.config['global']['enabled'] != '1':
252 if not options.no_send:
253 # print "Connecting to %s" % item.config['global']['server']
254 server = xmlrpclib.ServerProxy(item.config['global']['server'])
257 data = base64.urlsafe_b64encode(bz2.compress(p))
258 except AttributeError:
259 data = urlsafe_b64encode(bz2.compress(p))
263 print server.checkin(data)
264 except socket.error, m:
265 print "Error checking in: %s. Please try again later." % (m[1])
266 except xmlrpclib.Fault:
267 print "Error checking in. Connection closed before checkin complete. Please try again later."
271 if __name__ == '__main__':