%PDF- %PDF-
Direktori : /backups/router/usr/libexec/ |
Current File : //backups/router/usr/libexec/nuageinit |
#!/usr/libexec/flua --- -- SPDX-License-Identifier: BSD-2-Clause-FreeBSD -- -- Copyright(c) 2022 Baptiste Daroussin <bapt@FreeBSD.org> local nuage = require("nuage") local ucl = require("ucl") local yaml = require("yaml") if #arg ~= 2 then nuage.err("Usage: " .. arg[0] .. " <cloud-init-directory> (<config-2> | <nocloud>)", false) end local path = arg[1] local citype = arg[2] local default_user = { name = "freebsd", homedir = "/home/freebsd", groups = "wheel", gecos = "FreeBSD User", shell = "/bin/sh", plain_text_passwd = "freebsd" } local root = os.getenv("NUAGE_FAKE_ROOTDIR") if not root then root = "" end local function open_config(name) nuage.mkdir_p(root .. "/etc/rc.conf.d") local f, err = io.open(root .. "/etc/rc.conf.d/" .. name, "w") if not f then nuage.err("unable to open " .. name .. " config: " .. err) end return f end local function get_ifaces() local parser = ucl.parser() -- grab ifaces local ns = io.popen("netstat -i --libxo json") local netres = ns:read("*a") ns:close() local res, err = parser:parse_string(netres) if not res then nuage.warn("Error parsing netstat -i --libxo json outout: " .. err) return nil end local ifaces = parser:get_object() local myifaces = {} for _, iface in pairs(ifaces["statistics"]["interface"]) do if iface["network"]:match("<Link#%d>") then local s = iface["address"] myifaces[s:lower()] = iface["name"] end end return myifaces end local function config2_network(p) local parser = ucl.parser() local f = io.open(p .. "/network_data.json") if not f then -- silently return no network configuration is provided return end f:close() local res, err = parser:parse_file(p .. "/network_data.json") if not res then nuage.warn("error parsing network_data.json: " .. err) return end local obj = parser:get_object() local ifaces = get_ifaces() if not ifaces then nuage.warn("no network interfaces found") return end local mylinks = {} for _, v in pairs(obj["links"]) do local s = v["ethernet_mac_address"]:lower() mylinks[v["id"]] = ifaces[s] end nuage.mkdir_p(root .. "/etc/rc.conf.d") local network = open_config("network") local routing = open_config("routing") local ipv6 = {} local ipv6_routes = {} local ipv4 = {} for _, v in pairs(obj["networks"]) do local interface = mylinks[v["link"]] if v["type"] == "ipv4_dhcp" then network:write("ifconfig_" .. interface .. '="DHCP"\n') end if v["type"] == "ipv4" then network:write( "ifconfig_" .. interface .. '="inet ' .. v["ip_address"] .. " netmask " .. v["netmask"] .. '"\n' ) if v["gateway"] then routing:write('defaultrouter="' .. v["gateway"] .. '"\n') end if v["routes"] then for i, r in ipairs(v["routes"]) do local rname = "cloudinit" .. i .. "_" .. interface if v["gateway"] and v["gateway"] == r["gateway"] then goto next end if r["network"] == "0.0.0.0" then routing:write('defaultrouter="' .. r["gateway"] .. '"\n') goto next end routing:write("route_" .. rname .. '="-net ' .. r["network"] .. " ") routing:write(r["gateway"] .. " " .. r["netmask"] .. '"\n') ipv4[#ipv4 + 1] = rname ::next:: end end end if v["type"] == "ipv6" then ipv6[#ipv6 + 1] = interface ipv6_routes[#ipv6_routes + 1] = interface network:write("ifconfig_" .. interface .. '_ipv6="inet6 ' .. v["ip_address"] .. '"\n') if v["gateway"] then routing:write('ipv6_defaultrouter="' .. v["gateway"] .. '"\n') routing:write("ipv6_route_" .. interface .. '="' .. v["gateway"]) routing:write(" -prefixlen 128 -interface " .. interface .. '"\n') end -- TODO compute the prefixlen for the routes --if v["routes"] then -- for i, r in ipairs(v["routes"]) do -- local rname = "cloudinit" .. i .. "_" .. mylinks[v["link"]] -- -- skip all the routes which are already covered by the default gateway, some provider -- -- still list plenty of them. -- if v["gateway"] == r["gateway"] then -- goto next -- end -- routing:write("ipv6_route_" .. rname .. '"\n') -- ipv6_routes[#ipv6_routes + 1] = rname -- ::next:: -- end --end end end if #ipv4 > 0 then routing:write('static_routes="') routing:write(table.concat(ipv4, " ") .. '"\n') end if #ipv6 > 0 then network:write('ipv6_network_interfaces="') network:write(table.concat(ipv6, " ") .. '"\n') network:write('ipv6_default_interface="' .. ipv6[1] .. '"\n') end if #ipv6_routes > 0 then routing:write('ipv6_static_routes="') routing:write(table.concat(ipv6, " ") .. '"\n') end network:close() routing:close() end if citype == "config-2" then local parser = ucl.parser() local res, err = parser:parse_file(path .. "/meta_data.json") if not res then nuage.err("error parsing config-2 meta_data.json: " .. err) end local obj = parser:get_object() if obj.public_keys then local homedir = nuage.adduser(default_user) for _,v in pairs(obj.public_keys) do nuage.addsshkey(homedir, v) end end nuage.sethostname(obj["hostname"]) -- network config2_network(path) elseif citype == "nocloud" then local f, err = io.open(path .. "/meta-data") if err then nuage.err("error parsing nocloud meta-data: " .. err) end local obj = yaml.eval(f:read("*a")) f:close() if not obj then nuage.err("error parsing nocloud meta-data") end local hostname = obj["local-hostname"] if not hostname then hostname = obj["hostname"] end if hostname then nuage.sethostname(hostname) end else nuage.err("Unknown cloud init type: " .. citype) end -- deal with user-data local ud = nil local f = nil userdatas = {"user-data", "user_data"} for _, v in pairs(userdatas) do f = io.open(path .. "/" .. v, "r") if f then ud = v break end end if not f then os.exit(0) end local line = f:read("*l") f:close() if line == "#cloud-config" then f = io.open(path .. "/" .. ud) local obj = yaml.eval(f:read("*a")) f:close() if not obj then nuage.err("error parsing cloud-config file: " .. ud) end if obj.groups then for n, g in pairs(obj.groups) do if (type(g) == "string") then local r = nuage.addgroup({name = g}) if not r then nuage.warn("failed to add group: " .. g) end elseif type(g) == "table" then for k, v in pairs(g) do nuage.addgroup({name = k, members = v}) end else nuage.warn("invalid type: " .. type(g) .. " for users entry number " .. n) end end end if obj.users then for n, u in pairs(obj.users) do if type(u) == "string" then if u == "default" then nuage.adduser(default_user) else nuage.adduser({name = u}) end elseif type(u) == "table" then -- ignore users without a username if u.name == nil then goto unext end local homedir = nuage.adduser(u) if u.ssh_authorized_keys then for _, v in ipairs(u.ssh_authorized_keys) do nuage.addsshkey(homedir, v) end end else nuage.warn("invalid type : " .. type(u) .. " for users entry number " .. n) end ::unext:: end else -- default user if none are defined nuage.adduser(default_user) end if obj.ssh_authorized_keys then local homedir = nuage.adduser(default_user) for _, k in ipairs(obj.ssh_authorized_keys) do nuage.addsshkey(homedir, k) end end if obj.network then local ifaces = get_ifaces() nuage.mkdir_p(root .. "/etc/rc.conf.d") local network = open_config("network") local routing = open_config("routing") local ipv6 = {} for _, v in pairs(obj.network.ethernets) do if not v.match then goto next end if not v.match.macaddress then goto next end if not ifaces[v.match.macaddress] then nuage.warn("not interface matching: " .. v.match.macaddress) goto next end local interface = ifaces[v.match.macaddress] if v.dhcp4 then network:write("ifconfig_" .. interface .. '="DHCP"\n') elseif v.addresses then for _, a in pairs(v.addresses) do if a:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)") then network:write("ifconfig_" .. interface .. '="inet ' .. a .. '"\n') else network:write("ifconfig_" .. interface .. '_ipv6="inet6 ' .. a .. '"\n') ipv6[#ipv6 + 1] = interface end end end if v.gateway4 then routing:write('defaultrouter="' .. v.gateway4 .. '"\n') end if v.gateway6 then routing:write('ipv6_defaultrouter="' .. v.gateway6 .. '"\n') routing:write("ipv6_route_" .. interface .. '="' .. v.gateway6) routing:write(" -prefixlen 128 -interface " .. interface .. '"\n') end ::next:: end if #ipv6 > 0 then network:write('ipv6_network_interfaces="') network:write(table.concat(ipv6, " ") .. '"\n') network:write('ipv6_default_interface="' .. ipv6[1] .. '"\n') end network:close() routing:close() end else local res, err = os.execute(path .. "/" .. ud) if not res then nuage.err("error executing user-data script: " .. err) end end