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

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

cmt.py:

  • removed compatibility check

sara_cmt/cluster/templatetags/cmts_extras.py:

  • added compatibility check
  • see #4

this should do the trick

File size: 11.8 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    definition = token.split_contents()
169
170    if len(definition) != 4 and len(definition) != 2:
171        raise template.TemplateSyntaxError, '%r tag requires at least 1 arguments' % tag
172
173    tag = definition[0]
174    path_arg = definition[1]
175    #kw_as = definition[2]
176    #kw_output = definition[3]
177
178    if len(definition) == 4:
179
180        #RB: 4 arguments means: {% store /path/filename as output %}
181        #RB: old style: DONT try to resolve variable
182        #RB: instead convert filename to quoted string
183
184        path_str = "'%s'" %path_arg
185
186    else:
187
188        #RB: 2 arguments can mean: {% store 'string' %}
189        #RB: 2 arguments can mean: {% store variable %}
190
191        path_str = path_arg
192
193    # RB: parse the template thing until %endstore found
194    nodelist = parser.parse(('endstore',))
195    parser.delete_first_token()
196
197    # RB: Now lets start writing output files
198    return generateStoreOutput(tag, path_str, nodelist)
199
200class generateStoreOutput(template.Node):
201
202    def __init__(self, tag, path_str, nodelist):
203        self.tag = tag
204        self.nodelist = nodelist
205        self.path_str = path_str
206
207    def render(self, context):
208
209        if (self.path_str[0] == self.path_str[-1] and self.path_str[0] in ('"', "'")):
210
211            mypath_str = str(self.path_str)[1:-1]
212
213        else:
214            # RB: Not quoted: must be a variable: attempt to resolve to value
215            try:
216                pathvar = template.Variable( str(self.path_str) )
217                mypath_str = pathvar.resolve(context)
218            except template.VariableDoesNotExist:
219                #raise template.TemplateSyntaxError, '%r tag argument 1: not a variable %r' %( tag, path_str )
220                pass
221
222        # RB: render template between store tags
223        output = self.nodelist.render(context)
224
225        # RB: store output in context dict for later writing to file
226        context['stores'][ mypath_str ] = output
227
228        # RB: output generated into context dict, so we return nothing
229        return ''
230
231class ScriptNode(template.Node):
232    """
233        Renderer, which executes the lines included in the script-tags.
234    """
235
236    def __init__(self, nodelist):
237        self.nodelist = nodelist
238
239    def render(self, context):
240        script = self.nodelist.render(context)
241        if context.has_key('epilogue'):
242            context['epilogue'].append(script)
243        else:
244            context['epilogue'] = [script]
245        # All content between {% epilogue %} and {% endepilogue %} is parsed now
246        return ''
247
248@register.tag(name='epilogue')
249def do_epilogue(parser, token):
250    """
251        Saving the contents between the epilogue-tags
252    """
253    nodelist = parser.parse(('endepilogue',))
254    parser.delete_first_token()
255    return ScriptNode(nodelist)
256
257from django.db.models import get_model
258
259@register.tag(name='getbasenets')
260def do_getbasenets(parser, token):
261
262    try:
263        tag, network_name, kw_as, varname = token.split_contents()
264    except ValueError:
265        raise template.TemplateSyntaxError, '%r tag requires exactly 4 arguments' % tag
266
267    return getBaseNets( varname, network_name )
268
269class getBaseNets(template.Node):
270
271    """
272        Get list of basenets in a network (name)
273
274        Usage: {% getbasenets <network name> as <listname> %}
275    """
276
277    def __init__(self, varname, network_name ):
278
279        self.varname = varname
280        self.network_name = network_name.strip("'").strip('"').__str__()
281        self.basenets = [ ]
282
283    def render(self, context):
284
285        if (self.network_name[0] == self.network_name[-1] and self.network_name[0] in ('"', "'")):
286
287            network_str = str( self.network_name.strip("'").strip('"') )
288        else:
289            # RB: Not quoted: must be a variable: attempt to resolve to value
290            try:
291                networkvar = template.Variable( str(self.network_name) )
292                network_str = networkvar.resolve(context)
293            except template.VariableDoesNotExist:
294                #raise template.TemplateSyntaxError, '%r tag argument 1: not a variable %r' %( tag, path_str )
295                pass
296
297        from IPy import IP
298
299        network_units = get_model('cluster', 'Network').objects.filter( name=str(network_str) )
300
301        for n in network_units:
302
303            for ipnum in IP( n.cidr ):
304                if not base_net( ipnum ) in self.basenets:
305                    self.basenets.append( str( base_net( ipnum ) ) )
306
307        context[ self.varname ] = self.basenets
308        self.basenets = [ ]
309
310        return ''
311
312@register.tag(name='getracks')
313def do_getracks(parser, token):
314
315    try:
316        tag, cluster, kw_as, name = token.split_contents()
317    except ValueError:
318        raise template.TemplateSyntaxError, '%r tag requires exactly 4 arguments' % tag
319
320    return getRacks( name, cluster )
321
322class getRacks(template.Node):
323
324    """
325        Get list of racks in a cluster
326
327        Usage: {% getracks <cluster> as <listname> %}
328    """
329
330    def __init__(self, name, cluster):
331
332        self.name = name
333        self.cluster = cluster.strip("'").strip('"').__str__()
334        self.racks = [ ]
335
336    def render(self, context):
337
338        cluster_units = get_model('cluster', 'HardwareUnit').objects.filter( cluster__name=str(self.cluster) )
339
340        for u in cluster_units:
341            if u.rack not in self.racks:
342                self.racks.append( u.rack )
343
344        context[ self.name ] = self.racks
345        return ''
346
347@register.tag(name='use')
348def do_use(parser, token):
349    """
350        Compilation function to definine Querysets for later use.
351       
352        Usage: {% use <entity> with <attribute>=<value> as <list/var> <key> %}
353    """
354    tag = token.contents.split()[0]
355
356    try:
357        definition = token.split_contents()
358        # definition should look like ['use', <entity>, 'with' <query>, 'as', '<key>']
359    except ValueError:
360        raise template.TemplateSyntaxError, '%r tag requires at least 5 arguments' % tag
361    if len(definition) != 6:
362        raise template.TemplateSyntaxError, '%r tag requires at least 5 arguments' % tag
363    if definition[2] != 'with':
364        raise template.TemplateSyntaxError, "second argument of %r tag has to be 'with'" % tag
365    if definition[-2] != 'as':
366        raise template.TemplateSyntaxError, "second last argument of %r tag has to be 'as'" % tag
367
368    entity = definition[1]
369    query = definition[-3]
370    key = definition[-1]
371
372    return QuerySetNode(entity, query, key)
373
374class QuerySetNode(template.Node):
375    """
376        Renderer, which fetches objects from the database.
377    """
378
379    def __init__(self, entity, query, key):
380        self.entity = entity
381        self.query = query
382        self.key = key
383
384    def render(self, context):
385
386        if (self.query[0] == self.query[-1] and self.query[0] in ('"', "'")):
387
388            myquery_str = str( self.query.strip("'").strip('"') )
389        else:
390            # RB: Not quoted: must be a variable: attempt to resolve to value
391            try:
392                queryvar = template.Variable( str(self.query) )
393                myquery_str = queryvar.resolve(context)
394            except template.VariableDoesNotExist:
395                #raise template.TemplateSyntaxError, '%r tag argument 1: not a variable %r' %( tag, path_str )
396                pass
397
398        attr, val = myquery_str.split('=')
399        queryset = get_model('cluster', self.entity).objects.filter(**{attr:val})
400        if len(queryset) == 1:
401            queryset = queryset[0]
402        context[self.key] = queryset
403        logger.debug('context = %s'%context)
404        return ''
405
406# use <entity> with <attribute>=<value> as <key>
407
408
409       
Note: See TracBrowser for help on using the repository browser.