luci-base: implement session handling in luci.model.uci

Introduce luci.model.uci.set_session_id() and luci.model.uci.get_session_id()
to set and get the effective session ID respectively.

When a session ID is set, it is sent as `ubus_rpc_session` attribute to rpcd,
causing it to use per-session change directories, isolating LuCI changes from
the global system uci state.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2018-04-19 11:42:12 +02:00
parent fc8f825e2f
commit 9b22c9c1e1
2 changed files with 193 additions and 156 deletions

View file

@ -32,6 +32,15 @@ local ERRSTR = {
"Connection failed"
}
local session_id = nil
local function call(cmd, args)
if type(args) == "table" and session_id then
args.ubus_rpc_session = session_id
end
return util.ubus("uci", cmd, args)
end
function cursor()
return _M
@ -54,6 +63,10 @@ function get_savedir(self)
return "/tmp/.uci"
end
function get_session_id(self)
return session_id
end
function set_confdir(self, directory)
return false
end
@ -62,6 +75,11 @@ function set_savedir(self, directory)
return false
end
function set_session_id(self, id)
session_id = id
return true
end
function load(self, config)
return true
@ -77,7 +95,7 @@ end
function changes(self, config)
local rv = util.ubus("uci", "changes", { config = config })
local rv = call("changes", { config = config })
local res = {}
if type(rv) == "table" and type(rv.changes) == "table" then
@ -116,12 +134,12 @@ end
function revert(self, config)
local _, err = util.ubus("uci", "revert", { config = config })
local _, err = call("revert", { config = config })
return (err == nil), ERRSTR[err]
end
function commit(self, config)
local _, err = util.ubus("uci", "commit", { config = config })
local _, err = call("commit", { config = config })
return (err == nil), ERRSTR[err]
end
@ -133,7 +151,7 @@ function apply(self, configs, command)
if type(configs) == "table" then
for _, config in ipairs(configs) do
util.ubus("service", "event", {
call("service", "event", {
type = "config.change",
data = { package = config }
})
@ -145,7 +163,7 @@ end
function foreach(self, config, stype, callback)
if type(callback) == "function" then
local rv, err = util.ubus("uci", "get", {
local rv, err = call("get", {
config = config,
type = stype
})
@ -186,7 +204,7 @@ local function _get(self, operation, config, section, option)
if section == nil then
return nil
elseif type(option) == "string" and option:byte(1) ~= 46 then
local rv, err = util.ubus("uci", operation, {
local rv, err = call(operation, {
config = config,
section = section,
option = option
@ -220,7 +238,7 @@ function get_state(self, ...)
end
function get_all(self, config, section)
local rv, err = util.ubus("uci", "get", {
local rv, err = call("get", {
config = config,
section = section
})
@ -271,7 +289,7 @@ end
function section(self, config, stype, name, values)
local rv, err = util.ubus("uci", "add", {
local rv, err = call("add", {
config = config,
type = stype,
name = name,
@ -297,7 +315,7 @@ function set(self, config, section, option, value)
local sname, err = self:section(config, option, section)
return (not not sname), err
else
local _, err = util.ubus("uci", "set", {
local _, err = call("set", {
config = config,
section = section,
values = { [option] = value }
@ -319,7 +337,7 @@ function set_list(self, config, section, option, value)
end
function tset(self, config, section, values)
local _, err = util.ubus("uci", "set", {
local _, err = call("set", {
config = config,
section = section,
values = values
@ -353,7 +371,7 @@ function reorder(self, config, section, index)
return false, "Invalid argument"
end
local _, err = util.ubus("uci", "order", {
local _, err = call("order", {
config = config,
sections = sections
})
@ -363,7 +381,7 @@ end
function delete(self, config, section, option)
local _, err = util.ubus("uci", "delete", {
local _, err = call("delete", {
config = config,
section = section,
option = option
@ -374,13 +392,13 @@ end
function delete_all(self, config, stype, comparator)
local _, err
if type(comparator) == "table" then
_, err = util.ubus("uci", "delete", {
_, err = call("delete", {
config = config,
type = stype,
match = comparator
})
elseif type(comparator) == "function" then
local rv = util.ubus("uci", "get", {
local rv = call("get", {
config = config,
type = stype
})
@ -389,7 +407,7 @@ function delete_all(self, config, stype, comparator)
local sname, section
for sname, section in pairs(rv.values) do
if comparator(section) then
_, err = util.ubus("uci", "delete", {
_, err = call("delete", {
config = config,
section = sname
})
@ -397,7 +415,7 @@ function delete_all(self, config, stype, comparator)
end
end
elseif comparator == nil then
_, err = util.ubus("uci", "delete", {
_, err = call("delete", {
config = config,
type = stype
})

View file

@ -43,8 +43,8 @@ Delete all sections of a given type that match certain criteria.
@name Cursor.delete_all
@param config UCI config
@param type UCI section type
@param comparator Function that will be called for each section and
returns a boolean whether to delete the current section (optional)
@param comparator Function that will be called for each section and returns
a boolean whether to delete the current section (optional)
]]
---[[
@ -88,8 +88,8 @@ Get an option or list and return values as table.
@param config UCI config
@param section UCI section name
@param option UCI option
@return table. If the option was not found, you will simply get
-- an empty table.
@return table. If the option was not found, you will simply get an empty
table.
]]
---[[
@ -113,15 +113,17 @@ has the same effect as deleting the option.
@param config UCI config
@param section UCI section name
@param option UCI option
@param value value or table. Raw values will become a single item table.
@param value Value or table. Non-table values will be set as single
item UCI list.
@return Boolean whether operation succeeded
]]
---[[
Create a sub-state of this cursor. The sub-state is tied to the parent
Create a sub-state of this cursor.
The sub-state is tied to the parent curser, means it the parent unloads or
loads configs, the sub state will do so as well.
curser, means it the parent unloads or loads configs, the sub state will
do so as well.
@class function
@name Cursor.substate
@return UCI state cursor tied to the parent cursor
@ -268,6 +270,14 @@ Get the directory for uncomitted changes.
@return Save directory
]]
---[[
Get the effective session ID.
@class function
@name Cursor.get_session_id
@return String containing the session ID
]]
---[[
Set the configuration directory.
@ -286,6 +296,15 @@ Set the directory for uncommited changes.
@return Boolean whether operation succeeded
]]
---[[
Set the effective session ID.
@class function
@name Cursor.set_session_id
@param id String containing the session ID to set
@return Boolean whether operation succeeded
]]
---[[
Discard changes made to a config.