From d87814c2db948a01f4bdf2d60b5ba8dd29ad8fc7 Mon Sep 17 00:00:00 2001 From: Tim Wilkinson Date: Mon, 2 Dec 2024 21:28:41 -0800 Subject: [PATCH] Migrate dhcp options and tags into UCI (#1738) * Migrate DHCP option/tag files into UCI --- files/app/main/status/e/dhcp.ut | 80 +++++++++++--------- files/app/partial/dhcp.ut | 18 +---- files/etc/uci-defaults/20_setup_migrate | 48 ++++++++++++ files/usr/local/bin/node-setup | 56 +++++--------- files/usr/share/ucode/aredn/configuration.uc | 7 -- 5 files changed, 114 insertions(+), 95 deletions(-) diff --git a/files/app/main/status/e/dhcp.ut b/files/app/main/status/e/dhcp.ut index 0fd16dd6..5b34a1c0 100755 --- a/files/app/main/status/e/dhcp.ut +++ b/files/app/main/status/e/dhcp.ut @@ -50,7 +50,7 @@ if (request.env.REQUEST_METHOD === "PUT") { } } if (!uciMesh.get("setup", "dhcpreservations")) { - uciMesh.set("setup", "dhcpreservations", "reservation"); + uciMesh.set("setup", "dhcpreservations", "dhcpreservations"); } if (length(reservations)) { uciMesh.set("setup", "dhcpreservations", "reservation", reservations); @@ -63,28 +63,40 @@ if (request.env.REQUEST_METHOD === "PUT") { if ("advtags" in request.args) { configuration.prepareChanges(); const advtags = json(request.args.advtags); - const dhcp = configuration.getDHCP(); - let f = fs.open(dhcp.dhcptags, "w"); - if (f) { - for (let i = 0; i < length(advtags); i++) { - const t = advtags[i]; - f.write(`${t.name} ${t.type} ${t.match}\n`); - } - f.close(); + const tags = []; + for (let i = 0; i < length(advtags); i++) { + const t = advtags[i]; + push(tags, `${t.name} ${t.type} ${t.match}`); } + if (!uciMesh.get("setup", "dhcptags")) { + uciMesh.set("setup", "dhcptags", "dhcptags"); + } + if (length(tags)) { + uciMesh.set("setup", "dhcptags", "tag", tags); + } + else { + uciMesh.delete("setup", "dhcptags", "tag"); + } + uciMesh.commit("setup"); } if ("advoptions" in request.args) { configuration.prepareChanges(); const advoptions = json(request.args.advoptions); - const dhcp = configuration.getDHCP(); - let f = fs.open(dhcp.dhcpoptions, "w"); - if (f) { - for (let i = 0; i < length(advoptions); i++) { - const o = advoptions[i]; - f.write(`${o.name} ${o.always ? "force" : "onrequest"} ${o.type} ${o.value}\n`); - } - f.close(); + const options = []; + for (let i = 0; i < length(advoptions); i++) { + const o = advoptions[i]; + push(options, `${o.name} ${o.always ? "force" : "onrequest"} ${o.type} ${o.value}`); } + if (!uciMesh.get("setup", "dhcpoptions")) { + uciMesh.set("setup", "dhcpoptions", "dhcpoptions"); + } + if (length(options)) { + uciMesh.set("setup", "dhcpoptions", "option", options); + } + else { + uciMesh.delete("setup", "dhcpoptions", "option"); + } + uciMesh.commit("setup"); } print(_R("changes")); return; @@ -120,7 +132,7 @@ for (let i = 0; i < length(res); i++) { } } } -let f = fs.open(dhcp.leases); +const f = fs.open(dhcp.leases); if (f) { for (let l = f.read("line"); length(l); l = f.read("line")) { // ?, mac, ip, name, ? @@ -142,27 +154,21 @@ if (f) { } f.close(); } -f = fs.open(dhcp.dhcptags); -if (f) { - for (let l = f.read("line"); length(l); l = f.read("line")) { - const m = match(replace(l, /\n+$/, ""), /^([^\W_]+)\s(\w+)\s(.+)$/); - if (m) { - const p = replace(replace(replace(m[3], /"/g, """), //g, ">"); - push(advtags, { name: m[1], type: m[2], match: p }); - } - } - f.close(); +const tags = uciMesh.get("setup", "dhcptags", "tag") || []; +for (let i = 0; i < length(tags); i++) { + const m = match(replace(tags[i], /\n+$/, ""), /^([^\W_]+)\s(\w+)\s(.+)$/); + if (m) { + const p = replace(replace(replace(m[3], /"/g, """), //g, ">"); + push(advtags, { name: m[1], type: m[2], match: p }); + } } -f = fs.open(dhcp.dhcpoptions); -if (f) { - for (let l = f.read("line"); length(l); l = f.read("line")) { - const m = match(replace(l, /\n+$/, ""), /^(\S*)\s(force|onrequest)\s(\d+)\s(.*)$/); - if (m) { - const p = replace(replace(replace(m[4], /"/g, """), //g, ">"); - push(advoptions, { name: m[1], always: m[2] === "force", type: int(m[3]), value: p }); - } +const opts = uciMesh.get("setup", "dhcpoptions", "option") || []; +for (let i = 0; i < length(opts); i++) { + const m = match(replace(opts[i], /\n+$/, ""), /^(\S*)\s(force|onrequest)\s(\d+)\s(.*)$/); + if (m) { + const p = replace(replace(replace(m[4], /"/g, """), //g, ">"); + push(advoptions, { name: m[1], always: m[2] === "force", type: int(m[3]), value: p }); } - f.close(); } const dhcpOptionTypes = { "1": ["netmask", "mask"], diff --git a/files/app/partial/dhcp.ut b/files/app/partial/dhcp.ut index d9dc6bb7..c45a028e 100755 --- a/files/app/partial/dhcp.ut +++ b/files/app/partial/dhcp.ut @@ -39,7 +39,7 @@ let at = 0; let ao = 0; if (dhcp.enabled) { - let f = fs.open(dhcp.leases); + const f = fs.open(dhcp.leases); if (f) { while (length(f.read("line"))) { da++; @@ -47,20 +47,8 @@ f.close(); } dr = length(uciMesh.get("setup", "dhcpreservations", "reservation") || []); - f = fs.open(dhcp.dhcptags); - if (f) { - while (length(f.read("line"))) { - at++; - } - f.close(); - } - f = fs.open(dhcp.dhcpoptions); - if (f) { - while (length(f.read("line"))) { - ao++; - } - f.close(); - } + at = length(uciMesh.get("setup", "dhcptags", "tag") || []); + ao = length(uciMesh.get("setup", "dhcpoptions", "option") || []); } %} {% if (dhcp.enabled) { %} diff --git a/files/etc/uci-defaults/20_setup_migrate b/files/etc/uci-defaults/20_setup_migrate index e25a6411..f3f95cd5 100755 --- a/files/etc/uci-defaults/20_setup_migrate +++ b/files/etc/uci-defaults/20_setup_migrate @@ -100,12 +100,60 @@ if not c:get("setup", "dhcpreservations") then end end +-- Migrate the old school _setup.dhcptags.{nat,dmz} files +if not c:get("setup", "dhcptags") then + local file = "/etc/config.mesh/_setup.dhcptags." + if (nixio.fs.stat(file .. "nat", "size") or -1) > 0 then + file = file .. "nat" + elseif (nixio.fs.stat(file .. "dmz", "size") or -1) > 0 then + file = file .. "dmz" + else + file = nil + end + if file then + local dhcp = {} + for line in io.lines(file) + do + dhcp[#dhcp + 1] = line + end + c:set("setup", "dhcptags", "dhcptags") + c:set("setup", "dhcptags", "tag", dhcp) + c:commit("setup") + end +end + +-- Migrate the old school _setup.dhcpoptions.{nat,dmz} files +if not c:get("setup", "dhcpoptions") then + local file = "/etc/config.mesh/_setup.dhcpoptions." + if (nixio.fs.stat(file .. "nat", "size") or -1) > 0 then + file = file .. "nat" + elseif (nixio.fs.stat(file .. "dmz", "size") or -1) > 0 then + file = file .. "dmz" + else + file = nil + end + if file then + local dhcp = {} + for line in io.lines(file) + do + dhcp[#dhcp + 1] = line + end + c:set("setup", "dhcpoptions", "dhcpoptions") + c:set("setup", "dhcpoptions", "option", dhcp) + c:commit("setup") + end +end + -- Dont remove this yet otherwise we cannot revert this node -- os.remove("/etc/config.mesh/_setup") -- os.remove("/etc/config.mesh/_setup.service.dmz") -- os.remove("/etc/config.mesh/_setup.service.nat") -- os.remove("/etc/config.mesh/_setup.dhcp.dmz") -- os.remove("/etc/config.mesh/_setup.dhcp.nat") +-- os.remove("/etc/config.mesh/_setup.dhcptags.dmz") +-- os.remove("/etc/config.mesh/_setup.dhcptags.nat") +-- os.remove("/etc/config.mesh/_setup.dhcpoptions.dmz") +-- os.remove("/etc/config.mesh/_setup.dhcpoptions.nat") __EOF__ /usr/bin/lua /tmp/setup_migrate diff --git a/files/usr/local/bin/node-setup b/files/usr/local/bin/node-setup index 6818c138..720f0d9b 100755 --- a/files/usr/local/bin/node-setup +++ b/files/usr/local/bin/node-setup @@ -309,18 +309,12 @@ end -- select ports and dhcp files based on mode local portfile = "/etc/config.mesh/_setup.ports" -local dhcptagsfile = "/etc/config.mesh/_setup.dhcptags" -local dhcpoptionsfile = "/etc/config.mesh/_setup.dhcpoptions" local aliasfile = "/etc/config.mesh/aliases" if is_nat_mode() then portfile = portfile .. ".nat" - dhcptagsfile = dhcptagsfile .. ".nat" - dhcpoptionsfile = dhcpoptionsfile .. ".nat" aliasfile = aliasfile .. ".nat" else portfile = portfile .. ".dmz" - dhcptagsfile = dhcptagsfile .. ".dmz" - dhcpoptionsfile = dhcpoptionsfile .. ".dmz" aliasfile = aliasfile .. ".dmz" end @@ -774,38 +768,31 @@ if is_nat_mode() then end -- setup node lan dhcp -local function load_dhcp_tags(dhcptagsfile) +local function load_dhcp_tags() local dhcp_tags = {} - - for line in io.lines(dhcptagsfile) + local tags = cm:get_all("setup", "dhcptags", "tag") or {} + for _, tag in ipairs(tags) do - if not (line:match("^%s*#") or line:match("^%s*$")) then - local name, condition, pattern = line:match("(%S+)%s+(%S+)%s+(.*)") - if pattern then - table.insert(get_subtable(dhcp_tags, condition), - {name = name, pattern = pattern}) - end + local name, condition, pattern = tag:match("(%S+)%s+(%S+)%s+(.*)") + if pattern then + table.insert(get_subtable(dhcp_tags, condition), { name = name, pattern = pattern }) end end return dhcp_tags end -local function load_dhcp_options(dhcpoptionsfile) +local function load_dhcp_options() local dhcp_options = {} - if nixio.fs.access(dhcpoptionsfile) then - for line in io.lines(dhcpoptionsfile) - do - if not (line:match("^%s*#") or line:match("^%s*$")) then - local tag, force, opt_num, opt_val = line:match("(%S*)%s+(%w+)%s+(%d+)%s+(.*)") - if opt_val then - local by_tag = get_subtable(dhcp_options, tag) - if tag == "" and force == FORCED then - force = UNFORCED -- force is unsupported for untagged options - end - table.insert(get_subtable(by_tag, force), - {num = opt_num, val = opt_val}) - end + local opts = cm:get_all("setup", "dhcpoptions", "option") or {} + for _, option in ipairs(opts) + do + local tag, force, opt_num, opt_val = option:match("(%S*)%s+(%w+)%s+(%d+)%s+(.*)") + if opt_val then + local by_tag = get_subtable(dhcp_options, tag) + if tag == "" and force == FORCED then + force = UNFORCED -- force is unsupported for untagged options end + table.insert(get_subtable(by_tag, force), { num = opt_num, val = opt_val }) end end return dhcp_options @@ -877,13 +864,10 @@ do table.insert(dhcp_option_list, "3") end - local advanced_options = load_dhcp_options(dhcpoptionsfile) - - if nixio.fs.access(dhcptagsfile) then - for condition, cond_list in pairs(load_dhcp_tags(dhcptagsfile)) - do - create_classifying_section(condition, cond_list) - end + local advanced_options = load_dhcp_options() + for condition, cond_list in pairs(load_dhcp_tags()) + do + create_classifying_section(condition, cond_list) end for tag, forcelist in pairs(advanced_options) diff --git a/files/usr/share/ucode/aredn/configuration.uc b/files/usr/share/ucode/aredn/configuration.uc index 7c1ab83b..a2014543 100755 --- a/files/usr/share/ucode/aredn/configuration.uc +++ b/files/usr/share/ucode/aredn/configuration.uc @@ -222,8 +222,6 @@ export function getDHCP(mode) cidr: network.netmaskToCIDR(setup.lan_mask), leases: "/tmp/dhcp.leases", ports: "/etc/config.mesh/_setup.ports.nat", - dhcptags: "/etc/config.mesh/_setup.dhcptags.nat", - dhcpoptions: "/etc/config.mesh/_setup.dhcpoptions.nat", aliases: "/etc/config.mesh/aliases.nat" }; } @@ -244,8 +242,6 @@ export function getDHCP(mode) cidr: network.netmaskToCIDR(setup.lan_mask), leases: "/tmp/dhcp.leases", ports: "/etc/config.mesh/_setup.ports.dmz", - dhcptags: "/etc/config.mesh/_setup.dhcptags.dmz", - dhcpoptions: "/etc/config.mesh/_setup.dhcpoptions.dmz", aliases: "/etc/config.mesh/aliases.dmz" }; } @@ -265,10 +261,7 @@ export function getDHCP(mode) mask: setup.dmz_lan_mask, cidr: network.netmaskToCIDR(setup.dmz_lan_mask), leases: "/tmp/dhcp.leases", - services: "/etc/config.mesh/_setup.services.dmz", ports: "/etc/config.mesh/_setup.ports.dmz", - dhcptags: "/etc/config.mesh/_setup.dhcptags.dmz", - dhcpoptions: "/etc/config.mesh/_setup.dhcpoptions.dmz", aliases: "/etc/config.mesh/aliases.dmz" }; }