minor cosmetic in conf_files
[nodemanager.git] / conf_files.py
1 #!/usr/bin/env python3
2
3 """configuration files"""
4
5 import grp
6 import os
7 import pwd
8 from hashlib import sha1 as sha
9 import xmlrpc.client
10
11 import curlwrapper
12 import logger
13 import tools
14 from config import Config
15
16 # right after net
17 priority = 2
18
19 class conf_files:
20     def __init__(self, noscripts=False):
21         self.config = Config()
22         self.noscripts = noscripts
23         self.data = None
24
25     def checksum(self, path):
26         try:
27             f = open(path)
28             try: return sha(f.read()).digest()
29             finally: f.close()
30         except IOError: return None
31
32     def system(self, cmd):
33         if not self.noscripts and cmd:
34             logger.verbose('conf_files: running command %s' % cmd)
35             return tools.fork_as(None, os.system, cmd)
36         else: return 0
37
38     def update_conf_file(self, cf_rec):
39         if not cf_rec['enabled']:
40             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)