source: trunk/pxeconfig.in @ 137

Last change on this file since 137 was 137, checked in by bas, 15 years ago

debian/changelog,
pxeconfig.in:

  • fixed some spelling errors
  • Property keywords set to Id
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 7.5 KB
RevLine 
[78]1#!@PYTHON@
[2]2#
[104]3# set ts=4, sw=4
4#
[2]5# Author: Bas van der Vlies <basv@sara.nl>
6# Date  : 16 February 2002
7#
8# Tester: Walter de Jong <walter@sara.nl>
9#
[29]10# SVN info
11#  $Id: pxeconfig.in 137 2009-04-15 12:12:38Z bas $
[2]12#
[14]13# Copyright (C) 2002
[6]14#
[14]15# This file is part of the pxeconfig utils
[6]16#
[14]17# This program is free software; you can redistribute it and/or modify it
18# under the terms of the GNU General Public License as published by the
19# Free Software Foundation; either version 2, or (at your option) any
20# later version.
[6]21#
[14]22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25# GNU General Public License for more details.
[6]26#
[14]27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
30#
[2]31"""
[133]32Usage: pxeconfig [-f,--filename <name>] <hosts>
[49]33
[133]34Specifying hostnames:
35   To specify a range use the [] to indicate a range,
36   a couple of examples herebelow.
[10]37
[133]38   The first five nodes of rack 16
39          - gb-r16n[1-5]
[123]40
[133]41   The first five nodes and node 12 and 18 of rack 16 to 20
42      - gb-r[16-20]n[1-5,12,18]
[123]43
[137]44   The first five nodes de in rack 16 with padding enabled
[133]45          - gb-r[16]n[01-5]
[118]46
[133]47The ranges ([]) are not only limited to numbers, letters can also be used.
[123]48
[19]49With this program you can configure which PXE configuration file a node
[133]50will use when it boots.
[19]51
[126]52See following link for usage and examples:
53 - https://subtrac.sara.nl/oss/pxeconfig/wiki/PxeUsage
[2]54"""
55
56import string
57import sys
58import os
59import glob
[3]60import getopt
[47]61import socket
[74]62import ConfigParser
[123]63import re
[2]64
[132]65# import from the sara_python_modules
66from sara import AdvancedParser
67
[2]68# Constants
69#
[133]70PXE_CONF_DIR = '/tftpboot/pxelinux.cfg'
71NETWORK      = 'network'
72START        = 'start'
73END          = 'end'
74VERSION      = '3.0.0'
[2]75
[119]76class PxeConfig(Exception):
77        def __init__(self, msg=''):
78                self.msg = msg
79                Exception.__init__(self, msg)
80
81        def __repr__(self):
82                return self.msg
83
[75]84def ReadConfig(file):
[74]85        """
86        Parse the config file
87        """
88        if not os.path.isfile(file):
[136]89                error = 'File %s does not exist' %file
90                raise PxeConfig, error
[74]91
[75]92        config = ConfigParser.RawConfigParser()
[74]93        try:
94                config.read(file)
95        except ConfigParser.MissingSectionHeaderError,detail:
[136]96                raise PxeConfig, detail
[74]97
[75]98        # Not yet uses
[74]99        #
[75]100        #projects = {}
101        #for section in config.sections():
102        #       projects[section] = {}
103        #       for option in  config.options(section):
104        #       projects[section][option] = config.get(section, option)
[74]105
[75]106        stanza = config.defaults()
107        return stanza
[74]108
[19]109def select_pxe_configfile():
[133]110        """
111        Let user choose which pxeconfig file to use.
112        """
113       
114        os.chdir(PXE_CONF_DIR)
115       
116        # Try to determine to which file the default symlink points, and
117        # if it exists, remove it from the list.
118        #
119        try:
120                default_file = os.readlink('default')
121        except OSError:
122                default_file = None
123        pass
[2]124
[133]125        files = glob.glob('default.*')
126        if not files:
[136]127                error =  'There are no pxe config files starting with: default.'
128                raise PxeConfig, error
[2]129
[133]130        if default_file:
131                files.remove(default_file)
[2]132
[133]133        # sort the files
134        #
135        files.sort()
[2]136 
[133]137        print 'Which pxe config file must we use: ?'
138        i = 1   
139        for file in files:
140                print "%d : %s" %(i,file)
141                i = i + 1
[2]142
[133]143        while 1:
144                index = raw_input('Select a number: ')
145                try:
146                        index = int(index)
147                except ValueError:
148                        index = len(files) + 1
[2]149
[133]150                # Is the user smart enough to select
151                # the right value??
152                #
153                if 0 < index <= len(files):
154                        break
[2]155
[133]156        return files[index-1]
[2]157
[135]158def manage_links(haddr, options):
[126]159        """
160        Create the links in the PXE_CONF_DIR,
161        list : A list containing: network hex address, pxe config file,
[2]162           start number, end number
[126]163        """
[133]164        if options.VERBOSE:
[135]165                print 'manage_links(%s)' %(haddr)
[126]166       
167        os.chdir(PXE_CONF_DIR)
[133]168        pxe_filename = options.filename
[126]169       
[135]170        if options.REMOVE:
[136]171                if options.DEBUG or options.DRY_RUN or options.VERBOSE:
[135]172                        print 'removing %s/%s' %(PXE_CONF_DIR, haddr)
[125]173
[135]174                if os.path.exists(haddr) and not options.DRY_RUN:
175                        os.unlink(haddr)
[122]176
[135]177        else:
[136]178                if options.DEBUG or options.DRY_RUN or options.VERBOSE:
[135]179                        print 'linking %s to %s' %(haddr, pxe_filename)
[15]180
[135]181                if not options.DRY_RUN:
182                        if os.path.exists(haddr):
183                                os.unlink(haddr)
184                        os.symlink(pxe_filename, haddr)
[15]185
[133]186def net_2_hex(net, options):
[119]187        """
188        This function checks if the give network is a Class C-network and will
189        convert the network address to a hex address if true.
190        """
[136]191        if options.DEBUG:
[133]192                str = 'net_2_hex : %s' %(net)
193                print str
[119]194       
195        d = string.split(net, '.')
196        if len(d) != 3:
197                error = '%s is not a valid  C-class network address' %(net)
198                raise PxeConfig, error
[2]199
[119]200        # Check if we have valid network values
201        r = ''
202        for i in d:
[133]203                r = '%s%02X' %(r, int(i))
[2]204
[133]205        if options.DEBUG:
206                print 'C-network converted to hex: ', r
[19]207
[119]208        return r
[19]209
[136]210def hosts_2_hex(hosts, options):
211        """
212        Convert hostname(s) to a net address that can be handled by manage_links function
213        """
214        if options.DEBUG:
215                str = 'host_2_hex: %s' %hosts
216                print str
217
218        for host in hosts:
219                try:
220                        addr = socket.gethostbyname(host)
221                except socket.error,detail:
222                        error =  '%s not an valid hostname: %s' %(host,detail)
223                        raise PxeConfig, error
224
225                net = string.splitfields(addr, '.')
226                cnet = string.joinfields(net[0:3], '.')
227
228                haddr = '%s%02X' %(net_2_hex(cnet, options), int(net[3]))
229
230                manage_links(haddr, options)
231               
232
[132]233def add_options(p):
234        """
235        add the default options
236        """
237        p.set_defaults(
238                DEBUG   = False,
239                VERBOSE = False,
240                DRY_RUN = False,
241                REMOVE  = False,
242                VERSION  = False,
243        )
244
[136]245        p.add_option('-d', '--debug',
[133]246                action = 'store_true',
[136]247                dest   = 'DEBUG',
248                help   = 'Toggle debug mode (default : False)'
[133]249        )
250
[132]251        p.add_option('-f', '--filename',
252                action = 'store',
253                dest   = 'filename',
254                help   = 'Specifies which PXE filename must be use'
255        )
256
[136]257        p.add_option('-n', '--dry-run',
258                action = 'store_true',
259                dest   = 'DRY_RUN',
260                help   = 'Do not execute any command'
261        )
262
[132]263        p.add_option('-r', '--remove',
264                action = 'store_true',
265                dest   = 'REMOVE',
266                help   = 'Removes the PXE filename for a host(s)'
267        )
268
[133]269        p.add_option('-v', '--verbose',
270                action = 'store_true',
271                dest   = 'VERBOSE',
[136]272                help   = 'Make the program more verbose (default: False)'
[133]273        )
274
[132]275        p.add_option('-V', '--version',
276                action = 'store_true',
277                dest   = 'VERSION',
[133]278                help   = 'Print the program version number and exit'
[132]279        )
280
[136]281def parser(argv, settings):
[132]282        """
[133]283        Make use of sara advance parser module. It can handle regex in hostnames
[132]284        """
[133]285        parser = AdvancedParser.AdvancedParser(usage=__doc__)
[132]286        add_options(parser)
287
[133]288        options, args = parser.parse_args()
[135]289
290        if not args:
291                print __doc__
292                sys.exit(0)
[123]293       
[133]294        if options.VERSION:
295                print VERSION
296                sys.exit(0)
[3]297
[136]298        # debug can be specified by the command line or options file
299        #
300        if not options.DEBUG:
301                try:
302                        if settings['debug']:
303                                options.DEBUG = int(settings['debug'])
304                except KeyError:
305                        pass
306
[133]307        if options.filename:
308                if not os.path.isfile(os.path.join(PXE_CONF_DIR, options.filename)):
309                                error =  '%s: Filename does not exists' %(options.filename)
[136]310                                raise PxeConfig, error
[133]311        else:
312                options.filename = select_pxe_configfile()
[105]313
[133]314        if options.DEBUG:
315                print args, options
[123]316
[133]317        hosts_2_hex(args, options)
[126]318
[125]319
[2]320def main():
[104]321        # A dictionary holding the boot info
322        #
[117]323        global PXE_CONF_DIR
[104]324       
325        configfile = '@pxeconfig_conf@'
326        settings = ReadConfig(configfile)
327       
328        try:
329                PXE_CONF_DIR = settings['pxe_config_dir']
[117]330
[104]331        except KeyError:
332                pass
[105]333
[118]334        PXE_CONF_DIR = os.path.realpath(PXE_CONF_DIR)
[117]335        if not os.path.isdir(PXE_CONF_DIR):
[120]336                error =  'pxeconfig directory: %s does not exists' %(PXE_CONF_DIR)
337                raise PxeConfig, error
[117]338
[136]339        parser(sys.argv, settings)
340
[120]341       
342if __name__ == '__main__':
[119]343        try:
[133]344                main()
[119]345        except PxeConfig, detail:
346                print detail
347                sys.exit(1)
Note: See TracBrowser for help on using the repository browser.