source: trunk/pxeconfig/pxeconfig @ 52

Last change on this file since 52 was 51, checked in by bas, 19 years ago

pxeconfig:

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