source: trunk/pxeconfig/pxeconfig @ 54

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

pxeconfig:

Added --debug and --remover option
  • Property keywords set to Id
  • Property svn:keywords set to Id
File size: 7.9 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 53 2005-09-19 13:55:56Z 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>]
[53]33 [-f|--file <filename>] [hostname(s)]
34 [-n|--net <C-net> -s|--start <number> -e|--end <number> -f|--file <filename>]
35 [-r|--remove]
[24]36 [-V|--version]
[10]37
[19]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:
[2]43  1) Network address (Class C-network address only)
[9]44  2) Starting number
[2]45  3) Ending number
[9]46  4) Which PXE config file to use
[2]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
[3]64import getopt
[47]65import socket
[2]66
67# DEBUG
68#
69DEBUG=0
70
71# Constants
72#
[4]73PXE_CONF_DIR='/tftpboot/pxelinux.cfg'
[19]74NETWORK='network'
75FILENAME='filename'
76START='start'
77END='end'
[53]78VERSION='0.6'
79REMOVE='remove'
[2]80
[53]81SHORTOPT_LIST='hVd:n:s:e:f:r'
82LONGOPT_LIST=['help', 'version', 'directory=', 'net=', 'start=', 'end=', 'file=', 'remove', 'debug']
[19]83
84def select_pxe_configfile():
[2]85  """
[9]86  Let user choose which pxeconfig file to use.
[2]87  """
88
[4]89  os.chdir(PXE_CONF_DIR)
[2]90
[9]91  # Try to determine to which file the default symlink points, and
92  # if it exists, remove it from the list.
[2]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:
[16]116    index = raw_input('Select a number: ')
[2]117    try:
118      index = int(index)
119    except ValueError:
120      index = len(files) + 1
121
122    # Is the user smart enough to select
[9]123    # the right value??
[2]124    #
125    if 0 < index <= len(files): break
126
127  return files[index-1]
128
[53]129def manage_links(dict):
[2]130  """
[4]131  Create the links in the PXE_CONF_DIR,
[9]132    list : A list containing: network hex address, pxe config file,
[2]133           start number, end number
134  """
[4]135  os.chdir(PXE_CONF_DIR)
[19]136  naddr = dict[NETWORK]
137  pxe_filename = dict[FILENAME]
138  for i in range(dict[START], dict[END]+1):
[2]139    haddr = '%s%02X' %(naddr, i)
[15]140
[53]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)
[15]152
[47]153def convert_network(net, prefix=''):
[2]154  """
[9]155  This function checks if the give network is a Class C-network and will
[2]156  convert the network address to a hex address if true.
157  """
158  d = string.split(net, '.')
159
160  if len(d) != 3:
[19]161    if prefix:
162      net = prefix + ' : ' + net
163     
164    print '%s is not a valid  C-class network address!!!' %net
[2]165    sys.exit(1)
166
[19]167
168  # Display right message for interactive/commandline
169  if prefix:
170    prefix = prefix + ' ' + net
171  else:
172    prefix = net
173
[2]174  # Check if we have valid network values
175  r = ''
176  for i in d:
[19]177    i = check_number(i, prefix)
[2]178    r = '%s%02X' %(r,i)
179
180  if DEBUG:
181    print r
182
183  return r
184
[19]185def check_number(number, prefix=''):
[2]186  """
187  This functions checks if the input is between 0 < number < 255:
188     number : is a string
[19]189     prefix ; a string that must be displayed if an error occurs
[2]190  """
191  try:
192    n = int(number)
193  except ValueError, detail:
[19]194    print prefix,detail
[2]195    sys.exit(1)
196
197  if 0 <= n <= 255:
198    return n
199  else:
[19]200
201    if prefix:
202      number = prefix +' : ' + number
203
[2]204    print '%s is not a valid number, must be between 0 and 255' %number
205    sys.exit(1)
206
[19]207def interactive(binfo):
[2]208
209  print __doc__
210
[9]211  network = raw_input('Give network address (xxx.xxx.xxx): ') 
[47]212  naddr = convert_network(network)
[2]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
[19]220  pxe_filename = select_pxe_configfile()
[2]221
[19]222  binfo[NETWORK] = naddr
223  binfo[START] = int(start)
224  binfo[END] = int(end)
225  binfo[FILENAME] = pxe_filename
[2]226
[19]227  if DEBUG:
228    print network, binfo
[2]229
[19]230def check_cmd_line(binfo):
231  if len(binfo.keys()) != 4:
232    print __doc__
[20]233    print 'Not enough arguments to create the links!!'
[19]234    sys.exit(1)
[6]235
[19]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):
[3]243  """
[47]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.
[3]249  """
[4]250  global PXE_CONF_DIR
[53]251  global DEBUG
[19]252
[3]253  try:
254    opts, args = getopt.getopt(argv[1:], SHORTOPT_LIST, LONGOPT_LIST)
255  except getopt.error, detail:
[20]256    print __doc__
[3]257    print detail
258    sys.exit(1)
259
[19]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)
[3]269
[19]270    elif opt in ['-n', '--net']:
271      network = value
[47]272      binfo[NETWORK] = convert_network(value, opt)
[4]273
[19]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
[24]283    elif opt in ['-V', '--version']:
[23]284      print VERSION
285      sys.exit(0)
286
[53]287    elif opt in ['-r', '--remove']:
288      binfo[REMOVE] = 1
289
290    elif opt in ['--debug']:
291      DEBUG = 1
292
[20]293    elif opt in ['-h', '--help']:
294      print __doc__
295      sys.exit(0)
[19]296
[51]297  if args:
298        return args
[20]299
[47]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])
[53]314                manage_links(binfo)
[47]315
316
[2]317def main():
[19]318  # A dictionary holding the boot info
319  #
320  bootinfo = {}
[53]321  bootinfo[REMOVE] = 0
[2]322
[47]323  hostnames = check_args(sys.argv, bootinfo)
324
[53]325  if bootinfo[REMOVE]:
326     bootinfo[FILENAME] = 'remove_boot_file'
[47]327
[53]328
[47]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):
[53]334              bootinfo[FILENAME] = select_pxe_configfile()
[47]335        hosts_links(hostnames,bootinfo)
[19]336  else:
[47]337        if bootinfo:   
338                check_cmd_line(bootinfo)
339        else:
340                interactive(bootinfo)
[53]341        manage_links(bootinfo)
[19]342
[2]343if __name__ == '__main__':
344  main()
Note: See TracBrowser for help on using the repository browser.