From 31bd7bd491738d8653a9e181594969a3665aca22 Mon Sep 17 00:00:00 2001 From: Kaarle Ritvanen Date: Tue, 10 Mar 2015 21:11:19 +0200 Subject: persistence: move augeas back-end directives out of addresses --- aconf/model/field.lua | 8 ++++++- aconf/model/root.lua | 20 ++++++++++++++--- aconf/modules/dns-zone.lua | 4 +++- aconf/modules/dnsmasq.lua | 18 +++++++++++---- aconf/modules/network.lua | 41 ++++++++++++++++++++++------------- aconf/modules/openssh.lua | 7 +++--- aconf/persistence/backends/augeas.lua | 36 +++++++++++++++++++----------- 7 files changed, 94 insertions(+), 40 deletions(-) diff --git a/aconf/model/field.lua b/aconf/model/field.lua index f5382c4..6e4607f 100644 --- a/aconf/model/field.lua +++ b/aconf/model/field.lua @@ -158,7 +158,12 @@ end function M.Field:topology(context) return { - {path=context.path, addr=context.addr, type=self.dtype} + { + path=context.path, + addr=context.addr, + be_mode=self.be_mode, + type=self.dtype + } } end @@ -332,6 +337,7 @@ end function M.TreeNode:topology(context) local res = super(self, M.TreeNode):topology(context) + res[1].subtype = res[1].type res[1].type = 'table' util.extend(res, node.topology(self:load(context, {create=true}))) return res diff --git a/aconf/model/root.lua b/aconf/model/root.lua index 2a135f2..a407b07 100644 --- a/aconf/model/root.lua +++ b/aconf/model/root.lua @@ -71,14 +71,28 @@ function M.register(name, field, params) for _, record in ipairs(node.topology(root:fetch(name))) do local top = M.topology(record.addr, true) - local function set(k, v) - setdefault(top, k, v) - assert(top[k] == v) + local function set(k, v, t) + if not t then t = top end + setdefault(t, k, v) + assert(t[k] == v) end set('type', record.type) + set('subtype', record.subtype) table.insert(top.paths, record.path) + local mode = record.be_mode + if mode then + if object.isinstance( + mode, require('aconf.path.address.special').SpecialMode + ) then + mode = {['.']=mode} + end + for addr, m in pairs(mode) do + set('mode', m, addr == '.' and top or top(addr, true)) + end + end + if record.scope then local scope = node.addr( root:fetch(pth.to_absolute(record.scope, pth.parent(record.path))) diff --git a/aconf/modules/dns-zone.lua b/aconf/modules/dns-zone.lua index f01c395..f0bd3e1 100644 --- a/aconf/modules/dns-zone.lua +++ b/aconf/modules/dns-zone.lua @@ -68,7 +68,9 @@ M.register( M.Collection{ type=M.Collection{ type=M.List{ - type=M.Model{model=Record, addr='#/*/*'}, ui_member='Record' + type=M.Model{model=Record, addr='*/*'}, + be_mode=M.addr.special.enum_keys, + ui_member='Record' }, ui_member='' }, diff --git a/aconf/modules/dnsmasq.lua b/aconf/modules/dnsmasq.lua index 5fd831c..f46e4a0 100644 --- a/aconf/modules/dnsmasq.lua +++ b/aconf/modules/dnsmasq.lua @@ -8,7 +8,7 @@ local M = require('aconf.model') local filter_conf = '/etc/dnsmasq-filter.conf' local Address = M.new() -Address.address = M.net.IPAddress{addr='&'} +Address.address = M.net.IPAddress{be_mode=M.addr.special.value} Address.domain = M.String local Filter = M.new() @@ -34,15 +34,25 @@ Filter.redirect_address = M.net.IPAddress{ Filter.address = M.Model{model=Address, visible=false} Filter.whitelist = M.Set{ type=M.net.DomainName, - addr='server/@/\\#/domain/#', + addr='server/\\#/domain', ui_name='Domain whitelist', widget='inline' } local Dnsmasq = M.new() -Dnsmasq.filter = M.Model{model=Filter, addr='/augeas'..filter_conf} +Dnsmasq.filter = M.Model{ + model=Filter, + addr='/augeas'..filter_conf, + be_mode={ + server=M.addr.special.value_equals(), + ['server/\\#/domain']=M.addr.special.enum_keys + } +} Dnsmasq.conf_file = M.Set{ - type=M.String, addr='/augeas/etc/dnsmasq.conf/conf-file/#', visible=false + type=M.String, + addr='/augeas/etc/dnsmasq.conf/conf-file', + be_mode=M.addr.special.enum_keys, + visible=false } M.register('dnsmasq', Dnsmasq) diff --git a/aconf/modules/network.lua b/aconf/modules/network.lua index 17e0127..05d8576 100644 --- a/aconf/modules/network.lua +++ b/aconf/modules/network.lua @@ -13,7 +13,7 @@ Host.address = M.net.IPAddress{required=true, addr='ipaddr'} Host.canonical = M.String{required=true, ui_name='Canonical name'} Host.alias = M.Set{ type=M.String, - addr='alias/#', + be_mode=M.addr.special.enum_keys, ui_name='Aliases', ui_member='Alias', detail=false @@ -21,10 +21,16 @@ Host.alias = M.Set{ local Resolv = M.new() Resolv.servers = M.List{ - type=M.net.IPAddress, addr='nameserver/#', widget='inline' + type=M.net.IPAddress, + addr='nameserver', + be_mode=M.addr.special.enum_keys, + widget='inline' } Resolv.search_domains = M.List{ - type=M.String, addr='search/domain/#', widget='inline' + type=M.String, + addr='search/domain', + be_mode=M.addr.special.enum_keys, + widget='inline' } @@ -177,13 +183,13 @@ Interface.slaves = M.Set{ condition={type='bond'}, type=M.Reference{scope='../..', filter={status='detached'}}, required=true, - addr='@family/link/@method/none/bond-slaves' + addr='link/none/bond-slaves' } Interface.ports = M.Set{ condition={type='bridge'}, type=M.Reference{scope='../..', filter={status='detached'}}, required=true, - addr='@family/link/@method/none/bridge-ports' + addr='link/none/bridge-ports' } -- TODO do not allow VLAN creation for non-existent interfaces Interface.trunk = M.Reference{ @@ -195,7 +201,7 @@ Interface.trunk = M.Reference{ required=true, scope='..', filter={status={'detached', 'configured'}}, - addr='@family/link/@method/none/vlan-raw-device' + addr='link/none/vlan-raw-device' } -- TODO ensure that (trunk, tag) is unique Interface.vlan_tag = M.Integer{ @@ -204,7 +210,7 @@ Interface.vlan_tag = M.Integer{ required=true, min=0, max=4095, - addr='@family/link/@method/none/vlan-id', + addr='link/none/vlan-id', ui_name='VLAN tag' } @@ -212,7 +218,7 @@ Interface.ipv4 = M.Model{ model=IPv4, condition={status={'detached', 'configured'}}, create=true, - addr='@family/inet', + addr='inet', ui_name='IPv4 configuration', widget='inline' } @@ -220,7 +226,7 @@ Interface.ipv6 = M.Model{ model=IPv6, condition={status={'detached', 'configured'}}, create=true, - addr='@family/inet6', + addr='inet6', ui_name='IPv6 configuration', widget='inline' } @@ -247,15 +253,20 @@ Net.resolver = M.Model{ } Net.enabled_ifaces = M.Set{ - type=M.Reference{ - scope='../interfaces', - addr=iface_aug_addr..'/auto/#/*/*', - on_delete='set-null' - }, + type=M.Reference{scope='../interfaces', addr='*/*', on_delete='set-null'}, + addr=iface_aug_addr..'/auto', + be_mode=M.addr.special.enum_keys, visible=false } Net.interfaces = M.Collection{ - type=Interface, addr=iface_aug_addr..'/iface/@', widget='inline' + type=Interface, + addr=iface_aug_addr..'/iface', + be_mode={ + ['.']=M.addr.special.value_equals(), + ['*']=M.addr.special.value_equals('family'), + ['*/link']=M.addr.special.value_equals('method') + }, + widget='inline' } M.register('net', Net, {ui_name='Network'}) diff --git a/aconf/modules/openssh.lua b/aconf/modules/openssh.lua index 3b37759..4592c71 100644 --- a/aconf/modules/openssh.lua +++ b/aconf/modules/openssh.lua @@ -1,6 +1,6 @@ --[[ Copyright (c) 2013 Natanael Copa -Copyright (c) 2013-2014 Kaarle Ritvanen +Copyright (c) 2013-2015 Kaarle Ritvanen See LICENSE file for license details --]] @@ -17,7 +17,7 @@ SshKey.type = M.String{ {'ssh-rsa', 'ssh-rsa'} } } -SshKey.key = M.String{addr='&'} +SshKey.key = M.String{be_mode=M.addr.special.value} SshKey.comment = M.String local Sshd = M.service('sshd') @@ -35,7 +35,8 @@ Sshd.agent_forward = M.Boolean{ } Sshd.root_auth_keys = M.List{ type=SshKey, - addr='/augeas/root/.ssh/authorized_keys/key/#', + addr='/augeas/root/.ssh/authorized_keys/key', + be_mode=M.addr.special.enum_keys, ui_name='Root login keys', ui_member='Key' } diff --git a/aconf/persistence/backends/augeas.lua b/aconf/persistence/backends/augeas.lua index 2679371..2210346 100644 --- a/aconf/persistence/backends/augeas.lua +++ b/aconf/persistence/backends/augeas.lua @@ -49,12 +49,20 @@ local function key(mode) return mode.key or '.' end +local function aug_top(path) + path = copy(path) + table.insert(path, 1, 'augeas') + return topology(path) +end + + local function conv_path(path) local res = '/files' if #path == 0 then return res, nil, {} end path = copy(path) - local mode + local top = aug_top{} + local mode, parent local keys = {} repeat @@ -70,26 +78,27 @@ local function conv_path(path) res = append_key_pred(res, k, comp) table.insert(keys, k) else assert(false) end - mode = nil - elseif isinstance(comp, special.SpecialMode) then mode = comp + parent = nil else + parent = res res = res..'/'..comp keys = {} end + top = top and top(address.escape(comp)) + mode = top and top.mode + table.remove(path, 1) until #path == 0 - return res, mode, isinstance(mode, special.Value) and {} or keys -end - + if isinstance(mode, special.Value) then + assert(parent) + res = parent + end -local function aug_top(path) - path = copy(path) - table.insert(path, 1, 'augeas') - return topology(path) + return res, mode, keys end @@ -104,6 +113,8 @@ function backend:get(path, top) local tpe = top and top.type local tbl = tpe == 'table' + if tbl and top.subtype == 'model' then mode = nil end + local leaf = not tbl and not mode if isinstance(mode, special.Value) then assert(not tbl) @@ -116,7 +127,7 @@ function backend:get(path, top) if #matches == 0 and not is_selector then return end if is_selector and #path > 1 and not self:get( - array_without_last(array_without_last(path)), true + array_without_last(path), true ) then return end @@ -170,7 +181,6 @@ function backend:set(mods) local function insert(path, new) local apath, mode, keys = conv_path(path) - if mode then path[#path] = nil end if #path == 0 then return apath, keys end local name = path[#path] @@ -178,7 +188,7 @@ function backend:set(mods) local ppath, pmode = conv_path(parent) if isinstance(pmode, special.Selector) then - gc[address.join('/', table.unpack(array_without_last(parent)))] = false + gc[address.join('/', table.unpack(parent))] = false if isinstance(pmode, special.EnumKeys) then local count = #self.aug:match(ppath) -- cgit v1.2.3