source: trunk/pxeconfig/pxeconfig @ 47

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

pxeconfig:

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