source: trunk/pxeconfig.in @ 138

Last change on this file since 138 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
Line 
1#!@PYTHON@
2#
3# set ts=4, sw=4
4#
5# Author: Bas van der Vlies <basv@sara.nl>
6# Date  : 16 February 2002
7#
8# Tester: Walter de Jong <walter@sara.nl>
9#
10# SVN info
11#  $Id: pxeconfig.in 137 2009-04-15 12:12:38Z bas $
12#
13# Copyright (C) 2002
14#
15# This file is part of the pxeconfig utils
16#
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.
21#
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.
26#
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#
31"""
32Usage: pxeconfig [-f,--filename <name>] <hosts>
33
34Specifying hostnames:
35   To specify a range use the [] to indicate a range,
36   a couple of examples herebelow.
37
38   The first five nodes of rack 16
39          - gb-r16n[1-5]
40
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]
43
44   The first five nodes de in rack 16 with padding enabled
45          - gb-r[16]n[01-5]
46
47The ranges ([]) are not only limited to numbers, letters can also be used.
48
49With this program you can configure which PXE configuration file a node
50will use when it boots.
51
52See following link for usage and examples:
53 - https://subtrac.sara.nl/oss/pxeconfig/wiki/PxeUsage
54"""
55
56import string
57import sys
58import os
59import glob
60import getopt
61import socket
62import ConfigParser
63import re
64
65# import from the sara_python_modules
66from sara import AdvancedParser
67
68# Constants
69#
70PXE_CONF_DIR = '/tftpboot/pxelinux.cfg'
71NETWORK      = 'network'
72START        = 'start'
73END          = 'end'
74VERSION      = '3.0.0'
75
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
84def ReadConfig(file):
85        """
86        Parse the config file
87        """
88        if not os.path.isfile(file):
89                error = 'File %s does not exist' %file
90                raise PxeConfig, error
91
92        config = ConfigParser.RawConfigParser()
93        try:
94                config.read(file)
95        except ConfigParser.MissingSectionHeaderError,detail:
96                raise PxeConfig, detail
97
98        # Not yet uses
99        #
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)
105
106        stanza = config.defaults()
107        return stanza
108
109def select_pxe_configfile():
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
124
125        files = glob.glob('default.*')
126        if not files:
127                error =  'There are no pxe config files starting with: default.'
128                raise PxeConfig, error
129
130        if default_file:
131                files.remove(default_file)
132
133        # sort the files
134        #
135        files.sort()
136 
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
142
143        while 1:
144                index = raw_input('Select a number: ')
145                try:
146                        index = int(index)
147                except ValueError:
148                        index = len(files) + 1
149
150                # Is the user smart enough to select
151                # the right value??
152                #
153                if 0 < index <= len(files):
154                        break
155
156        return files[index-1]
157
158def manage_links(haddr, options):
159        """
160        Create the links in the PXE_CONF_DIR,
161        list : A list containing: network hex address, pxe config file,
162           start number, end number
163        """
164        if options.VERBOSE:
165                print 'manage_links(%s)' %(haddr)
166       
167        os.chdir(PXE_CONF_DIR)
168        pxe_filename = options.filename
169       
170        if options.REMOVE:
171                if options.DEBUG or options.DRY_RUN or options.VERBOSE:
172                        print 'removing %s/%s' %(PXE_CONF_DIR, haddr)
173
174                if os.path.exists(haddr) and not options.DRY_RUN:
175                        os.unlink(haddr)
176
177        else:
178                if options.DEBUG or options.DRY_RUN or options.VERBOSE:
179                        print 'linking %s to %s' %(haddr, pxe_filename)
180
181                if not options.DRY_RUN:
182                        if os.path.exists(haddr):
183                                os.unlink(haddr)
184                        os.symlink(pxe_filename, haddr)
185
186def net_2_hex(net, options):
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        """
191        if options.DEBUG:
192                str = 'net_2_hex : %s' %(net)
193                print str
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
199
200        # Check if we have valid network values
201        r = ''
202        for i in d:
203                r = '%s%02X' %(r, int(i))
204
205        if options.DEBUG:
206                print 'C-network converted to hex: ', r
207
208        return r
209
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
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
245        p.add_option('-d', '--debug',
246                action = 'store_true',
247                dest   = 'DEBUG',
248                help   = 'Toggle debug mode (default : False)'
249        )
250
251        p.add_option('-f', '--filename',
252                action = 'store',
253                dest   = 'filename',
254                help   = 'Specifies which PXE filename must be use'
255        )
256
257        p.add_option('-n', '--dry-run',
258                action = 'store_true',
259                dest   = 'DRY_RUN',
260                help   = 'Do not execute any command'
261        )
262
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
269        p.add_option('-v', '--verbose',
270                action = 'store_true',
271                dest   = 'VERBOSE',
272                help   = 'Make the program more verbose (default: False)'
273        )
274
275        p.add_option('-V', '--version',
276                action = 'store_true',
277                dest   = 'VERSION',
278                help   = 'Print the program version number and exit'
279        )
280
281def parser(argv, settings):
282        """
283        Make use of sara advance parser module. It can handle regex in hostnames
284        """
285        parser = AdvancedParser.AdvancedParser(usage=__doc__)
286        add_options(parser)
287
288        options, args = parser.parse_args()
289
290        if not args:
291                print __doc__
292                sys.exit(0)
293       
294        if options.VERSION:
295                print VERSION
296                sys.exit(0)
297
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
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)
310                                raise PxeConfig, error
311        else:
312                options.filename = select_pxe_configfile()
313
314        if options.DEBUG:
315                print args, options
316
317        hosts_2_hex(args, options)
318
319
320def main():
321        # A dictionary holding the boot info
322        #
323        global PXE_CONF_DIR
324       
325        configfile = '@pxeconfig_conf@'
326        settings = ReadConfig(configfile)
327       
328        try:
329                PXE_CONF_DIR = settings['pxe_config_dir']
330
331        except KeyError:
332                pass
333
334        PXE_CONF_DIR = os.path.realpath(PXE_CONF_DIR)
335        if not os.path.isdir(PXE_CONF_DIR):
336                error =  'pxeconfig directory: %s does not exists' %(PXE_CONF_DIR)
337                raise PxeConfig, error
338
339        parser(sys.argv, settings)
340
341       
342if __name__ == '__main__':
343        try:
344                main()
345        except PxeConfig, detail:
346                print detail
347                sys.exit(1)
Note: See TracBrowser for help on using the repository browser.