diff options
-rw-r--r-- | MANIFEST.in | 1 | ||||
-rw-r--r-- | cobbler/template_api.py | 192 | ||||
-rw-r--r-- | setup.py | 1 |
3 files changed, 30 insertions, 164 deletions
diff --git a/MANIFEST.in b/MANIFEST.in index 659f04a2..e7821624 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -15,6 +15,7 @@ include config/users.digest include config/users.conf include config/completions include config/cobbler_bash +include config/cheetah_macros recursive-include templates *.template recursive-include kickstarts *.ks include docs/cobbler.1.gz diff --git a/cobbler/template_api.py b/cobbler/template_api.py index e6a4b2ab..c81c67a1 100644 --- a/cobbler/template_api.py +++ b/cobbler/template_api.py @@ -25,6 +25,8 @@ import Cheetah.Template import os.path import re +CHEETAH_MACROS_FILE = '/etc/cobbler/cheetah_macros' + # This class is defined using the Cheetah language. Using the 'compile' function # we can compile the source directly into a python class. This class will allow # us to define the cheetah builtins. @@ -36,10 +38,22 @@ BuiltinTemplate = Cheetah.Template.Template.compile(source="\n".join([ # still need to make the snippet's namespace (searchList) available to the # template calling SNIPPET (done in the other part). - # TODO: Should this be in its own file? If so, should it go into - # /var/lib/cobbler or should it go with cobbler's site-package? - # how about /etc/cobbler/cheetah.conf ? -- mpd - + # Moved the other functions into /etc/cobbler/cheetah_macros + # Left SNIPPET here since it is very important. + + # This function can be used in two ways: + # Cheetah syntax: + # + # $SNIPPET('my_snippet') + # + # SNIPPET syntax: + # + # SNIPPET::my_snippet + # + # This follows all of the rules of snippets and advanced snippets. First it + # searches for a per-system snippet, then a per-profile snippet, then a + # general snippet. If none is found, a comment explaining the error is + # substituted. "#def SNIPPET($file)", "#set $fullpath = $find_snippet($file)", "#if $fullpath", @@ -48,168 +62,11 @@ BuiltinTemplate = Cheetah.Template.Template.compile(source="\n".join([ "# Error: no snippet data for $file", "#end if", "#end def", - - # Comment every line containing the $pattern given - "#def comment_lines($filename, $pattern, $commentchar='#')", - "perl -npe 's/^(.*${pattern}.*)$/${commentchar}\\${1}/' -i '$filename'", - "#end def", - - # Comments every line which contains only the exact pattern. - "#def comment_lines_exact($filename, $pattern, $commentchar='#')", - "perl -npe 's/^(${pattern})$/${commentchar}\\${1}/' -f '$filename'", - "#end def", - - # Uncomments every (commented) line containing the pattern - # Patterns should not contain the # - "#def uncomment_lines($filename, $pattern, $commentchar='#')", - "perl -npe 's/^[ \\t]*${commentchar}(.*${pattern}.*)$/\\${1}/' -i '$filename'", - "#end def", - - # Nullify (by changing to 'true') all instances of a given sh command. This - # does understand lines with multiple commands (separated by ';') and also - # knows to ignore comments. Consider other options before using this - # method. - "#def delete_command($filename, $pattern)", - "sed -nr '", - " h", - " s/^([^#]*)(#?.*)$/\\1/", - " s/((^|;)[ \\t]*)${pattern}([ \\t]*($|;))/\\1true\\3/g", - " s/((^|;)[ \\t]*)${pattern}([ \\t]*($|;))/\\1true\\3/g", - " x", - " s/^([^#]*)(#?.*)$/\\2/", - " H", - " x", - " s/\\n//", - " p", - "' -i '$filename'", - "#end def", - - # Replace a configuration parameter value, or add it if it doesn't exist. - # Assumes format is [param_name] [value] - "#def set_config_value($filename, $param_name, $value)", - "if [ -n \"\\$(grep -Ee '^[ \\t]*${param_name}[ \\t]+' '$filename')\" ]", - "then", - " perl -npe 's/^([ \\t]*${param_name}[ \\t]+)[\\x21-\\x7E]*([ \\t]*(#.*)?)$/\\${1}${sedesc($value)}\\${2}/' -i '$filename'", - "else", - " echo '$param_name $value' >> '$filename'", - "fi", - "#end def", - - # Replace a configuration parameter value, or add it if it doesn't exist. - # Assues format is [param_name] [delimiter] [value], where [delimiter] is - # usually '='. - "#def set_config_value_delim($filename, $param_name, $delim, $value)", - "if [ -n \"\\$(grep -Ee '^[ \\t]*${param_name}[ \\t]*${delim}[ \\t]*' '$filename')\" ]", - "then", - " perl -npe 's/^([ \\t]*${param_name}[ \\t]*${delim}[ \\t]*)[\\x21-\\x7E]*([ \\t]*(#.*)?)$/${1}${sedesc($value)}${2}/' -i '$filename'", - "else", - " echo '$param_name$delim$value' >> '$filename'", - "fi", - "#end def", - - # Copy a file from the server to the client. - "#def copy_over_file($serverfile, $clientfile)", - "cat << 'EOF' > '$clientfile'", - "#include $files + $serverfile", - "EOF", - "#end def", - - # Copy a file from the server and append the contents to a file on the - # client. - "#def copy_over_file($serverfile, $clientfile)", - "cat << 'EOF' >> '$clientfile'", - "#include $files + $serverfile", - "EOF", - "#end def", - - # Convenience function: Copy/append several files at once. This accepts a - # list of tuples. The first element indicates whether to overwrite ('w') or - # append ('a'). The second element is the file name on both the server and - # the client (a '/' is prepended on the client side). - "#def copy_files($filelist)", - "#for $thisfile in $filelist", - "#if $thisfile[0] == 'a'", - "$copy_append_file($thisfile[1], '/' + $thisfile[1])", - "#else", - "$copy_over_file($thisfile[1], '/' + $thisfile[1])", - "#end if", - "#end for", - "#end def", - - # Append some content to the todo file. NOTE: $todofile must be defined - # before using this (unless you want unexpected results). Be sure to end - # the content with 'EOF' - "#def TODO()", - "cat << 'EOF' >> '$todofile'", - "#end def", - - # Set the owner, group, and permissions for several files. Assignment can - # be plain ('p') or recursive. If recursive you can assign everything ('r') - # or just files ('f'). This method takes a list of tuples. The first element - # of each indicates which style. The remaining elements are owner, group, - # and mode respectively. If 'f' is used, an additional element is a find - # pattern that can further restrict assignments (use '*' if no additional - # restrict is desired). - "#def set_permissions($filelist)", - "#for $file in $filelist", - "#if $file[0] == 'p'", - "#if $file[1] != '' and $file[2] != ''", - "chown '$file[1]:$file[2]' '$file[4]'", - "#else", - "#if $file[1] != ''", - "chown '$file[1]' '$file[4]'", - "#end if", - "#if $file[2] != ''", - "chgrp '$file[2]' '$file[4]'", - "#end if", - "#end if", - "#if $file[3] != ''", - "chmod '$file[3]' '$file[4]'", - "#end if", - "#elif $file[0] == 'r'", - "#if $file[1] != '' and $file[2] != ''", - "chown -R '$file[1]:$file[2]' '$file[4]'", - "#else", - "#if $file[1] != ''", - "chown -R '$file[1]' '$file[4]'", - "#end if", - "#if $file[2] != ''", - "chgrp -R '$file[2]' '$file[4]'", - "#end if", - "#end if", - "#if $file[3] != ''", - "chmod -R '$file[3]' '$file[4]'", - "#end if", - "#elif $file[0] == 'f'", - "#if $file[1] != '' and $file[2] != ''", - "find $file[4] -name '$file[5]' -type f -exec chown -R '$file[1]:$file[2]' {} \\;", - "#else", - "#if $file[1] != ''", - "find $file[4] -name '$file[5]' -type f -exec chown -R '$file[1]' {} \\;", - "#end if", - "#if $file[2] != ''", - "find $file[4] -name '$file[5]' -type f -exec chgrp -R '$file[2]' {} \\;", - "#end if", - "#end if", - "#if $file[3] != ''", - "find $file[4] -name '$file[5]' -type f -exec chmod -R '$file[3]' {} \\;", - "#end if", - "#end if", - "#end for", - "#end def", - - # Cheeseball an entire directory. - "#def includeall($dir)", - "#import os", - "#for $file in $os.listdir($snippetsdir + '/' + $dir)", - "#include $snippetsdir + '/' + $dir + '/' + $file", - "#end for", - "#end def", - ]) + "\n") +MacrosTemplate = Cheetah.Template.Template.compile(file=CHEETAH_MACROS_FILE) -class Template(BuiltinTemplate): +class Template(BuiltinTemplate, MacrosTemplate): """ This class will allow us to include any pure python builtin functions. @@ -270,7 +127,7 @@ class Template(BuiltinTemplate): def find_snippet(self, file): """ Locate the appropriate snippet for the current system and profile. - This will first check for a per_system snippet, a per_profile snippet, + This will first check for a per-system snippet, a per-profile snippet, and a general snippet. If no snippet is located, it returns None. """ if self.varExists('system_name'): @@ -315,6 +172,13 @@ class Template(BuiltinTemplate): return result + # This function is used by several cheetah methods in cheetah_macros. + # It can be used by the end user as well. + # Ex: Replace all instances of '/etc/banner' with a value stored in + # $new_banner + # + # sed 's/$sedesc("/etc/banner")/$sedesc($new_banner)/' + # def sedesc(self, value): """ Escape a string for use in sed. @@ -80,6 +80,7 @@ if __name__ == "__main__": (etcpath, ['config/rsync.exclude']), (etcpath, ['config/users.conf']), (etcpath, ['config/acls.conf']), + (etcpath, ['config/cheetah_macros']), (initpath, ['config/cobblerd']), (etcpath, ['config/settings']), # (bashpath, ['config/cobbler_bash']), |