source: trunk/src/pxeconfig.py @ 166

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

We do nat have to generate pxeconfig.py anymore it is now a module

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