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