-- -- (C) 2019-21 - ntop.org -- local dirs = ntop.getDirs() package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path require "lua_utils" local host_pools_utils = require "host_pools_utils" local discover = require "discover_utils" local template = require "template_utils" local graph_utils = require "graph_utils" local page_utils = require "page_utils" sendHTTPContentTypeHeader('text/html') if not isAdministratorOrPrintErr() then return end page_utils.set_active_menu_entry(page_utils.menu_entries.pools_host) -- append the menu above the page dofile(dirs.installdir .. "/scripts/lua/inc/menu.lua") page_utils.print_page_title(i18n("host_pools.host_pools")) -- ************************************* ------ local pool_add_warnings = {} if _POST["edit_pools"] ~= nil then local config = paramsPairsDecode(_POST, true) for pool_id, pool_name in pairs(config) do -- Filter pool ids only if tonumber(pool_id) ~= nil then host_pools_utils.createPool(pool_id, pool_name, nil --[[ children_safe ]], nil --[[ enforce_quotas_per_pool_member ]], nil --[[ enforce_shapers_per_pool_member ]], true --[[ create or rename ]]) end end -- Reload is required here to load the new metadata ntop.reloadHostPools() elseif _POST["pool_to_delete"] ~= nil then local pool_id = _POST["pool_to_delete"] host_pools_utils.deletePool(pool_id) -- Note: this will also reload the shaping rules ntop.reloadHostPools() elseif (_POST["edit_members"] ~= nil) then local pool_to_edit = _POST["pool"] local config = paramsPairsDecode(_POST, true) local sanitized = {} -- Sanitize parameters for new_member, value in pairs(config) do if not isValidPoolMember(new_member) then http_lint.validationError(_POST, "new_member", new_member, "Invalid pool member") end local parts = split(value, "|") if #parts ~= 3 then http_lint.validationError(_POST, "member_values", parts, "Invalid member values") end local assembled = { old_member = parts[1], alias = parts[2], icon = parts[3], } -- Convention: use uppercase letters for mac, lowercase for ip if isMacAddress(new_member) then new_member = string.upper(new_member) else new_member = string.lower(new_member) end if (not isEmptyString(old_member)) and (not isValidPoolMember(assembled.old_member)) then http_lint.validationError(_POST, "old_member", new_member, "Invalid pool member") end if not http_lint.validateUnchecked(assembled.alias) then http_lint.validationError(_POST, "alias", assembled.alias, "Invalid member alias") end if not http_lint.validateSingleWord(assembled.icon) then http_lint.validationError(_POST, "icon", assembled.icon, "Invalid member icon") end local hostinfo = hostkey2hostinfo(new_member) local network, prefix = splitNetworkPrefix(hostinfo.host) local already_added = false if prefix ~= nil then local masked = ntop.networkPrefix(network, prefix) if masked ~= network then -- Normalize new networks (extract their prefix) local new_key = host2member(masked, hostinfo.vlan, prefix) pool_add_warnings[#pool_add_warnings + 1] = i18n("host_pools.network_normalized", { network = hostinfo2hostkey(hostkey2hostinfo(new_member)), network_normalized = hostinfo2hostkey(hostkey2hostinfo(new_key)) }) sanitized[new_key] = assembled already_added = true end end if not already_added then sanitized[new_member] = assembled end end config = sanitized -- This code handles member address changes -- delete old addresses for k,value in pairs(table.clone(config) --[[ Work on a copy to modify the original while iterating ]]) do local old_member = value.old_member if((not isEmptyString(old_member)) and (k ~= old_member)) then if config[old_member] then -- Do not delete and re-add members which have only changed their list key config[old_member].old_member = old_member else host_pools_utils.deletePoolMember(pool_to_edit, old_member) end end end -- add new addresses for new_member,value in pairs(config) do local k = value.old_member local is_new_member = (k ~= new_member) if is_new_member then local res, info = host_pools_utils.addPoolMember(pool_to_edit, new_member) if (res == false) and (info.existing_member_pool ~= nil) then -- remove @0 local member_to_print = hostinfo2hostkey(hostkey2hostinfo(new_member)) pool_add_warnings[#pool_add_warnings + 1] = i18n("host_pools.member_exists", { member_name = member_to_print, member_pool = host_pools_utils.getPoolName(info.existing_member_pool) }) end end local host_key, is_network = host_pools_utils.getMemberKey(new_member) if not is_network then local alias = value.alias local skip_alias = false if isMacAddress(new_member) then local manuf = ntop.getMacManufacturer(new_member) if (manuf ~= nil) and (manuf.extended == alias) then -- this is not the alias, it is the manufacturer skip_alias = true end end if(((not is_new_member) or (not isEmptyString(alias))) and (not skip_alias)) then setHostAltName(host_key, alias) end local icon = tonumber(value.icon) if (not isEmptyString(icon)) and ((not is_new_member) or (icon ~= 0)) and isMacAddress(new_member) and new_member ~= "00:00:00:00:00:00" then setCustomDeviceType(new_member, icon) ntop.setMacDeviceType(new_member, icon, true --[[ overwrite ]]) end end end ntop.reloadHostPools() elseif _POST["member_to_delete"] ~= nil then local pool_to_edit = _POST["pool"] host_pools_utils.deletePoolMember(pool_to_edit, _POST["member_to_delete"]) ntop.reloadHostPools() elseif _POST["empty_pool"] ~= nil then host_pools_utils.emptyPool(_POST["empty_pool"]) ntop.reloadHostPools() elseif (_POST["member"] ~= nil) and (_POST["pool"] ~= nil) then -- change member pool host_pools_utils.changeMemberPool(_POST["member"], _POST["pool"], nil, true --[[do not consider host MAC]]) ntop.reloadHostPools() end function printPoolNameField(pool_id_str) print[[
]] print[[]] print[[
]] print[[
]] end function printMemberAddressField(member_str, origin_value_str) print[[
]] print[[]] print[[
]] print[[
]] end function printMemberVlanField(member_str) print[[
]] print[[]] print[[
]] print[[
]] end function printIconField(member_str) discover.printDeviceTypeSelector("", "icon_member_' + " .. member_str .. " + '") end function printAliasField(member_str) print[[]] end -------------------------------------------------------------------------------- local selected_pool_id = _GET["pool"] local selected_pool = nil local available_pools = host_pools_utils.getPoolsList() for _, pool in ipairs(available_pools) do if pool.id == selected_pool_id then selected_pool = pool end end if selected_pool == nil then if #available_pools == 1 then -- only the default pool is available selected_pool = available_pools[1] else selected_pool = available_pools[2] end end -- We are passing too much _POST data, no more than 5 members allowed local perPageMembers = "5" local perPagePools = "10" local members_filtering = _GET["members_filter"] local manage_url = "?ifid="..ifId.."&page=pools&pool="..selected_pool.id.."#manage" local ifstats = interface.getStats() -------------------------------------------------------------------------------- print [[

]] print('\n') local function formatMemberFilter() if starts(members_filtering, "manuf:") then return i18n("host_pools.manufacturer_filter", {manufacturer=string.sub(members_filtering, string.len("manuf:")+1)}) else return i18n("host_pools.member_filter", {member=split(members_filtering, "/")[1]}) end end if members_filtering ~= nil then print[[ ]] end print('') print('
') print(i18n("host_pools.pool")) print(': ') local no_pools = (#available_pools <= 1) if selected_pool.id ~= host_pools_utils.DEFAULT_POOL_ID then if areHostPoolsTimeseriesEnabled(ifid) then print("  ") end end print('
') print( template.gen("typeahead_input.html", { typeahead={ base_id = "t_member", action = ntop.getHttpPrefix() .. "/lua/if_stats.lua#manage", parameters = { pool = selected_pool.id, ifid = tostring(ifId), page = "pools", }, json_key = "key", query_field = "members_filter", query_url = ntop.getHttpPrefix() .. "/lua/find_member.lua", query_title = i18n("host_pools.search_member"), style = "margin-left:1em; width:25em;", } }) ) print('
') if no_pools then print[[]] end for _, msg in ipairs(pool_add_warnings) do print([[
]]..i18n("warning")..[[: ]]..msg..[[
]]) end print[[

]] if not ntop.isEnterpriseM() and not ntop.isnEdgeEnterprise() then print[[]] print(i18n("notes")) print[[
  • ]] print(i18n("host_pools.max_members_message", {maxnum = host_pools_utils.LIMITED_NUMBER_POOL_MEMBERS})) print[[
]] end print[[ ]] print[[




]] local notes = {} if ntop.isnEdge() then notes[#notes + 1] = "
  • "..i18n("host_pools.cannot_delete_cp")..".
  • " end if not ntop.isEnterpriseM() and not ntop.isnEdgeEnterprise() then notes[#notes + 1] = "
  • "..i18n("host_pools.max_pools_message", {maxnum=host_pools_utils.LIMITED_NUMBER_USER_HOST_POOLS}).."
  • " end if #notes > 0 then print(i18n("notes")) print[[]] end print[[
    ]] -- Create delete dialogs print( template.gen("modal_confirm_dialog.html", { dialog={ id = "delete_pool_dialog", action = "deletePool(delete_pool_id)", title = i18n("host_pools.delete_pool"), message = i18n("host_pools.confirm_delete_pool") .. ' "", ' .. i18n("host_pools.and_associated_members").."?", confirm = i18n("delete"), } }) ) print( template.gen("modal_confirm_dialog.html", { dialog={ id = "delete_member_dialog", action = "deletePoolMember(delete_member_id)", title = i18n("host_pools.remove_member"), message = i18n("host_pools.confirm_remove_member") .. ' "" ' .. i18n("host_pools.from_pool") .. ' "' .. selected_pool.name .. '"?', confirm = i18n("remove"), } }) ) print( template.gen("modal_confirm_dialog.html", { dialog={ id = "empty_pool_dialog", action = "emptyCurrentPool()", title = i18n("host_pools.empty_pool"), message = i18n("host_pools.confirm_empty_pool") .. " " .. selected_pool.name.."?", confirm = i18n("host_pools.empty_pool"), } }) ) print( template.gen("modal_confirm_dialog.html", { dialog={ id = "change_member_pool_dialog", action = "changeMemberPool(change_member_id)", title = i18n("host_pools.change_member_pool"), message = i18n("host_pools.select_new_pool", {member=''}) .. '

    ', custom_alert_class = "", confirm = i18n("host_pools.change_pool"), } }) ) -- Create import dialog print( template.gen("import_modal.html", { dialog={ title = i18n("host_pools.config_import"), label = "", message = i18n("host_pools.config_import_message"), cancel = i18n("cancel"), apply = i18n("apply"), } }) ) print[[ ]] -------------------------------------------------------------------------------- print[[ ]] -- ==== Manage tab ==== print [[ ]] -- ==== Create tab ==== print [[ ]] print[[ ]] -- ************************************* ------ -- append the menu below the page dofile(dirs.installdir .. "/scripts/lua/inc/footer.lua")