source: trunk/pxeconfig.in @ 133

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

New Version that use the Advance Parser option from Dennis Stam

  • Property keywords set to Id
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 7.2 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 133 2009-04-14 13:58:42Z 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 a 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                print 'File %s does not exist' %file
90                sys.exit(1)
91
92        config = ConfigParser.RawConfigParser()
93        try:
94                config.read(file)
95        except ConfigParser.MissingSectionHeaderError,detail:
96                print detail
97                sys.exit(1)
98
99        # Not yet uses
100        #
101        #projects = {}
102        #for section in config.sections():
103        #       projects[section] = {}
104        #       for option in  config.options(section):
105        #       projects[section][option] = config.get(section, option)
106
107        stanza = config.defaults()
108        return stanza
109
110def select_pxe_configfile():
111        """
112        Let user choose which pxeconfig file to use.
113        """
114       
115        os.chdir(PXE_CONF_DIR)
116       
117        # Try to determine to which file the default symlink points, and
118        # if it exists, remove it from the list.
119        #
120        try:
121                default_file = os.readlink('default')
122        except OSError:
123                default_file = None
124        pass
125
126        files = glob.glob('default.*')
127        if not files:
128                print 'There are no pxe config files starting with: default.'
129                sys.exit(1)
130
131        if default_file:
132                files.remove(default_file)
133
134        # sort the files
135        #
136        files.sort()
137 
138        print 'Which pxe config file must we use: ?'
139        i = 1   
140        for file in files:
141                print "%d : %s" %(i,file)
142                i = i + 1
143
144        while 1:
145                index = raw_input('Select a number: ')
146                try:
147                        index = int(index)
148                except ValueError:
149                        index = len(files) + 1
150
151                # Is the user smart enough to select
152                # the right value??
153                #
154                if 0 < index <= len(files):
155                        break
156
157        return files[index-1]
158
159def manage_links(dict, options):
160        """
161        Create the links in the PXE_CONF_DIR,
162        list : A list containing: network hex address, pxe config file,
163           start number, end number
164        """
165        if options.VERBOSE:
166                print 'manage_links()'
167       
168        os.chdir(PXE_CONF_DIR)
169        naddr = dict[NETWORK]
170        pxe_filename = options.filename
171       
172        for i in range(dict[START], dict[END]+1):
173                haddr = '%s%02X' %(naddr, i)
174       
175                if options.REMOVE:
176                        if options.DEBUG or options.DRY_RUN:
177                                print 'removing %s/%s' %(PXE_CONF_DIR, haddr)
178
179                        if os.path.exists(haddr) and not options.DRY_RUN:
180                                os.unlink(haddr)
181
182                else:
183                        if options.DEBUG or options.DRY_RUN:
184                                print 'linking %s to %s' %(haddr, pxe_filename)
185
186                        if not options.DRY_RUN:
187                                if os.path.exists(haddr):
188                                        os.unlink(haddr)
189                                os.symlink(pxe_filename, haddr)
190
191def net_2_hex(net, options):
192        """
193        This function checks if the give network is a Class C-network and will
194        convert the network address to a hex address if true.
195        """
196        if options.VERBOSE:
197                str = 'net_2_hex : %s' %(net)
198                print str
199       
200        d = string.split(net, '.')
201        if len(d) != 3:
202                error = '%s is not a valid  C-class network address' %(net)
203                raise PxeConfig, error
204
205        # Check if we have valid network values
206        r = ''
207        for i in d:
208                r = '%s%02X' %(r, int(i))
209
210        if options.DEBUG:
211                print 'C-network converted to hex: ', r
212
213        return r
214
215def add_options(p):
216        """
217        add the default options
218        """
219        p.set_defaults(
220                DEBUG   = False,
221                VERBOSE = False,
222                DRY_RUN = False,
223                REMOVE  = False,
224                VERSION  = False,
225        )
226
227        p.add_option('-n', '--dry-run',
228                action = 'store_true',
229                dest   = 'DRY_RUN',
230                help   = 'Do not execute any command'
231        )
232
233        p.add_option('-f', '--filename',
234                action = 'store',
235                dest   = 'filename',
236                help   = 'Specifies which PXE filename must be use'
237        )
238
239        p.add_option('-r', '--remove',
240                action = 'store_true',
241                dest   = 'REMOVE',
242                help   = 'Removes the PXE filename for a host(s)'
243        )
244
245        p.add_option('-v', '--verbose',
246                action = 'store_true',
247                dest   = 'VERBOSE',
248                help   = 'Make the program more verbose'
249        )
250
251        p.add_option('-V', '--version',
252                action = 'store_true',
253                dest   = 'VERSION',
254                help   = 'Print the program version number and exit'
255        )
256
257def parser(argv):
258        """
259        Make use of sara advance parser module. It can handle regex in hostnames
260        """
261        parser = AdvancedParser.AdvancedParser(usage=__doc__)
262        add_options(parser)
263
264        options, args = parser.parse_args()
265       
266        if options.VERSION:
267                print VERSION
268                sys.exit(0)
269
270        if options.filename:
271                if not os.path.isfile(os.path.join(PXE_CONF_DIR, options.filename)):
272                                error =  '%s: Filename does not exists' %(options.filename)
273                                print error
274                                sys.exit(1)
275        else:
276                options.filename = select_pxe_configfile()
277
278        if options.DEBUG:
279                print args, options
280
281        hosts_2_hex(args, options)
282
283def hosts_2_hex(hosts, options):
284        """
285        Convert hostname(s) to a net address that can be handled by manage_links function
286        """
287        if options.VERBOSE:
288                str = 'host_2_hex: %s' %hosts
289                print str
290
291        for host in hosts:
292                try:
293                        addr = socket.gethostbyname(host)
294                except socket.error,detail:
295                        error =  '%s not an valid hostname: %s' %(host,detail)
296                        print error
297                        sys.exit(1)
298
299                net = string.splitfields(addr, '.')
300                cnet = string.joinfields(net[0:3], '.')
301
302                binfo = dict()
303                binfo[NETWORK] = net_2_hex(cnet, options)
304                binfo[START] = int(net[3])
305                binfo[END] =  int(net[3])
306                manage_links(binfo, options)
307               
308
309def main():
310        # A dictionary holding the boot info
311        #
312        global PXE_CONF_DIR
313       
314        configfile = '@pxeconfig_conf@'
315        settings = ReadConfig(configfile)
316       
317        try:
318                PXE_CONF_DIR = settings['pxe_config_dir']
319
320        except KeyError:
321                pass
322
323        PXE_CONF_DIR = os.path.realpath(PXE_CONF_DIR)
324        if not os.path.isdir(PXE_CONF_DIR):
325                error =  'pxeconfig directory: %s does not exists' %(PXE_CONF_DIR)
326                raise PxeConfig, error
327
328        parser(sys.argv)
329       
330if __name__ == '__main__':
331        try:
332                main()
333        except PxeConfig, detail:
334                print detail
335                sys.exit(1)
Note: See TracBrowser for help on using the repository browser.