source: trunk/pxeconfig/pxeconfig @ 54

Last change on this file since 54 was 53, checked in by bas, 17 years ago

pxeconfig:

Added --debug and --remover option
  • Property keywords set to Id
  • Property svn:keywords set to Id
File size: 7.9 KB
Line 
1#!/usr/bin/env python
2#
3# Author: Bas van der Vlies <basv@sara.nl>
4# Date  : 16 February 2002
5#
6# Tester: Walter de Jong <walter@sara.nl>
7#
8# SVN info
9#  $Id: pxeconfig 53 2005-09-19 13:55:56Z bas $
10#
11# Copyright (C) 2002
12#
13# This file is part of the pxeconfig utils
14#
15# This program is free software; you can redistribute it and/or modify it
16# under the terms of the GNU General Public License as published by the
17# Free Software Foundation; either version 2, or (at your option) any
18# later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program; if not, write to the Free Software
27# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
28#
29"""
30Usage: pxeconfig
31
32 [-d|--directory <pxe_config_dir>]
33 [-f|--file <filename>] [hostname(s)]
34 [-n|--net <C-net> -s|--start <number> -e|--end <number> -f|--file <filename>]
35 [-r|--remove]
36 [-V|--version]
37
38With this program you can configure which PXE configuration file a node
39will use when it boots. The program can be started interactivly or via
40command line options.
41
42When this program is started interactive it will ask the following questions:
43  1) Network address (Class C-network address only)
44  2) Starting number
45  3) Ending number
46  4) Which PXE config file to use
47
48For example, if the answers are:
49  1) 10.168.44
50  2) 2
51  3) 4
52  4) default.node_install
53
54Then the result is that is create symbolic links in /tftpboot/pxelinux.cfg:
55  0AA82C02 ----> default.node_install
56  0AA82C03 ----> default.node_install
57  0AA82C04 ----> default.node_install
58"""
59
60import string
61import sys
62import os
63import glob
64import getopt
65import socket
66
67# DEBUG
68#
69DEBUG=0
70
71# Constants
72#
73PXE_CONF_DIR='/tftpboot/pxelinux.cfg'
74NETWORK='network'
75FILENAME='filename'
76START='start'
77END='end'
78VERSION='0.6'
79REMOVE='remove'
80
81SHORTOPT_LIST='hVd:n:s:e:f:r'
82LONGOPT_LIST=['help', 'version', 'directory=', 'net=', 'start=', 'end=', 'file=', 'remove', 'debug']
83
84def select_pxe_configfile():
85  """
86  Let user choose which pxeconfig file to use.
87  """
88
89  os.chdir(PXE_CONF_DIR)
90
91  # Try to determine to which file the default symlink points, and
92  # if it exists, remove it from the list.
93  #
94  try:
95    default_file = os.readlink('default')
96  except OSError:
97    default_file = None
98    pass
99
100  files = glob.glob('default.*')
101  if not files:
102    print 'There are no pxe config files starting with: default.'
103    sys.exit(1)
104
105  if default_file:
106    files.remove(default_file)
107 
108
109  print 'Which pxe config file must we use: ?' 
110  i = 1   
111  for file in files:
112    print "%d : %s" %(i,file)
113    i = i +1
114
115  while 1:
116    index = raw_input('Select a number: ')
117    try:
118      index = int(index)
119    except ValueError:
120      index = len(files) + 1
121
122    # Is the user smart enough to select
123    # the right value??
124    #
125    if 0 < index <= len(files): break
126
127  return files[index-1]
128
129def manage_links(dict):
130  """
131  Create the links in the PXE_CONF_DIR,
132    list : A list containing: network hex address, pxe config file,
133           start number, end number
134  """
135  os.chdir(PXE_CONF_DIR)
136  naddr = dict[NETWORK]
137  pxe_filename = dict[FILENAME]
138  for i in range(dict[START], dict[END]+1):
139    haddr = '%s%02X' %(naddr, i)
140
141    if dict[REMOVE]:
142       if DEBUG:
143          print 'removing %s/%s' %(PXE_CONF_DIR, haddr)
144       if os.path.exists(haddr):
145          os.unlink(haddr)
146    else:
147       if DEBUG:
148          print 'linking %s to %s' %(haddr, pxe_filename)
149       if os.path.exists(haddr):
150          os.unlink(haddr)
151       os.symlink(pxe_filename, haddr)
152
153def convert_network(net, prefix=''):
154  """
155  This function checks if the give network is a Class C-network and will
156  convert the network address to a hex address if true.
157  """
158  d = string.split(net, '.')
159
160  if len(d) != 3:
161    if prefix:
162      net = prefix + ' : ' + net
163     
164    print '%s is not a valid  C-class network address!!!' %net
165    sys.exit(1)
166
167
168  # Display right message for interactive/commandline
169  if prefix:
170    prefix = prefix + ' ' + net
171  else:
172    prefix = net
173
174  # Check if we have valid network values
175  r = ''
176  for i in d:
177    i = check_number(i, prefix)
178    r = '%s%02X' %(r,i)
179
180  if DEBUG:
181    print r
182
183  return r
184
185def check_number(number, prefix=''):
186  """
187  This functions checks if the input is between 0 < number < 255:
188     number : is a string
189     prefix ; a string that must be displayed if an error occurs
190  """
191  try:
192    n = int(number)
193  except ValueError, detail:
194    print prefix,detail
195    sys.exit(1)
196
197  if 0 <= n <= 255:
198    return n
199  else:
200
201    if prefix:
202      number = prefix +' : ' + number
203
204    print '%s is not a valid number, must be between 0 and 255' %number
205    sys.exit(1)
206
207def interactive(binfo):
208
209  print __doc__
210
211  network = raw_input('Give network address (xxx.xxx.xxx): ') 
212  naddr = convert_network(network)
213
214  start = raw_input('Starting number: ') 
215  start = check_number(start)
216
217  end = raw_input('Ending number: ') 
218  end = check_number(end)
219
220  pxe_filename = select_pxe_configfile()
221
222  binfo[NETWORK] = naddr
223  binfo[START] = int(start)
224  binfo[END] = int(end)
225  binfo[FILENAME] = pxe_filename
226
227  if DEBUG:
228    print network, binfo
229
230def check_cmd_line(binfo):
231  if len(binfo.keys()) != 4:
232    print __doc__
233    print 'Not enough arguments to create the links!!'
234    sys.exit(1)
235
236  # check_filename
237  #
238  if not os.path.isfile(os.path.join(PXE_CONF_DIR, binfo[FILENAME])):
239    print '%s: Filename does not exists' %binfo[FILENAME]
240    sys.exit(1)
241
242def check_args(argv, binfo):
243  """
244  This function parses the command line options and returns the rest as
245  an list of hostnames:
246    argv     : a list of command line options.
247    binfo    : returning a dict with the netinfo. if used non-interactively
248    hostnames: the rest of the command lines options that are not-parseble.
249  """
250  global PXE_CONF_DIR
251  global DEBUG
252
253  try:
254    opts, args = getopt.getopt(argv[1:], SHORTOPT_LIST, LONGOPT_LIST)
255  except getopt.error, detail:
256    print __doc__
257    print detail
258    sys.exit(1)
259
260  # Check given options
261  #
262  for opt,value in opts:
263    if opt in ['-d', '--directory']:
264      if os.path.isdir(value):
265        PXE_CONF_DIR = value
266      else:
267        print 'Directory %s does not exists\n' %value
268        sys.exit(1)
269
270    elif opt in ['-n', '--net']:
271      network = value
272      binfo[NETWORK] = convert_network(value, opt)
273
274    elif opt in ['-s', '--start']:
275      binfo[START] = check_number(value, opt)
276
277    elif opt in ['-e', '--end']:
278      binfo[END] = check_number(value, opt)
279
280    elif opt in ['-f', '--file']:
281      binfo[FILENAME] = value
282
283    elif opt in ['-V', '--version']:
284      print VERSION
285      sys.exit(0)
286
287    elif opt in ['-r', '--remove']:
288      binfo[REMOVE] = 1
289
290    elif opt in ['--debug']:
291      DEBUG = 1
292
293    elif opt in ['-h', '--help']:
294      print __doc__
295      sys.exit(0)
296
297  if args:
298        return args
299
300def hosts_links(hosts, binfo):
301        for host in hosts:
302                try:
303                        addr = socket.gethostbyname(host)
304                except socket.error,detail:
305                        print '%s not an valid hostname: %s' %(host,detail)
306                        sys.exit(1)
307                       
308                net = string.splitfields(addr, '.')
309                cnet = string.joinfields(net[0:3], '.')
310
311                binfo[NETWORK] = convert_network(cnet)
312                binfo[START] = int(net[3])
313                binfo[END] =  int(net[3])
314                manage_links(binfo)
315
316
317def main():
318  # A dictionary holding the boot info
319  #
320  bootinfo = {}
321  bootinfo[REMOVE] = 0
322
323  hostnames = check_args(sys.argv, bootinfo)
324
325  if bootinfo[REMOVE]:
326     bootinfo[FILENAME] = 'remove_boot_file'
327
328
329  # If we supplied args then make links for the supplied hosts
330  # else make links for class C-networks
331  #
332  if hostnames:
333        if not bootinfo.has_key(FILENAME):
334              bootinfo[FILENAME] = select_pxe_configfile()
335        hosts_links(hostnames,bootinfo)
336  else:
337        if bootinfo:   
338                check_cmd_line(bootinfo)
339        else:
340                interactive(bootinfo)
341        manage_links(bootinfo)
342
343if __name__ == '__main__':
344  main()
Note: See TracBrowser for help on using the repository browser.