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