From 557f63b7c1d5538decd1fb87e67f52195d499227 Mon Sep 17 00:00:00 2001 From: Astro Date: Wed, 17 Nov 2021 23:57:16 +0100 Subject: [PATCH] nix/pkgs/subnetplan: init --- nix/pkgs/default.nix | 9 +- nix/pkgs/subnetplan/Gemfile | 3 + nix/pkgs/subnetplan/Gemfile.lock | 13 +++ nix/pkgs/subnetplan/default.nix | 15 ++++ nix/pkgs/subnetplan/gemset.nix | 12 +++ nix/pkgs/subnetplan/render.rb | 139 +++++++++++++++++++++++++++++++ nix/pkgs/subnetplans.nix | 54 ++++++++++++ 7 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 nix/pkgs/subnetplan/Gemfile create mode 100644 nix/pkgs/subnetplan/Gemfile.lock create mode 100644 nix/pkgs/subnetplan/default.nix create mode 100644 nix/pkgs/subnetplan/gemset.nix create mode 100644 nix/pkgs/subnetplan/render.rb create mode 100644 nix/pkgs/subnetplans.nix diff --git a/nix/pkgs/default.nix b/nix/pkgs/default.nix index 9a483c0..6aee49f 100644 --- a/nix/pkgs/default.nix +++ b/nix/pkgs/default.nix @@ -79,8 +79,13 @@ let starlink = import ./starlink { inherit pkgs; }; + + subnetplans = import ./subnetplans.nix { + inherit self nixpkgs system; + }; in -rootfs-packages // vm-packages // device-templates // network-graphs // starlink // { +rootfs-packages // vm-packages // device-templates // network-graphs // starlink // subnetplans // { inherit export-openwrt-models export-config dns-slaves - encrypt-secrets decrypt-secrets switch-to-production; + encrypt-secrets decrypt-secrets switch-to-production + ; } diff --git a/nix/pkgs/subnetplan/Gemfile b/nix/pkgs/subnetplan/Gemfile new file mode 100644 index 000000000..9e90ff2 --- /dev/null +++ b/nix/pkgs/subnetplan/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "ipaddress_2", "~> 0.14" diff --git a/nix/pkgs/subnetplan/Gemfile.lock b/nix/pkgs/subnetplan/Gemfile.lock new file mode 100644 index 000000000..4d11e5a --- /dev/null +++ b/nix/pkgs/subnetplan/Gemfile.lock @@ -0,0 +1,13 @@ +GEM + remote: https://rubygems.org/ + specs: + ipaddress_2 (0.14.0) + +PLATFORMS + ruby + +DEPENDENCIES + ipaddress_2 (~> 0.14) + +BUNDLED WITH + 2.1.4 diff --git a/nix/pkgs/subnetplan/default.nix b/nix/pkgs/subnetplan/default.nix new file mode 100644 index 000000000..c895d1d --- /dev/null +++ b/nix/pkgs/subnetplan/default.nix @@ -0,0 +1,15 @@ +{ pkgs ? import {} }: +with pkgs; +let + gems = bundlerEnv { + name = "gems-for-subnetplan"; + gemdir = ./.; + }; +in stdenv.mkDerivation rec { + name = "subnetplan"; + buildInputs = [ gems.wrappedRuby ]; + buildCommand = '' + install -D -m755 ${./render.rb} $out/bin/${name} + patchShebangs $out/bin/${name} + ''; +} diff --git a/nix/pkgs/subnetplan/gemset.nix b/nix/pkgs/subnetplan/gemset.nix new file mode 100644 index 000000000..df7f426 --- /dev/null +++ b/nix/pkgs/subnetplan/gemset.nix @@ -0,0 +1,12 @@ +{ + ipaddress_2 = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1wdy1ka0i9mncjqid2kv3ng6gi95y5xb9ykl0ar8lnrriia42v1c"; + type = "gem"; + }; + version = "0.14.0"; + }; +} diff --git a/nix/pkgs/subnetplan/render.rb b/nix/pkgs/subnetplan/render.rb new file mode 100644 index 000000000..c41ef11 --- /dev/null +++ b/nix/pkgs/subnetplan/render.rb @@ -0,0 +1,139 @@ +#!/usr/bin/env ruby + +require 'ipaddress_2' +require 'erb' + +TABLE_WIDTH = 8 + +class Subnet + attr_reader :addr, :desc + attr_accessor :addr_visible + + def initialize addr, desc + @addr = addr + @desc = desc + @addr_visible = false + end +end + +class Group + attr_accessor :net, :blocks + + def initialize net, blocks + @net = net + @blocks = blocks + end +end + +class Block + attr_accessor :label, :name + + def initialize label, name + @label = label + @name = name + end +end + +nets = [] +while line = gets + a, desc = line.split(/ /, 2) + addr = IPAddress.parse a + desc.chomp! + + nets << Subnet.new(addr, desc) +end + +nets.sort_by! { |net| net.addr } + +collisions = 0 +prev = nil +nets.each do |net| + if prev and (net.addr.include?(prev.addr) or prev.addr.include?(net.addr)) + STDERR.puts "#{prev.addr} and #{net.addr} overlap" + collisions += 1 + end + prev = net +end +exit 1 if collisions > 0 + +GROUP_PREFIX = 16 +groups = {} +nets.each do |net| + group = net.addr.supernet(GROUP_PREFIX).to_s + (groups[group] ||= []) << net +end + +max_prefix = groups.collect { nets.collect { |net| net.addr.prefix }.max }.max +groups = groups.collect do |group, nets| + allnet = nets[0].addr.clone + while allnet.prefix > 0 and not allnet.include?(nets[nets.size - 1].addr) + allnet = allnet.supernet(allnet.prefix - 1) + end + + blocks = [] + row = [] + allnet.subnet(max_prefix).each do |addr| + net = nets.select { |net| net.addr.include? addr }[0] + label = net ? "#{addr}/#{net.addr.prefix}" : addr.to_s + row << Block.new(label, net ? net.desc : "") + if row.size >= TABLE_WIDTH + blocks << row + row = [] + end + end + blocks << row if row.size > 0 + + blocks.each do |row| + prev_name = nil + row.each_with_index do |block| + block.label = "" if prev_name == block.name + prev_name = block.name + end + end + + Group.new(allnet, blocks) +end + +def background_color desc + case desc + when "core" + "#9F9F9F" + when "mgmt" + "#FF3F3F" + when "c3d2" + "yellow" + when "serv", "cluster" + "orange" + when "pub" + "#7FFF7F" + when /priv(\d+)/ + "hsl(240, 80%, #{60 + 5 * ($1.to_i % 8)}%)" + else + "white" + end +end + +html = ERB::new <<~EOF + + + Subnetwork Plan + + + + <% groups.each do |group| %> + + + + <% group.blocks.each do |row| %> + + <% row.each do |block| %> + + <% end %> + + <% end %> + <% end %> +
<%= group.net.to_string %>
<%= block.label %> <%= block.name %>
+ + +EOF +puts html.result diff --git a/nix/pkgs/subnetplans.nix b/nix/pkgs/subnetplans.nix new file mode 100644 index 000000000..e3c16b2 --- /dev/null +++ b/nix/pkgs/subnetplans.nix @@ -0,0 +1,54 @@ +{ self, nixpkgs, system }: + +with nixpkgs.legacyPackages.${system}; +let + config = self.lib.config; +in +rec { + subnetplan4 = + stdenv.mkDerivation { + name = "subnetplan4.html"; + src = builtins.toFile "subnets4.txt" ( + lib.concatMapStringsSep "\n" (net: + "${config.site.net.${net}.subnet4} ${net}" + ) (builtins.attrNames ( + lib.filterAttrs (_: { subnet4, ... }: subnet4 != null) + config.site.net + )) + ); + buildInputs = [ + (import ./subnetplan { inherit pkgs; }) + ]; + buildCommand = '' + subnetplan < $src > $out + ''; + }; + + subnetplan6 = + stdenv.mkDerivation { + name = "subnetplan6.html"; + src = builtins.toFile "subnets6.txt" ( + lib.concatMapStrings (net: + lib.concatMapStrings (ctx: '' + ${config.site.net.${net}.subnets6.${ctx}} ${net} + '') (builtins.attrNames config.site.net.${net}.subnets6) + ) (builtins.attrNames config.site.net) + ); + buildInputs = [ + (import ./subnetplan { inherit pkgs; }) + ]; + buildCommand = '' + subnetplan < $src > $out + ''; + }; + + subnetplans = runCommand "subnetplans" {} '' + DIR=$out/share/doc/zentralwerk + mkdir -p $DIR $out/nix-support + + ${lib.concatMapStrings (pkg: '' + ln -s ${pkg} $DIR/${pkg.name} + echo doc report $DIR/${pkg.name} >> $out/nix-support/hydra-build-products + '') [ subnetplan4 subnetplan6 ]} + ''; +}