source: trunk/src/pxeconfig.py @ 171

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

pxe_global.py:

  • moved some more functions to the library the exception Class

src/pxeconfigd.py:

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