source: trunk/sara_cmt/sara_cmt/cluster/templatetags/cmts_extras.py @ 14136

Last change on this file since 14136 was 14136, checked in by ramonb, 12 years ago

templatetags/cmts_extras.py:

  • some cleanup
File size: 11.3 KB
Line 
1import os, re, string
2
3# Inspired by Django tips on:
4#   http://www.b-list.org/weblog/2006/jun/07/django-tips-write-better-template-tags/
5from django import template
6from django.template.defaultfilters import stringfilter
7from django.utils.encoding import smart_unicode, force_unicode
8
9from sara_cmt.logger import Logger
10logger = Logger().getLogger()
11
12#from django.db.models import get_model
13
14register = template.Library()
15
16class NoBlankLinesNode(template.Node):
17    """
18        Renderer that'll remove all blank lines.
19    """
20
21    def __init__(self, nodelist):
22        self.nodelist = nodelist
23
24    def render(self, context):
25        return re.sub('\n([\ \t]*\n)+', '\n', force_unicode(
26            self.nodelist.render(context)))
27
28@register.tag
29def noblanklines(parser, token):
30    nodelist = parser.parse(('endnoblanklines',))
31    parser.delete_first_token()
32    return NoBlankLinesNode(nodelist)
33
34@stringfilter
35def arpanize(value):
36    """
37        Converts a IP (range) to reversed DNS style arpa notation
38
39        Usage:
40            {{{ <variable>|arpanize }}}
41
42        I.e.:
43            {% assign broadcast = '192.168.1.0' %}
44            {{{ broastcast|arpanize }}}
45        Results in output:
46            1.168.192.in-addr.arpa
47    """
48    ip_blocks = value.split('.')
49
50    reverse_block = [ ip_blocks[2], ip_blocks[1], ip_blocks[0], 'in-addr.arpa' ]
51
52    return string.join( reverse_block, '.' )
53
54register.filter( 'arpanize', arpanize )
55
56@stringfilter
57def base_net(value):
58    """
59        Converts a IP (range) to it's first 3 octects
60
61        Usage:
62            {{{ <variable>|base_net }}}
63
64        I.e.:
65            {% assign broadcast = '192.168.1.0' %}
66            {{{ broastcast|base_net }}}
67        Results in output:
68            192.168.1
69    """
70    ip_blocks = value.split('.')
71
72    return string.join( ip_blocks[:3], '.' )
73
74register.filter( 'base_net', base_net )
75
76@stringfilter
77def ip_last_digit(value):
78    """
79        Converts a IP (range) to it's last octect
80
81        Usage:
82            {{{ <variable>|ip_last_digit }}}
83
84        I.e.:
85            {% assign myip = '192.168.1.123' %}
86            {{{ myip|ip_last_digit }}}
87        Results in output:
88            123
89    """
90    ip_blocks = value.split('.')
91
92    return ip_blocks[3]
93
94register.filter( 'ip_last_digit', ip_last_digit )
95
96@register.tag(name='assign')
97def do_assign(parser,token):
98
99    """
100        Variable assignment within template
101
102        Usage: {% assign newvar = <space seperated list of strings/vars> %}
103         i.e.: {% assign file_name = '/var/tmp/rack-' rack.label '.txt' %}
104    """
105    definition = token.split_contents()
106
107    if len(definition) < 4:
108        raise template.TemplateSyntaxError, '%r tag requires at least 4 arguments' % tag
109
110    tag = definition[0]
111    new_var = definition[1]
112    is_teken = definition[2]
113    assignees = definition[3:]
114
115    return resolveVariables( new_var, assignees )
116
117class resolveVariables(template.Node):
118
119    def __init__(self, varname, varlist ):
120
121        self.varname = varname
122        self.varlist = varlist
123
124    def render(self, context):
125        resvars = [ ]
126
127        for a in self.varlist:
128
129            var_str = ''
130
131            if not (a[0] == a[-1] and a[0] in ('"', "'")):
132                try:
133                    # RB: no quotes must mean its a variable
134                    #
135                    a_var = template.Variable( a )
136                    var_str = a_var.resolve(context)
137
138                except template.VariableDoesNotExist:
139
140                    #RB: still think not allowed to raise exceptions from render function
141                    #
142                    #raise template.TemplateSyntaxError, 'cannot resolve variable %r' %(  str( self.path ) )
143                    pass
144
145                resvars.append( str(var_str) )
146
147            else:
148                #RB: assume strings are quoted
149                #RB: strip quotes from string
150                #
151                a = str( a.strip("'").strip('"') )
152                resvars.append( str(a) )
153
154        #RB: finally assign the concatenated string to new varname
155        context[ self.varname ] = string.join( resvars, '' )
156
157        #RB: Django render functions not supposed/allowed to raise Exception, I think
158        return ''
159
160@register.tag(name='store')
161def do_save_meta(parser, token):
162    """
163        Compilation function to use for meta-info.
164
165        Usage: {% store '/path/to/file' %}
166               {% store variable %} # variable = '/path/to/file'
167    """
168    try:
169        # RB: split_contents respects quoted 'strings containing spaces'
170        tag, path_str = token.split_contents()
171    except ValueError:
172        raise template.TemplateSyntaxError, '%r tag requires at least 1 argument' % tag
173
174    # RB: parse the template thing until %endstore found
175    nodelist = parser.parse(('endstore',))
176    parser.delete_first_token()
177
178    # RB: Now lets start writing output files
179    return generateStoreOutput(tag, path_str, nodelist)
180
181class generateStoreOutput(template.Node):
182
183    def __init__(self, tag, path_str, nodelist):
184        self.tag = tag
185        self.nodelist = nodelist
186        self.path_str = path_str
187
188    def render(self, context):
189
190        if (self.path_str[0] == self.path_str[-1] and self.path_str[0] in ('"', "'")):
191
192            mypath_str = str(self.path_str)[1:-1]
193
194        else:
195            # RB: Not quoted: must be a variable: attempt to resolve to value
196            try:
197                pathvar = template.Variable( str(self.path_str) )
198                mypath_str = pathvar.resolve(context)
199            except template.VariableDoesNotExist:
200                #raise template.TemplateSyntaxError, '%r tag argument 1: not a variable %r' %( tag, path_str )
201                pass
202
203        # RB: render template between store tags
204        output = self.nodelist.render(context)
205
206        # RB: store output in context dict for later writing to file
207        context['stores'][ mypath_str ] = output
208
209        # RB: output generated into context dict, so we return nothing
210        return ''
211
212class ScriptNode(template.Node):
213    """
214        Renderer, which executes the lines included in the script-tags.
215    """
216
217    def __init__(self, nodelist):
218        self.nodelist = nodelist
219
220    def render(self, context):
221        script = self.nodelist.render(context)
222        if context.has_key('epilogue'):
223            context['epilogue'].append(script)
224        else:
225            context['epilogue'] = [script]
226        # All content between {% epilogue %} and {% endepilogue %} is parsed now
227        return ''
228
229@register.tag(name='epilogue')
230def do_epilogue(parser, token):
231    """
232        Saving the contents between the epilogue-tags
233    """
234    nodelist = parser.parse(('endepilogue',))
235    parser.delete_first_token()
236    return ScriptNode(nodelist)
237
238from django.db.models import get_model
239
240@register.tag(name='getbasenets')
241def do_getbasenets(parser, token):
242
243    try:
244        tag, network_name, kw_as, varname = token.split_contents()
245    except ValueError:
246        raise template.TemplateSyntaxError, '%r tag requires exactly 4 arguments' % tag
247
248    return getBaseNets( varname, network_name )
249
250class getBaseNets(template.Node):
251
252    """
253        Get list of basenets in a network (name)
254
255        Usage: {% getbasenets <network name> as <listname> %}
256    """
257
258    def __init__(self, varname, network_name ):
259
260        self.varname = varname
261        self.network_name = network_name.strip("'").strip('"').__str__()
262        self.basenets = [ ]
263
264    def render(self, context):
265
266        if (self.network_name[0] == self.network_name[-1] and self.network_name[0] in ('"', "'")):
267
268            network_str = str( self.network_name.strip("'").strip('"') )
269        else:
270            # RB: Not quoted: must be a variable: attempt to resolve to value
271            try:
272                networkvar = template.Variable( str(self.network_name) )
273                network_str = networkvar.resolve(context)
274            except template.VariableDoesNotExist:
275                #raise template.TemplateSyntaxError, '%r tag argument 1: not a variable %r' %( tag, path_str )
276                pass
277
278        from IPy import IP
279
280        network_units = get_model('cluster', 'Network').objects.filter( name=str(network_str) )
281
282        for n in network_units:
283
284            for ipnum in IP( n.cidr ):
285                if not base_net( ipnum ) in self.basenets:
286                    self.basenets.append( str( base_net( ipnum ) ) )
287
288        context[ self.varname ] = self.basenets
289        self.basenets = [ ]
290
291        return ''
292
293@register.tag(name='getracks')
294def do_getracks(parser, token):
295
296    try:
297        tag, cluster, kw_as, name = token.split_contents()
298    except ValueError:
299        raise template.TemplateSyntaxError, '%r tag requires exactly 4 arguments' % tag
300
301    return getRacks( name, cluster )
302
303class getRacks(template.Node):
304
305    """
306        Get list of racks in a cluster
307
308        Usage: {% getracks <cluster> as <listname> %}
309    """
310
311    def __init__(self, name, cluster):
312
313        self.name = name
314        self.cluster = cluster.strip("'").strip('"').__str__()
315        self.racks = [ ]
316
317    def render(self, context):
318
319        cluster_units = get_model('cluster', 'HardwareUnit').objects.filter( cluster__name=str(self.cluster) )
320
321        for u in cluster_units:
322            if u.rack not in self.racks:
323                self.racks.append( u.rack )
324
325        context[ self.name ] = self.racks
326        return ''
327
328@register.tag(name='use')
329def do_use(parser, token):
330    """
331        Compilation function to definine Querysets for later use.
332       
333        Usage: {% use <entity> with <attribute>=<value> as <list/var> <key> %}
334    """
335    tag = token.contents.split()[0]
336
337    try:
338        definition = token.split_contents()
339        # definition should look like ['use', <entity>, 'with' <query>, 'as', '<key>']
340    except ValueError:
341        raise template.TemplateSyntaxError, '%r tag requires at least 5 arguments' % tag
342    if len(definition) != 6:
343        raise template.TemplateSyntaxError, '%r tag requires at least 5 arguments' % tag
344    if definition[2] != 'with':
345        raise template.TemplateSyntaxError, "second argument of %r tag has to be 'with'" % tag
346    if definition[-2] != 'as':
347        raise template.TemplateSyntaxError, "second last argument of %r tag has to be 'as'" % tag
348
349    entity = definition[1]
350    query = definition[-3]
351    key = definition[-1]
352
353    return QuerySetNode(entity, query, key)
354
355class QuerySetNode(template.Node):
356    """
357        Renderer, which fetches objects from the database.
358    """
359
360    def __init__(self, entity, query, key):
361        self.entity = entity
362        self.query = query
363        self.key = key
364
365    def render(self, context):
366
367        if (self.query[0] == self.query[-1] and self.query[0] in ('"', "'")):
368
369            myquery_str = str( self.query.strip("'").strip('"') )
370        else:
371            # RB: Not quoted: must be a variable: attempt to resolve to value
372            try:
373                queryvar = template.Variable( str(self.query) )
374                myquery_str = queryvar.resolve(context)
375            except template.VariableDoesNotExist:
376                #raise template.TemplateSyntaxError, '%r tag argument 1: not a variable %r' %( tag, path_str )
377                pass
378
379        attr, val = myquery_str.split('=')
380        queryset = get_model('cluster', self.entity).objects.filter(**{attr:val})
381        if len(queryset) == 1:
382            queryset = queryset[0]
383        context[self.key] = queryset
384        logger.debug('context = %s'%context)
385        return ''
386
387# use <entity> with <attribute>=<value> as <key>
388
389
390       
Note: See TracBrowser for help on using the repository browser.