99e1a8cf1a1bd99f3698f811ca119ecb3e7ac321
[bootmanager.git] / source / steps / ReadNodeConfiguration.py
1 # Copyright (c) 2003 Intel Corporation
2 # All rights reserved.
3
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7
8 #     * Redistributions of source code must retain the above copyright
9 #       notice, this list of conditions and the following disclaimer.
10
11 #     * Redistributions in binary form must reproduce the above
12 #       copyright notice, this list of conditions and the following
13 #       disclaimer in the documentation and/or other materials provided
14 #       with the distribution.
15
16 #     * Neither the name of the Intel Corporation nor the names of its
17 #       contributors may be used to endorse or promote products derived
18 #       from this software without specific prior written permission.
19
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
24 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 # EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
33 # YOUR JURISDICTION. It is licensee's responsibility to comply with any
34 # export regulations applicable in licensee's jurisdiction. Under
35 # CURRENT (May 2000) U.S. export regulations this software is eligible
36 # for export from the U.S. and can be downloaded by or otherwise
37 # exported or reexported worldwide EXCEPT to U.S. embargoed destinations
38 # which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
39 # Afghanistan and any other country to which the U.S. has embargoed
40 # goods and services.
41
42
43 import sys, os, traceback
44 import string
45 import socket
46 import re
47
48 import utils
49 from Exceptions import *
50 import BootServerRequest
51 import BootAPI
52 import StartDebug
53 import notify_messages
54 import UpdateBootStateWithPLC
55
56
57 # two possible names of the configuration files
58 NEW_CONF_FILE_NAME= "plnode.txt"
59 OLD_CONF_FILE_NAME= "planet.cnf"
60
61
62 def Run( vars, log ):   
63     """
64     read the machines node configuration file, which contains
65     the node key and the node_id for this machine.
66     
67     these files can exist in several different locations with
68     several different names. Below is the search order:
69
70     filename      floppy   flash    ramdisk    cd
71     plnode.txt      1        2      4 (/)      5 (/usr/boot), 6 (/usr)
72     planet.cnf      3
73
74     The locations will be searched in the above order, plnode.txt
75     will be checked first, then planet.cnf. Flash devices will only
76     be searched on 3.0 cds.
77
78     Because some of the earlier
79     boot cds don't validate the configuration file (which results
80     in a file named /tmp/planet-clean.cnf), and some do, lets
81     bypass this, and mount and attempt to read in the conf
82     file ourselves. If it doesn't exist, we cannot continue, and a
83     BootManagerException will be raised. If the configuration file is found
84     and read, return 1.
85
86     Expect the following variables from the store:
87     BOOT_CD_VERSION          A tuple of the current bootcd version
88     SUPPORT_FILE_DIR         directory on the boot servers containing
89                              scripts and support files
90     
91     Sets the following variables from the configuration file:
92     WAS_NODE_ID_IN_CONF         Set to 1 if the node id was in the conf file
93     WAS_NODE_KEY_IN_CONF         Set to 1 if the node key was in the conf file
94     NONE_ID                     The db node_id for this machine
95     NODE_KEY                    The key for this node
96     NETWORK_SETTINGS            A dictionary of the values from the network
97                                 configuration file. keys set:
98                                    method
99                                    ip        
100                                    mac       
101                                    gateway   
102                                    network   
103                                    broadcast 
104                                    netmask   
105                                    dns1      
106                                    dns2      
107                                    hostname  
108                                    domainname
109
110     the mac address is read from the machine unless it exists in the
111     configuration file.
112     """
113
114     log.write( "\n\nStep: Reading node configuration file.\n" )
115
116
117     # make sure we have the variables we need
118     try:
119         BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
120         if BOOT_CD_VERSION == "":
121             raise ValueError, "BOOT_CD_VERSION"
122
123         SUPPORT_FILE_DIR= vars["SUPPORT_FILE_DIR"]
124         if SUPPORT_FILE_DIR == None:
125             raise ValueError, "SUPPORT_FILE_DIR"
126
127     except KeyError, var:
128         raise BootManagerException, "Missing variable in vars: %s\n" % var
129     except ValueError, var:
130         raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
131
132
133     NETWORK_SETTINGS= {}
134     NETWORK_SETTINGS['method']= "dhcp"
135     NETWORK_SETTINGS['ip']= ""
136     NETWORK_SETTINGS['mac']= ""
137     NETWORK_SETTINGS['gateway']= ""
138     NETWORK_SETTINGS['network']= ""
139     NETWORK_SETTINGS['broadcast']= ""
140     NETWORK_SETTINGS['netmask']= ""
141     NETWORK_SETTINGS['dns1']= ""
142     NETWORK_SETTINGS['dns2']= ""
143     NETWORK_SETTINGS['hostname']= "localhost"
144     NETWORK_SETTINGS['domainname']= "localdomain"
145     vars['NETWORK_SETTINGS']= NETWORK_SETTINGS
146
147     vars['NODE_ID']= 0
148     vars['NODE_KEY']= ""
149
150     vars['WAS_NODE_ID_IN_CONF']= 0
151     vars['WAS_NODE_KEY_IN_CONF']= 0
152
153     # for any devices that need to be mounted to get the configuration
154     # file, mount them here.
155     mount_point= "/tmp/conffilemount"
156     utils.makedirs( mount_point )
157
158     old_conf_file_contents= None
159     conf_file_contents= None
160     
161     
162     # 1. check the regular floppy device
163     log.write( "Checking standard floppy disk for plnode.txt file.\n" )
164
165     log.write( "Mounting /dev/fd0 on %s\n" % mount_point )
166     utils.sysexec_noerr( "mount -o ro -t ext2,msdos /dev/fd0 %s " \
167                          % mount_point, log )
168
169     conf_file_path= "%s/%s" % (mount_point,NEW_CONF_FILE_NAME)
170     
171     log.write( "Checking for existence of %s\n" % conf_file_path )
172     if os.access( conf_file_path, os.R_OK ):
173         try:
174             conf_file= file(conf_file_path,"r")
175             conf_file_contents= conf_file.read()
176             conf_file.close()
177             log.write( "Read in contents of file %s\n" % conf_file_path )
178         except IOError, e:
179             log.write( "Unable to read file %s\n" % conf_file_path )
180             pass
181
182         utils.sysexec_noerr( "umount %s" % mount_point, log )
183         if __parse_configuration_file( vars, log, conf_file_contents):
184             return 1
185         else:
186             raise BootManagerException( "Found configuration file plnode.txt " \
187                                         "on floppy, but was unable to parse it." )
188
189
190     # try the old file name, same device. its actually number 3 on the search
191     # order, but do it now to save mounting/unmounting the disk twice.
192     # try to parse it later...
193     conf_file_path= "%s/%s" % (mount_point,OLD_CONF_FILE_NAME)
194
195     log.write( "Checking for existence of %s (used later)\n" % conf_file_path )
196     if os.access( conf_file_path, os.R_OK ):
197         try:
198             old_conf_file= file(conf_file_path,"r")
199             old_conf_file_contents= old_conf_file.read()
200             old_conf_file.close()
201             log.write( "Read in contents of file %s\n" % conf_file_path )
202         except IOError, e:
203             log.write( "Unable to read file %s\n" % conf_file_path )
204             pass
205         
206     utils.sysexec_noerr( "umount %s" % mount_point, log )
207
208
209
210     if BOOT_CD_VERSION[0] == 3:
211         # 2. check flash devices on 3.0 based cds
212         log.write( "Checking flash devices for plnode.txt file.\n" )
213
214         # this is done the same way the 3.0 cds do it, by attempting
215         # to mount and sd*1 devices that are removable
216         devices= os.listdir("/sys/block/")
217
218         for device in devices:
219             if device[:2] != "sd":
220                 log.write( "Skipping non-scsi device %s\n" % device )
221                 continue
222
223             # test removable
224             removable_file_path= "/sys/block/%s/removable" % device
225             try:
226                 removable= int(file(removable_file_path,"r").read().strip())
227             except ValueError, e:
228                 continue
229             except IOError, e:
230                 continue
231
232             if not removable:
233                 log.write( "Skipping non-removable device %s\n" % device )
234                 continue
235
236             log.write( "Checking removable device %s\n" % device )
237
238             partitions= file("/proc/partitions", "r")
239             for line in partitions:
240                 found_file= 0
241                 parsed_file= 0
242                 
243                 if not re.search("%s[0-9]*$" % device, line):
244                     continue
245
246                 try:
247                     # major minor  #blocks  name
248                     parts= string.split(line)
249
250                     # ok, try to mount it and see if we have a conf file.
251                     full_device= "/dev/%s" % parts[3]
252                 except IndexError, e:
253                     log.write( "Incorrect /proc/partitions line:\n%s\n" % line )
254                     continue
255
256                 log.write( "Mounting %s on %s\n" % (full_device,mount_point) )
257                 try:
258                     utils.sysexec( "mount -o ro -t ext2,msdos %s %s" \
259                                    % (full_device,mount_point), log )
260                 except BootManagerException, e:
261                     log.write( "Unable to mount, trying next partition\n" )
262                     continue
263
264                 conf_file_path= "%s/%s" % (mount_point,NEW_CONF_FILE_NAME)
265
266                 log.write( "Checking for existence of %s\n" % conf_file_path )
267                 if os.access( conf_file_path, os.R_OK ):
268                     try:
269                         conf_file= file(conf_file_path,"r")
270                         conf_file_contents= conf_file.read()
271                         conf_file.close()
272                         found_file= 1
273                         log.write( "Read in contents of file %s\n" % \
274                                    conf_file_path )
275
276                         if __parse_configuration_file( vars, log, \
277                                                        conf_file_contents):
278                             parsed_file= 1
279                     except IOError, e:
280                         log.write( "Unable to read file %s\n" % conf_file_path )
281
282                 utils.sysexec_noerr( "umount %s" % mount_point, log )
283                 if found_file:
284                     if parsed_file:
285                         return 1
286                     else:
287                         raise BootManagerException( \
288                             "Found configuration file plnode.txt " \
289                             "on floppy, but was unable to parse it.")
290
291
292             
293     # 3. check standard floppy disk for old file name planet.cnf
294     log.write( "Checking standard floppy disk for planet.cnf file " \
295                "(from earlier.\n" )
296
297     if old_conf_file_contents:
298         if __parse_configuration_file( vars, log, old_conf_file_contents):
299             return 1
300         else:
301             raise BootManagerException( "Found configuration file planet.cnf " \
302                                         "on floppy, but was unable to parse it." )
303
304
305     # 4. check for plnode.txt in / (ramdisk)
306     log.write( "Checking / (ramdisk) for plnode.txt file.\n" )
307     
308     conf_file_path= "/%s" % NEW_CONF_FILE_NAME
309
310     log.write( "Checking for existence of %s\n" % conf_file_path )
311     if os.access(conf_file_path,os.R_OK):
312         try:
313             conf_file= file(conf_file_path,"r")
314             conf_file_contents= conf_file.read()
315             conf_file.close()
316             log.write( "Read in contents of file %s\n" % conf_file_path )
317         except IOError, e:
318             log.write( "Unable to read file %s\n" % conf_file_path )
319             pass
320     
321         if __parse_configuration_file( vars, log, conf_file_contents):            
322             return 1
323         else:
324             raise BootManagerException( "Found configuration file plnode.txt " \
325                                         "in /, but was unable to parse it.")
326
327     
328     # 5. check for plnode.txt in /usr/boot (mounted already)
329     log.write( "Checking /usr/boot (cd) for plnode.txt file.\n" )
330     
331     conf_file_path= "/usr/boot/%s" % NEW_CONF_FILE_NAME
332
333     log.write( "Checking for existence of %s\n" % conf_file_path )
334     if os.access(conf_file_path,os.R_OK):
335         try:
336             conf_file= file(conf_file_path,"r")
337             conf_file_contents= conf_file.read()
338             conf_file.close()
339             log.write( "Read in contents of file %s\n" % conf_file_path )
340         except IOError, e:
341             log.write( "Unable to read file %s\n" % conf_file_path )
342             pass
343     
344         if __parse_configuration_file( vars, log, conf_file_contents):            
345             return 1
346         else:
347             raise BootManagerException( "Found configuration file plnode.txt " \
348                                         "in /usr/boot, but was unable to parse it.")
349
350
351
352     # 6. check for plnode.txt in /usr (mounted already)
353     log.write( "Checking /usr (cd) for plnode.txt file.\n" )
354     
355     conf_file_path= "/usr/%s" % NEW_CONF_FILE_NAME
356
357     log.write( "Checking for existence of %s\n" % conf_file_path )
358     if os.access(conf_file_path,os.R_OK):
359         try:
360             conf_file= file(conf_file_path,"r")
361             conf_file_contents= conf_file.read()
362             conf_file.close()
363             log.write( "Read in contents of file %s\n" % conf_file_path )
364         except IOError, e:
365             log.write( "Unable to read file %s\n" % conf_file_path )
366             pass    
367     
368         if __parse_configuration_file( vars, log, conf_file_contents):            
369             return 1
370         else:
371             raise BootManagerException( "Found configuration file plnode.txt " \
372                                         "in /usr, but was unable to parse it.")
373
374
375     raise BootManagerException, "Unable to find and read a node configuration file."
376     
377
378
379
380 def __parse_configuration_file( vars, log, file_contents ):
381     """
382     parse a configuration file, set keys in var NETWORK_SETTINGS
383     in vars (see comment for function ReadNodeConfiguration). this
384     also reads the mac address from the machine if successful parsing
385     of the configuration file is completed.
386     """
387
388     BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
389     SUPPORT_FILE_DIR= vars["SUPPORT_FILE_DIR"]
390     NETWORK_SETTINGS= vars["NETWORK_SETTINGS"]
391     
392     if file_contents is None:
393         log.write( "__parse_configuration_file called with no file contents\n" )
394         return 0
395     
396     try:
397         line_num= 0
398         for line in file_contents.split("\n"):
399
400             line_num = line_num + 1
401             
402             # if its a comment or a whitespace line, ignore
403             if line[:1] == "#" or string.strip(line) == "":
404                 continue
405
406             # file is setup as name="value" pairs
407             parts= string.split(line,"=")
408             if len(parts) != 2:
409                 log.write( "Invalid line %d in configuration file:\n" % line_num )
410                 log.write( line + "\n" )
411                 return 0
412
413             name= string.strip(parts[0])
414             value= string.strip(parts[1])
415
416             # make sure value starts and ends with
417             # single or double quotes
418             quotes= value[0] + value[len(value)-1]
419             if quotes != "''" and quotes != '""':
420                 log.write( "Invalid line %d in configuration file:\n" % line_num )
421                 log.write( line + "\n" )
422                 return 0
423
424             # get rid of the quotes around the value
425             value= string.strip(value[1:len(value)-1])
426
427             if name == "NODE_ID":
428                 try:
429                     vars['NODE_ID']= int(value)
430                     vars['WAS_NODE_ID_IN_CONF']= 1
431                 except ValueError, e:
432                     log.write( "Non-numeric node_id in configuration file.\n" )
433                     return 0
434
435             if name == "NODE_KEY":
436                 vars['NODE_KEY']= value
437                 vars['WAS_NODE_KEY_IN_CONF']= 1
438
439             if name == "IP_METHOD":
440                 value= string.lower(value)
441                 if value != "static" and value != "dhcp":
442                     log.write( "Invalid IP_METHOD in configuration file:\n" )
443                     log.write( line + "\n" )
444                     return 0
445                 NETWORK_SETTINGS['method']= value.strip()
446
447             if name == "IP_ADDRESS":
448                 NETWORK_SETTINGS['ip']= value.strip()
449
450             if name == "IP_GATEWAY":
451                 NETWORK_SETTINGS['gateway']= value.strip()
452
453             if name == "IP_NETMASK":
454                 NETWORK_SETTINGS['netmask']= value.strip()
455
456             if name == "IP_NETADDR":
457                 NETWORK_SETTINGS['network']= value.strip()
458
459             if name == "IP_BROADCASTADDR":
460                 NETWORK_SETTINGS['broadcast']= value.strip()
461
462             if name == "IP_DNS1":
463                 NETWORK_SETTINGS['dns1']= value.strip()
464
465             if name == "IP_DNS2":
466                 NETWORK_SETTINGS['dns2']= value.strip()
467
468             if name == "HOST_NAME":
469                 NETWORK_SETTINGS['hostname']= string.lower(value)
470
471             if name == "DOMAIN_NAME":
472                 NETWORK_SETTINGS['domainname']= string.lower(value)
473
474             if name == "NET_DEVICE":
475                 NETWORK_SETTINGS['mac']= string.upper(value)
476                 
477
478     except IndexError, e:
479         log.write( "Unable to parse configuration file\n" )
480         return 0
481
482     # now if we are set to dhcp, clear out any fields
483     # that don't make sense
484     if NETWORK_SETTINGS["method"] == "dhcp":
485         NETWORK_SETTINGS["ip"]= ""
486         NETWORK_SETTINGS["gateway"]= ""     
487         NETWORK_SETTINGS["netmask"]= ""
488         NETWORK_SETTINGS["network"]= ""
489         NETWORK_SETTINGS["broadcast"]= ""
490         NETWORK_SETTINGS["dns1"]= ""
491         NETWORK_SETTINGS["dns2"]= ""
492
493     log.write("Successfully read and parsed node configuration file.\n" )
494
495     # if the mac wasn't specified, read it in from the system.
496     if NETWORK_SETTINGS["mac"] == "":
497         device= "eth0"
498         mac_addr= utils.get_mac_from_interface(device)
499
500         if mac_addr is None:
501             log.write( "Could not get mac address for device eth0.\n" )
502             return 0
503
504         NETWORK_SETTINGS["mac"]= string.upper(mac_addr)
505
506         log.write( "Got mac address %s for device %s\n" %
507                    (NETWORK_SETTINGS["mac"],device) )
508         
509
510     # now, if the conf file didn't contain a node id, post the mac address
511     # to plc to get the node_id value
512     if vars['NODE_ID'] is None or vars['NODE_ID'] == 0:
513         log.write( "Configuration file does not contain the node_id value.\n" )
514         log.write( "Querying PLC for node_id.\n" )
515
516         bs_request= BootServerRequest.BootServerRequest()
517         
518         postVars= {"mac_addr" : NETWORK_SETTINGS["mac"]}
519         result= bs_request.DownloadFile( "%s/getnodeid.php" %
520                                          SUPPORT_FILE_DIR,
521                                          None, postVars, 1, 1,
522                                          "/tmp/node_id")
523         if result == 0:
524             log.write( "Unable to make request to get node_id.\n" )
525             return 0
526
527         try:
528             node_id_file= file("/tmp/node_id","r")
529             node_id= string.strip(node_id_file.read())
530             node_id_file.close()
531         except IOError:
532             log.write( "Unable to read node_id from /tmp/node_id\n" )
533             return 0
534
535         try:
536             node_id= int(string.strip(node_id))
537         except ValueError:
538             log.write( "Got node_id from PLC, but not numeric: %s" % str(node_id) )
539             return 0
540
541         if node_id == -1:
542             log.write( "Got node_id, but it returned -1\n\n" )
543
544             log.write( "------------------------------------------------------\n" )
545             log.write( "This indicates that this node could not be identified\n" )
546             log.write( "by PLC. You will need to add the node to your site,\n" )
547             log.write( "and regenerate the network configuration file.\n" )
548             log.write( "See the Technical Contact guide for node setup\n" )
549             log.write( "procedures.\n\n" )
550             log.write( "Boot process canceled until this is completed.\n" )
551             log.write( "------------------------------------------------------\n" )
552             
553             cancel_boot_flag= "/tmp/CANCEL_BOOT"
554             # this will make the initial script stop requesting scripts from PLC
555             utils.sysexec( "touch %s" % cancel_boot_flag, log )
556
557             return 0
558
559         log.write( "Got node_id from PLC: %s\n" % str(node_id) )
560         vars['NODE_ID']= node_id
561
562
563
564     if vars['NODE_KEY'] is None or vars['NODE_KEY'] == "":
565         log.write( "Configuration file does not contain a node_key value.\n" )
566         log.write( "Using boot nonce instead.\n" )
567
568         # 3.x cds stored the file in /tmp/nonce in ascii form, so they
569         # can be read and used directly. 2.x cds stored in the same place
570         # but in binary form, so we need to convert it to ascii the same
571         # way the old boot scripts did so it matches whats in the db
572         # (php uses bin2hex, 
573         if BOOT_CD_VERSION[0] == 2:
574             read_mode= "rb"
575         else:
576             read_mode= "r"
577             
578         try:
579             nonce_file= file("/tmp/nonce",read_mode)
580             nonce= nonce_file.read()
581             nonce_file.close()
582         except IOError:
583             log.write( "Unable to read nonce from /tmp/nonce\n" )
584             return 0
585
586         if BOOT_CD_VERSION[0] == 2:
587             nonce= nonce.encode('hex')
588
589             # there is this nice bug in the php that currently accepts the
590             # nonce for the old scripts, in that if the nonce contains
591             # null chars (2.x cds sent as binary), then
592             # the nonce is truncated. so, do the same here, truncate the nonce
593             # at the first null ('00'). This could leave us with an empty string.
594             nonce_len= len(nonce)
595             for byte_index in range(0,nonce_len,2):
596                 if nonce[byte_index:byte_index+2] == '00':
597                     nonce= nonce[:byte_index]
598                     break
599         else:
600             nonce= string.strip(nonce)
601
602         log.write( "Read nonce, using as key.\n" )
603         vars['NODE_KEY']= nonce
604         
605         
606     # at this point, we've read the network configuration file.
607     # if we were setup using dhcp, get this system's current ip
608     # address and update the vars key ip, because it
609     # is needed for future api calls.
610
611     # at the same time, we can check to make sure that the hostname
612     # in the configuration file matches the ip address. if it fails
613     # notify the owners
614
615     hostname= NETWORK_SETTINGS['hostname'] + "." + \
616               NETWORK_SETTINGS['domainname']
617
618     # set to 0 if any part of the hostname resolution check fails
619     hostname_resolve_ok= 1
620
621     # set to 0 if the above fails, and, we are using dhcp in which
622     # case we don't know the ip of this machine (without having to
623     # parse ifconfig or something). In that case, we won't be able
624     # to make api calls, so printing a message to the screen will
625     # have to suffice.
626     can_make_api_call= 1
627
628     log.write( "Checking that hostname %s resolves\n" % hostname )
629
630     # try a regular dns lookup first
631     try:
632         resolved_node_ip= socket.gethostbyname(hostname)
633     except socket.gaierror, e:
634         hostname_resolve_ok= 0
635         
636
637     if NETWORK_SETTINGS['method'] == "dhcp":
638         if hostname_resolve_ok:
639             NETWORK_SETTINGS['ip']= resolved_node_ip
640             node_ip= resolved_node_ip
641         else:
642             can_make_api_call= 0
643     else:
644         node_ip= NETWORK_SETTINGS['ip']
645
646     # make sure the dns lookup matches what the configuration file says
647     if hostname_resolve_ok:
648         if node_ip != resolved_node_ip:
649             log.write( "Hostname %s does not resolve to %s, but %s:\n" % \
650                        (hostname,node_ip,resolved_node_ip) )
651             hostname_resolve_ok= 0
652         else:
653             log.write( "Hostname %s correctly resolves to %s:\n" %
654                        (hostname,node_ip) )
655
656         
657     vars["NETWORK_SETTINGS"]= NETWORK_SETTINGS
658
659     if not hostname_resolve_ok:
660         log.write( "Hostname does not resolve correctly, will not continue.\n" )
661
662         StartDebug.Run( vars, log )
663
664         if can_make_api_call:
665             log.write( "Notifying contacts of problem.\n" )
666
667             vars['BOOT_STATE']= 'dbg'
668             vars['STATE_CHANGE_NOTIFY']= 1
669             vars['STATE_CHANGE_NOTIFY_MESSAGE']= \
670                                      notify_messages.MSG_HOSTNAME_NOT_RESOLVE
671             
672             UpdateBootStateWithPLC.Run( vars, log )
673                     
674         log.write( "\n\n" )
675         log.write( "The hostname and/or ip in the network configuration\n" )
676         log.write( "file do not resolve and match.\n" )
677         log.write( "Please make sure the hostname set in the network\n" )
678         log.write( "configuration file resolves to the ip also specified\n" )
679         log.write( "there.\n\n" )
680         log.write( "Debug mode is being started on this cd. When the above\n" )
681         log.write( "is corrected, reboot the machine to try again.\n" )
682         
683         raise BootManagerException, \
684               "Configured node hostname does not resolve."
685     
686     return 1