da4c313e8e56013d769c550ad4aeeb2435d8c592
[nodemanager.git] / conf_files.py
1 """configuration files"""
2
3 import grp
4 import os
5 import pwd
6 try:
7     from hashlib import sha1 as sha
8 except ImportError:
9     from sha import sha
10
11 import curlwrapper
12 import logger
13 import tools
14 import xmlrpc.client
15 from config import Config
16
17 # right after net
18 priority = 2
19
20 class conf_files:
21     def __init__(self, noscripts=False):
22         self.config = Config()
23         self.noscripts = noscripts
24         self.data = None
25
26     def checksum(self, path):
27         try:
28             f = open(path)
29             try: return sha(f.read()).digest()
30             finally: f.close()
31         except IOError: return None
32
33     def system(self, cmd):
34         if not self.noscripts and cmd:
35             logger.verbose('conf_files: running command %s' % cmd)
36             return tools.fork_as(None, os.system, cmd)
37         else: return 0
38
39     def update_conf_file(self, cf_rec):
40         if not cf_rec['enabled']: return
41         dest = cf_rec['dest']
42         err_cmd = cf_rec['error_cmd']
43         mode = int(cf_rec['file_permissions'], base=8)
44         try:
45             uid = pwd.getpwnam(cf_rec['file_owner'])[2]
46         except:
47             logger.log('conf_files: cannot find user %s -- %s not updated'%(cf_rec['file_owner'], dest))
48             return
49         try:
50             gid = grp.getgrnam(cf_rec['file_group'])[2]
51         except:
52             logger.log('conf_files: cannot find group %s -- %s not updated'%(cf_rec['file_group'], dest))
53             return
54         url = 'https://%s/%s' % (self.config.PLC_BOOT_HOST, cf_rec['source'])
55         # set node_id at the end of the request - hacky
56         if tools.node_id():
57             if url.find('?') >0: url += '&'
58             else:                url += '?'
59             url += "node_id=%d"%tools.node_id()
60         else:
61             logger.log('conf_files: %s -- WARNING, cannot add node_id to request'%dest)
62         try:
63             logger.verbose("conf_files: retrieving URL=%s"%url)
64             contents = curlwrapper.retrieve(url, self.config.cacert)
65         except xmlrpc.client.ProtocolError as e:
66             logger.log('conf_files: failed to retrieve %s from %s, skipping' % (dest, url))
67             return
68         if not cf_rec['always_update'] and sha(contents).digest() == self.checksum(dest):
69             return
70         if self.system(cf_rec['preinstall_cmd']):
71             self.system(err_cmd)
72             if not cf_rec['ignore_cmd_errors']: return
73         logger.log('conf_files: installing file %s from %s' % (dest, url))
74         try: os.makedirs(os.path.dirname(dest))
75         except OSError: pass
76         tools.write_file(dest, lambda f: f.write(contents), mode=mode, uidgid=(uid, gid))
77         if self.system(cf_rec['postinstall_cmd']): self.system(err_cmd)
78
79     def run_once(self, data):
80         if "conf_files" in data:
81             for f in data['conf_files']:
82                 try: self.update_conf_file(f)
83                 except: logger.log_exc("conf_files: failed to update conf_file")
84         else:
85             logger.log_missing_data("conf_files.run_once", 'conf_files')
86
87
88 def start(): pass
89
90 def GetSlivers(data, config = None, plc = None):
91     logger.log("conf_files: Running.")
92     cf = conf_files()
93     cf.run_once(data)
94     logger.log("conf_files: Done.")
95
96 if __name__ == '__main__':
97     import optparse
98     parser = optparse.OptionParser()
99     parser.add_option('-f', '--config', action='store', dest='config', default='/etc/planetlab/plc_config', help='PLC configuration file')
100     parser.add_option('-k', '--session', action='store', dest='session', default='/etc/planetlab/session', help='API session key (or file)')
101     parser.add_option('--noscripts', action='store_true', dest='noscripts', default=False, help='Do not run pre- or post-install scripts')
102     (options, args) = parser.parse_args()
103
104     # Load /etc/planetlab/plc_config
105     config = Config(options.config)
106
107     # Load /etc/planetlab/session
108     if os.path.exists(options.session):
109         with open(options.session) as f:
110             session = f.read().strip()
111     else:
112         session = options.session
113
114     # Initialize XML-RPC client
115     from plcapi import PLCAPI
116     plc = PLCAPI(config.plc_api_uri, config.cacert, auth = session)
117
118     main = conf_files(options.noscripts)
119     data = plc.GetSlivers()
120     main.run_once(data)