Commit c91ce8c9 authored by Ad Schellevis's avatar Ad Schellevis

(configd) generate recursive templates, closes https://github.com/opnsense/core/issues/274

parent a4cd1e46
""" """
Copyright (c) 2014 Ad Schellevis Copyright (c) 2014 Ad Schellevis
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
...@@ -24,14 +25,16 @@ ...@@ -24,14 +25,16 @@
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------
package : configd package : configd
function: unix domain socket process worker process function: configd inline actions
"""
__author__ = 'Ad Schellevis'
"""
import syslog import syslog
import template
import config
__author__ = 'Ad Schellevis'
def execute(action, parameters): def execute(action, parameters):
...@@ -42,8 +45,7 @@ def execute(action, parameters): ...@@ -42,8 +45,7 @@ def execute(action, parameters):
:return: status ( string ) :return: status ( string )
""" """
if action.command == 'template.reload': if action.command == 'template.reload':
import template # generate template
import config
tmpl = template.Template(action.root_dir) tmpl = template.Template(action.root_dir)
conf = config.Config(action.config) conf = config.Config(action.config)
tmpl.setConfig(conf.get()) tmpl.setConfig(conf.get())
...@@ -57,12 +59,24 @@ def execute(action, parameters): ...@@ -57,12 +59,24 @@ def execute(action, parameters):
del tmpl del tmpl
return 'OK' return 'OK'
elif action.command == 'template.list':
# traverse all installed templates and return list
# the number of registered targets is returned between []
tmpl = template.Template(action.root_dir)
all_templates = tmpl.list_modules()
retval = []
for tag in sorted(all_templates.keys()):
template_name = '%s [%d]' % (tag, len(all_templates[tag]['+TARGETS']))
retval.append(template_name)
del tmpl
return '\n'.join(retval)
elif action.command == 'configd.actions': elif action.command == 'configd.actions':
# list all available configd actions # list all available configd actions
from processhandler import ActionHandler from processhandler import ActionHandler
act_handler = ActionHandler()
actHandler = ActionHandler() actions = act_handler.listActions(['message', 'description'])
actions = actHandler.listActions(['message', 'description'])
if unicode(parameters).lower() == 'json': if unicode(parameters).lower() == 'json':
import json import json
...@@ -70,7 +84,7 @@ def execute(action, parameters): ...@@ -70,7 +84,7 @@ def execute(action, parameters):
else: else:
result = [] result = []
for action in actions: for action in actions:
result.append('%s [ %s ]'%(action,actions[action]['description'])) result.append('%s [ %s ]' % (action, actions[action]['description']))
return '\n'.join(result) return '\n'.join(result)
......
...@@ -33,6 +33,7 @@ __author__ = 'Ad Schellevis' ...@@ -33,6 +33,7 @@ __author__ = 'Ad Schellevis'
import os import os
import os.path import os.path
import syslog
import collections import collections
import copy import copy
import jinja2 import jinja2
...@@ -56,7 +57,7 @@ class Template(object): ...@@ -56,7 +57,7 @@ class Template(object):
self._j2_env = jinja2.Environment(loader=jinja2.FileSystemLoader(self._template_dir), trim_blocks=True, self._j2_env = jinja2.Environment(loader=jinja2.FileSystemLoader(self._template_dir), trim_blocks=True,
extensions=["jinja2.ext.do",]) extensions=["jinja2.ext.do",])
def _readManifest(self, filename): def _read_manifest(self, filename):
""" """
:param filename: manifest filename (path/+MANIFEST) :param filename: manifest filename (path/+MANIFEST)
...@@ -70,7 +71,7 @@ class Template(object): ...@@ -70,7 +71,7 @@ class Template(object):
return result return result
def _readTargets(self, filename): def _read_targets(self, filename):
""" read raw target filename masks """ read raw target filename masks
:param filename: targets filename (path/+TARGETS) :param filename: targets filename (path/+TARGETS)
...@@ -93,9 +94,9 @@ class Template(object): ...@@ -93,9 +94,9 @@ class Template(object):
result = {} result = {}
file_path = '%s/%s' % (self._template_dir, module_name.replace('.', '/')) file_path = '%s/%s' % (self._template_dir, module_name.replace('.', '/'))
if os.path.exists('%s/+MANIFEST' % file_path) and read_manifest: if os.path.exists('%s/+MANIFEST' % file_path) and read_manifest:
result['+MANIFEST'] = self._readManifest('%s/+MANIFEST' % file_path) result['+MANIFEST'] = self._read_manifest('%s/+MANIFEST' % file_path)
if os.path.exists('%s/+TARGETS' % file_path): if os.path.exists('%s/+TARGETS' % file_path):
result['+TARGETS'] = self._readTargets('%s/+TARGETS' % file_path) result['+TARGETS'] = self._read_targets('%s/+TARGETS' % file_path)
else: else:
result['+TARGETS'] = {} result['+TARGETS'] = {}
...@@ -110,7 +111,7 @@ class Template(object): ...@@ -110,7 +111,7 @@ class Template(object):
result = {} result = {}
for root, dirs, files in os.walk(self._template_dir): for root, dirs, files in os.walk(self._template_dir):
if len(root) > len(self._template_dir): if len(root) > len(self._template_dir):
module_name = '.'.join(root.replace(self._template_dir, '').split('/')[:2]) module_name = '.'.join(root.replace(self._template_dir, '').split('/'))
if module_name not in result: if module_name not in result:
result[module_name] = self.list_module(module_name) result[module_name] = self.list_module(module_name)
...@@ -127,7 +128,7 @@ class Template(object): ...@@ -127,7 +128,7 @@ class Template(object):
# no data given, reset # no data given, reset
self._config = {} self._config = {}
def __findStringTags(self, instr): def __find_string_tags(self, instr):
""" """
:param instr: string with optional tags [field.$$] :param instr: string with optional tags [field.$$]
:return: :return:
...@@ -139,7 +140,7 @@ class Template(object): ...@@ -139,7 +140,7 @@ class Template(object):
return retval return retval
def __findFilters(self, tags): def __find_filters(self, tags):
""" match tags to config and construct a dictionary which we can use to construct the output filenames """ match tags to config and construct a dictionary which we can use to construct the output filenames
:param tags: list of tags [xmlnode.xmlnode.%.xmlnode,xmlnode] :param tags: list of tags [xmlnode.xmlnode.%.xmlnode,xmlnode]
:return: dictionary containing key (tagname) value {existing node key, value} :return: dictionary containing key (tagname) value {existing node key, value}
...@@ -203,8 +204,8 @@ class Template(object): ...@@ -203,8 +204,8 @@ class Template(object):
if not os.path.exists('/'.join(fparts)): if not os.path.exists('/'.join(fparts)):
os.mkdir('/'.join(fparts)) os.mkdir('/'.join(fparts))
def generate(self, module_name, create_directory=True): def _generate(self, module_name, create_directory=True):
""" generate configuration files using bound config and template data """ generate configuration files for one section using bound config and template data
:param module_name: module name in dot notation ( company.module ) :param module_name: module name in dot notation ( company.module )
:param create_directory: automatically create directories to place template output in ( if not existing ) :param create_directory: automatically create directories to place template output in ( if not existing )
...@@ -215,8 +216,8 @@ class Template(object): ...@@ -215,8 +216,8 @@ class Template(object):
for src_template in module_data['+TARGETS'].keys(): for src_template in module_data['+TARGETS'].keys():
target = module_data['+TARGETS'][src_template] target = module_data['+TARGETS'][src_template]
target_filename_tags = self.__findStringTags(target) target_filename_tags = self.__find_string_tags(target)
target_filters = self.__findFilters(target_filename_tags) target_filters = self.__find_filters(target_filename_tags)
result_filenames = {target: {}} result_filenames = {target: {}}
for target_filter in target_filters.keys(): for target_filter in target_filters.keys():
for key in target_filters[target_filter].keys(): for key in target_filters[target_filter].keys():
...@@ -266,3 +267,31 @@ class Template(object): ...@@ -266,3 +267,31 @@ class Template(object):
result.append(filename) result.append(filename)
return result return result
def generate(self, module_name, create_directory=True):
"""
:param module_name: module name in dot notation ( company.module ), may use wildcards
:param create_directory: automatically create directories to place template output in ( if not existing )
:return: list of generated output files
"""
result = []
for template_name in sorted(self.list_modules().keys()):
wildcard_pos = module_name.find('*')
do_generate = False
if wildcard_pos > -1 and module_name[:wildcard_pos] == template_name[:wildcard_pos]:
# wildcard match
do_generate = True
elif wildcard_pos == -1 and module_name == template_name:
# direct match
do_generate = True
elif wildcard_pos == -1 and len(module_name) < len(template_name) \
and '%s.'%module_name == template_name[0:len(module_name)+1]:
# match child item
do_generate = True
if do_generate:
syslog.syslog(syslog.LOG_NOTICE, "generate template container %s" % template_name)
for filename in self._generate(template_name, create_directory):
result.append(filename)
return result
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment