source: trunk/pxeconfig/pxeconfig @ 51

Last change on this file since 51 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
RevLine 
[2]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#
[29]8# SVN info
9#  $Id: pxeconfig 51 2004-12-13 15:23:50Z bas $
[2]10#
[14]11# Copyright (C) 2002
[6]12#
[14]13# This file is part of the pxeconfig utils
[6]14#
[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.
[6]19#
[14]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.
[6]24#
[14]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#
[2]29"""
[19]30Usage: pxeconfig
[49]31
[19]32 [-d|--directory <pxe_config_dir>]
[24]33 [-V|--version]
[19]34 [-n|--net <C-net> -s|--start <number> -e|--end <number> -f|--file <filename>]
[49]35 [-f|--file <filename>] [hostname(s)]
[10]36
[19]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:
[2]42  1) Network address (Class C-network address only)
[9]43  2) Starting number
[2]44  3) Ending number
[9]45  4) Which PXE config file to use
[2]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
[3]63import getopt
[47]64import socket
[2]65
66# DEBUG
67#
68DEBUG=0
69
70# Constants
71#
[4]72PXE_CONF_DIR='/tftpboot/pxelinux.cfg'
[19]73NETWORK='network'
74FILENAME='filename'
75START='start'
76END='end'
[47]77VERSION='0.5'
[2]78
[24]79SHORTOPT_LIST='hVd:n:s:e:f:'
[23]80LONGOPT_LIST=['help', 'version', 'directory=', 'net=', 'start=', 'end=', 'file=']
[19]81
82def select_pxe_configfile():
[2]83  """
[9]84  Let user choose which pxeconfig file to use.
[2]85  """
86
[4]87  os.chdir(PXE_CONF_DIR)
[2]88
[9]89  # Try to determine to which file the default symlink points, and
90  # if it exists, remove it from the list.
[2]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:
[16]114    index = raw_input('Select a number: ')
[2]115    try:
116      index = int(index)
117    except ValueError:
118      index = len(files) + 1
119
120    # Is the user smart enough to select
[9]121    # the right value??
[2]122    #
123    if 0 < index <= len(files): break
124
125  return files[index-1]
126
[19]127def create_links(dict):
[2]128  """
[4]129  Create the links in the PXE_CONF_DIR,
[9]130    list : A list containing: network hex address, pxe config file,
[2]131           start number, end number
132  """
[4]133  os.chdir(PXE_CONF_DIR)
[19]134  naddr = dict[NETWORK]
135  pxe_filename = dict[FILENAME]
136  for i in range(dict[START], dict[END]+1):
[2]137    haddr = '%s%02X' %(naddr, i)
138    if DEBUG:
139      print 'linking %s to %s' %(haddr, pxe_filename)
[15]140
141    if os.path.exists(haddr):
142       os.unlink(haddr)
143
[2]144    os.symlink(pxe_filename, haddr)
145
146
[47]147def convert_network(net, prefix=''):
[2]148  """
[9]149  This function checks if the give network is a Class C-network and will
[2]150  convert the network address to a hex address if true.
151  """
152  d = string.split(net, '.')
153
154  if len(d) != 3:
[19]155    if prefix:
156      net = prefix + ' : ' + net
157     
158    print '%s is not a valid  C-class network address!!!' %net
[2]159    sys.exit(1)
160
[19]161
162  # Display right message for interactive/commandline
163  if prefix:
164    prefix = prefix + ' ' + net
165  else:
166    prefix = net
167
[2]168  # Check if we have valid network values
169  r = ''
170  for i in d:
[19]171    i = check_number(i, prefix)
[2]172    r = '%s%02X' %(r,i)
173
174  if DEBUG:
175    print r
176
177  return r
178
[19]179def check_number(number, prefix=''):
[2]180  """
181  This functions checks if the input is between 0 < number < 255:
182     number : is a string
[19]183     prefix ; a string that must be displayed if an error occurs
[2]184  """
185  try:
186    n = int(number)
187  except ValueError, detail:
[19]188    print prefix,detail
[2]189    sys.exit(1)
190
191  if 0 <= n <= 255:
192    return n
193  else:
[19]194
195    if prefix:
196      number = prefix +' : ' + number
197
[2]198    print '%s is not a valid number, must be between 0 and 255' %number
199    sys.exit(1)
200
[19]201def interactive(binfo):
[2]202
203  print __doc__
204
[9]205  network = raw_input('Give network address (xxx.xxx.xxx): ') 
[47]206  naddr = convert_network(network)
[2]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
[19]214  pxe_filename = select_pxe_configfile()
[2]215
[19]216  binfo[NETWORK] = naddr
217  binfo[START] = int(start)
218  binfo[END] = int(end)
219  binfo[FILENAME] = pxe_filename
[2]220
[19]221  if DEBUG:
222    print network, binfo
[2]223
[19]224def check_cmd_line(binfo):
225  if len(binfo.keys()) != 4:
226    print __doc__
[20]227    print 'Not enough arguments to create the links!!'
[19]228    sys.exit(1)
[6]229
[19]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):
[3]237  """
[47]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.
[3]243  """
[4]244  global PXE_CONF_DIR
[19]245
[3]246  try:
247    opts, args = getopt.getopt(argv[1:], SHORTOPT_LIST, LONGOPT_LIST)
248  except getopt.error, detail:
[20]249    print __doc__
[3]250    print detail
251    sys.exit(1)
252
[19]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)
[3]262
[19]263    elif opt in ['-n', '--net']:
264      network = value
[47]265      binfo[NETWORK] = convert_network(value, opt)
[4]266
[19]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
[24]276    elif opt in ['-V', '--version']:
[23]277      print VERSION
278      sys.exit(0)
279
[20]280    elif opt in ['-h', '--help']:
281      print __doc__
282      sys.exit(0)
[19]283
[51]284  if args:
285        return args
[20]286
[47]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
[2]304def main():
[19]305  # A dictionary holding the boot info
306  #
307  bootinfo = {}
[2]308
[47]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)
[19]319  else:
[47]320        if bootinfo:   
321                check_cmd_line(bootinfo)
322        else:
323                interactive(bootinfo)
324        create_links(bootinfo)
[19]325
[2]326if __name__ == '__main__':
327  main()
Note: See TracBrowser for help on using the repository browser.