From 9b22c9c1e1290f077297b14b835b3b9085b48bde Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 19 Apr 2018 11:42:12 +0200 Subject: [PATCH] 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 --- modules/luci-base/luasrc/model/uci.lua | 50 +++-- modules/luci-base/luasrc/model/uci.luadoc | 299 ++++++++++++++++-------------- 2 files changed, 193 insertions(+), 156 deletions(-) diff --git a/modules/luci-base/luasrc/model/uci.lua b/modules/luci-base/luasrc/model/uci.lua index 0e3950c0b..fc2a605b3 100644 --- a/modules/luci-base/luasrc/model/uci.lua +++ b/modules/luci-base/luasrc/model/uci.lua @@ -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 }) diff --git a/modules/luci-base/luasrc/model/uci.luadoc b/modules/luci-base/luasrc/model/uci.luadoc index 49093c793..ef89d09b9 100644 --- a/modules/luci-base/luasrc/model/uci.luadoc +++ b/modules/luci-base/luasrc/model/uci.luadoc @@ -14,224 +14,226 @@ module "luci.model.uci" ---[[ Create a new UCI-Cursor. -@class function -@name cursor -@return UCI-Cursor +@class function +@name cursor +@return UCI-Cursor ]] ---[[ Create a new Cursor initialized to the state directory. -@class function -@name cursor_state -@return UCI cursor +@class function +@name cursor_state +@return UCI cursor ]] ---[[ Applies UCI configuration changes -@class function -@name Cursor.apply -@param configlist List of UCI configurations -@param command Don't apply only return the command +@class function +@name Cursor.apply +@param configlist List of UCI configurations +@param command Don't apply only return the command ]] ---[[ Delete all sections of a given type that match certain criteria. -@class function -@name Cursor.delete_all +@class function +@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) ]] ---[[ Create a new section and initialize it with data. -@class function -@name Cursor.section -@param config UCI config -@param type UCI section type -@param name UCI section name (optional) -@param values Table of key - value pairs to initialize the section with -@return Name of created section +@class function +@name Cursor.section +@param config UCI config +@param type UCI section type +@param name UCI section name (optional) +@param values Table of key - value pairs to initialize the section with +@return Name of created section ]] ---[[ Updated the data of a section using data from a table. -@class function -@name Cursor.tset -@param config UCI config -@param section UCI section name (optional) -@param values Table of key - value pairs to update the section with +@class function +@name Cursor.tset +@param config UCI config +@param section UCI section name (optional) +@param values Table of key - value pairs to update the section with ]] ---[[ Get a boolean option and return it's value as true or false. -@class function -@name Cursor.get_bool -@param config UCI config -@param section UCI section name -@param option UCI option -@return Boolean +@class function +@name Cursor.get_bool +@param config UCI config +@param section UCI section name +@param option UCI option +@return Boolean ]] ---[[ Get an option or list and return values as table. -@class function -@name Cursor.get_list -@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. +@class function +@name Cursor.get_list +@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. ]] ---[[ Get the given option from the first section with the given type. -@class function -@name Cursor.get_first -@param config UCI config -@param type UCI section type -@param option UCI option (optional) -@param default Default value (optional) -@return UCI value +@class function +@name Cursor.get_first +@param config UCI config +@param type UCI section type +@param option UCI option (optional) +@param default Default value (optional) +@return UCI value ]] ---[[ Set given values as list. Setting a list option to an empty list has the same effect as deleting the option. -@class function -@name Cursor.set_list -@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. -@return Boolean whether operation succeeded +@class function +@name Cursor.set_list +@param config UCI config +@param section UCI section name +@param option UCI option +@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. -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 +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. + +@class function +@name Cursor.substate +@return UCI state cursor tied to the parent cursor ]] ---[[ Add an anonymous section. -@class function -@name Cursor.add -@param config UCI config -@param type UCI section type -@return Name of created section +@class function +@name Cursor.add +@param config UCI config +@param type UCI section type +@return Name of created section ]] ---[[ Get a table of saved but uncommitted changes. -@class function -@name Cursor.changes -@param config UCI config -@return Table of changes -@see Cursor.save +@class function +@name Cursor.changes +@param config UCI config +@return Table of changes +@see Cursor.save ]] ---[[ Commit saved changes. -@class function -@name Cursor.commit -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.revert -@see Cursor.save +@class function +@name Cursor.commit +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.revert +@see Cursor.save ]] ---[[ Deletes a section or an option. -@class function -@name Cursor.delete -@param config UCI config -@param section UCI section name -@param option UCI option (optional) -@return Boolean whether operation succeeded +@class function +@name Cursor.delete +@param config UCI config +@param section UCI section name +@param option UCI option (optional) +@return Boolean whether operation succeeded ]] ---[[ Call a function for every section of a certain type. -@class function -@name Cursor.foreach -@param config UCI config -@param type UCI section type -@param callback Function to be called -@return Boolean whether operation succeeded +@class function +@name Cursor.foreach +@param config UCI config +@param type UCI section type +@param callback Function to be called +@return Boolean whether operation succeeded ]] ---[[ Get a section type or an option -@class function -@name Cursor.get -@param config UCI config -@param section UCI section name -@param option UCI option (optional) -@return UCI value +@class function +@name Cursor.get +@param config UCI config +@param section UCI section name +@param option UCI option (optional) +@return UCI value ]] ---[[ Get all sections of a config or all values of a section. -@class function -@name Cursor.get_all -@param config UCI config -@param section UCI section name (optional) -@return Table of UCI sections or table of UCI values +@class function +@name Cursor.get_all +@param config UCI config +@param section UCI section name (optional) +@return Table of UCI sections or table of UCI values ]] ---[[ Manually load a config. -@class function -@name Cursor.load -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.save -@see Cursor.unload +@class function +@name Cursor.load +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.save +@see Cursor.unload ]] ---[[ Revert saved but uncommitted changes. -@class function -@name Cursor.revert -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.commit -@see Cursor.save +@class function +@name Cursor.revert +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.commit +@see Cursor.save ]] ---[[ Saves changes made to a config to make them committable. -@class function -@name Cursor.save -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.load -@see Cursor.unload +@class function +@name Cursor.save +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.load +@see Cursor.unload ]] ---[[ @@ -243,57 +245,74 @@ then a named section of the given type is created. When invoked with four arguments `config`, `sectionname`, `optionname` and `optionvalue` then the value of the specified option is set to the given value. -@class function -@name Cursor.set -@param config UCI config -@param section UCI section name -@param option UCI option or UCI section type +@class function +@name Cursor.set +@param config UCI config +@param section UCI section name +@param option UCI option or UCI section type @param value UCI value or nothing if you want to create a section -@return Boolean whether operation succeeded +@return Boolean whether operation succeeded ]] ---[[ Get the configuration directory. -@class function -@name Cursor.get_confdir -@return Configuration directory +@class function +@name Cursor.get_confdir +@return Configuration directory ]] ---[[ Get the directory for uncomitted changes. -@class function -@name Cursor.get_savedir -@return Save directory +@class function +@name Cursor.get_savedir +@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. -@class function -@name Cursor.set_confdir +@class function +@name Cursor.set_confdir @param directory UCI configuration directory -@return Boolean whether operation succeeded +@return Boolean whether operation succeeded ]] ---[[ Set the directory for uncommited changes. -@class function -@name Cursor.set_savedir +@class function +@name Cursor.set_savedir @param directory UCI changes directory -@return Boolean whether operation succeeded +@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. -@class function -@name Cursor.unload -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.load -@see Cursor.save +@class function +@name Cursor.unload +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.load +@see Cursor.save ]] -- 2.11.0