4d16b16c3e79e3d08daf7bf3c798c6f4c0409a14
[bootmanager.git] / source / steps / UpdateNodeConfiguration.py
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2003 Intel Corporation
4 # All rights reserved.
5 #
6 # Copyright (c) 2004-2006 The Trustees of Princeton University
7 # All rights reserved.
8
9
10 import os
11
12 from Exceptions import *
13 import utils
14
15
16 # if this file is present in the vservers /etc directory,
17 # the resolv.conf and hosts files will automatically be updated
18 # by the bootmanager
19 UPDATE_FILE_FLAG = "AUTO_UPDATE_NET_FILES"
20
21
22 def Run(vars, log):
23     """
24     Reconfigure a node if necessary, including rewriting any network init
25     scripts based on what PLC has. Also, update any slivers on the machine
26     incase their network files are out of date (primarily /etc/hosts).
27
28     Also write out /etc/planetlab/session, a random string that gets
29     a new value at every request of BootGetNodeDetails (ie, every boot)
30
31     This step expects the root to be already mounted on SYSIMG_PATH.
32     
33     Except the following keys to be set:
34     SYSIMG_PATH              the path where the system image will be mounted
35                              (always starts with TEMP_PATH)
36     ROOT_MOUNTED             the node root file system is mounted
37     INTERFACE_SETTINGS  A dictionary of the values from the network
38                                 configuration file
39     """
40     
41     log.write("\n\nStep: Updating node configuration.\n")
42
43     # make sure we have the variables we need
44     try:
45         INTERFACE_SETTINGS = vars["INTERFACE_SETTINGS"]
46         if INTERFACE_SETTINGS == "":
47             raise ValueError("INTERFACE_SETTINGS")
48
49         SYSIMG_PATH = vars["SYSIMG_PATH"]
50         if SYSIMG_PATH == "":
51             raise ValueError("SYSIMG_PATH")
52
53         ROOT_MOUNTED = vars["ROOT_MOUNTED"]
54         if ROOT_MOUNTED == "":
55             raise ValueError("ROOT_MOUNTED")
56
57     except KeyError as var:
58         raise BootManagerException("Missing variable in vars: {}\n".format(var))
59     except ValueError as var:
60         raise BootManagerException("Variable in vars, shouldn't be: {}\n".format(var))
61
62     try:
63         ip = INTERFACE_SETTINGS['ip']
64         method = INTERFACE_SETTINGS['method']
65         hostname = INTERFACE_SETTINGS['hostname']
66         domainname = INTERFACE_SETTINGS['domainname']
67     except KeyError as var:
68         raise BootManagerException(
69               "Missing network value {} in var INTERFACE_SETTINGS\n".format(var))
70
71     
72     if not ROOT_MOUNTED:
73         raise BootManagerException("Root isn't mounted on SYSIMG_PATH\n")
74
75     log.write("Updating vserver's /etc/hosts and /etc/resolv.conf files\n")
76
77     # create a list of the full directory paths of all the vserver images that
78     # need to be updated.
79     update_path_list = []
80
81     for base_dir in ('/vservers', '/vservers/.vref', '/vservers/.vcache'):
82         try:
83             full_dir_path = "{}/{}".format(SYSIMG_PATH, base_dir)
84             slices = os.listdir(full_dir_path)
85
86             try:
87                 slices.remove("lost+found")
88             except ValueError as e:
89                 pass
90             
91             update_path_list = update_path_list + map(lambda x: \
92                                                      full_dir_path+"/"+x,
93                                                      slices)
94         except OSError as e:
95             continue
96
97
98     log.write("Updating network configuration in:\n")
99     if len(update_path_list) == 0:
100         log.write("No vserver images found to update.\n")
101     else:
102         for base_dir in update_path_list:
103             log.write("{}\n".format(base_dir))
104
105
106     # now, update /etc/hosts and /etc/resolv.conf in each dir if
107     # the update flag is there
108     for base_dir in update_path_list:
109         update_vserver_network_files(base_dir, vars, log)
110     
111     return
112
113
114
115 def update_vserver_network_files(vserver_dir, vars, log):
116     """
117     Update the /etc/resolv.conf and /etc/hosts files in the specified
118     vserver directory. If the files do not exist, write them out. If they
119     do exist, rewrite them with new values if the file UPDATE_FILE_FLAG
120     exists it /etc. if this is called with the vserver-reference directory,
121     always update the network config files and create the UPDATE_FILE_FLAG.
122
123     This is currently called when setting up the initial vserver reference,
124     and later when nodes boot to update existing vserver images.
125
126     Expect the following variables from the store:
127     SYSIMG_PATH        the path where the system image will be mounted
128                        (always starts with TEMP_PATH)
129     INTERFACE_SETTINGS   A dictionary of the values from the network
130                        configuration file
131     """
132
133     try:
134         SYSIMG_PATH = vars["SYSIMG_PATH"]
135         if SYSIMG_PATH == "":
136             raise ValueError("SYSIMG_PATH")
137
138         INTERFACE_SETTINGS = vars["INTERFACE_SETTINGS"]
139         if INTERFACE_SETTINGS == "":
140             raise ValueError("INTERFACE_SETTINGS")
141
142     except KeyError as var:
143         raise BootManagerException("Missing variable in vars: {}\n".format(var))
144     except ValueError as var:
145         raise BootManagerException("Variable in vars, shouldn't be: {}\n".format(var))
146
147     try:
148         ip = INTERFACE_SETTINGS['ip']
149         method = INTERFACE_SETTINGS['method']
150         hostname = INTERFACE_SETTINGS['hostname']
151         domainname = INTERFACE_SETTINGS['domainname']
152     except KeyError as var:
153         raise BootManagerException(
154               "Missing network value {} in var INTERFACE_SETTINGS\n".format(var))
155
156     try:
157         os.listdir(vserver_dir)
158     except OSError:
159         log.write("Directory {} does not exist to write network conf in.\n"
160                   .format(vserver_dir))
161         return
162
163     file_path = "{}/etc/{}".format(vserver_dir, UPDATE_FILE_FLAG)
164     update_files = 0
165     if os.access(file_path, os.F_OK):
166         update_files = 1
167
168         
169     # Thierry - 2012/03 - I'm renaming vserver-reference into sliceimage
170     # however I can't quite grasp the reason for this test below, very likely 
171     # compatibility with very old node images or something
172     if '/.vref/' in vserver_dir or \
173        '/.vcache/' in vserver_dir or \
174        '/vserver-reference' in vserver_dir:
175         log.write("Forcing update on vserver reference directory:\n{}\n"
176                   .format(vserver_dir))
177         utils.sysexec_noerr("echo '{}' > {}/etc/{}"
178                             .format(UPDATE_FILE_FLAG, vserver_dir, UPDATE_FILE_FLAG),
179                              log)
180         update_files = 1
181         
182
183     if update_files:
184         log.write("Updating network files in {}.\n".format(vserver_dir))
185         try:
186             # NOTE: this works around a recurring problem on public pl,
187             # suspected to be due to mismatch between 2.6.12 bootcd and
188             # 2.6.22/f8 root environment.  files randomly show up with the
189             # immutible attribute set.  this clears it before trying to write
190             # the files below.
191             utils.sysexec("chattr -i {}/etc/hosts".format(vserver_dir), log)
192             utils.sysexec("chattr -i {}/etc/resolv.conf".format(vserver_dir), log)
193         except:
194             pass
195
196         
197         file_path = "{}/etc/hosts".format(vserver_dir)
198         hosts_file = file(file_path, "w")
199         hosts_file.write("127.0.0.1       localhost\n")
200         if method == "static":
201             hosts_file.write("{} {}.{}\n".format(ip, hostname, domainname))
202         hosts_file.close()
203         hosts_file = None
204
205         file_path = "{}/etc/resolv.conf".format(vserver_dir)
206         if method == "dhcp":
207             # copy the resolv.conf from the boot cd env.
208             utils.sysexec("cp /etc/resolv.conf {}/etc".format(vserver_dir), log)
209         else:
210             # copy the generated resolv.conf from the system image, since
211             # we generated it via static settings
212             utils.sysexec("cp {}/etc/resolv.conf {}/etc"
213                           .format(SYSIMG_PATH, vserver_dir), log)
214             
215     return