#load "bots.fsx" open System open System.IO open System.Net.Http open System.Net.Http.Headers open System.Text open System.Text.Json open Bots [] let rec pages fetch offset collected = let page: JsonElement = fetch $"bots?botVerificationStatus=VERIFIED&limit=100&offset={offset}" let slugs = page.GetProperty("bots").EnumerateArray() |> Seq.map (fun bot -> bot.GetProperty("slug").GetString()) |> Seq.toList if slugs.Length = 100 then pages fetch (offset + slugs.Length) (slugs :: collected) else slugs :: collected |> List.rev |> List.concat let run () = use settings = JsonDocument.Parse(File.ReadAllText(Path.Combine(__SOURCE_DIRECTORY__, "settings.json"))) let config = settings.RootElement let excluded = strings config "excluded" |> Set.ofList use radar = new HttpClient() radar.BaseAddress <- Uri(config.GetProperty("radar").GetString()) radar.DefaultRequestHeaders.Authorization <- AuthenticationHeaderValue("Bearer", File.ReadAllText("/radar/token").Trim()) let fetch (path: string) = use request = new HttpRequestMessage(HttpMethod.Get, path) use response = radar.Send request response.EnsureSuccessStatusCode() |> ignore use body = JsonDocument.Parse(response.Content.ReadAsStream()) if not (body.RootElement.GetProperty("success").GetBoolean()) then failwith $"Radar request failed: {path}" body.RootElement.GetProperty("result").Clone() let bots = pages fetch 0 [] |> List.map (fun slug -> (fetch ("bots/" + slug)).GetProperty("bot") |> decode) let desired = bots |> List.collect (headers excluded) |> routes config let ns = config.GetProperty("namespace").GetString() let endpoint = $"/apis/gateway.networking.k8s.io/v1/namespaces/{ns}/httproutes" use kube = new HttpClient() kube.BaseAddress <- Uri "https://kubernetes.default.svc" kube.DefaultRequestHeaders.Authorization <- AuthenticationHeaderValue( "Bearer", File.ReadAllText("/var/run/secrets/kubernetes.io/serviceaccount/token").Trim() ) let send method (path: string) payload = use request = new HttpRequestMessage(method, path) payload |> Option.iter (fun value -> request.Content <- new StringContent(value, Encoding.UTF8, "application/apply-patch+yaml")) use response = kube.Send request response.EnsureSuccessStatusCode() |> ignore use body = JsonDocument.Parse(response.Content.ReadAsStream()) body.RootElement.Clone() let names = desired |> List.map (fun route -> route.metadata.name) |> Set.ofList desired |> List.iter (fun route -> send HttpMethod.Patch (endpoint + "/" + route.metadata.name + "?fieldManager=bot-redirect") (Some(JsonSerializer.Serialize route)) |> ignore) let existing = send HttpMethod.Get (endpoint + "?labelSelector=app.kubernetes.io%2Fmanaged-by%3Dbot-redirect") None existing.GetProperty("items").EnumerateArray() |> Seq.map (fun route -> route.GetProperty("metadata").GetProperty("name").GetString()) |> Seq.filter (fun name -> not (Set.contains name names)) |> Seq.iter (fun name -> send HttpMethod.Delete (endpoint + "/" + name) None |> ignore) printfn "bots=%d routes=%d" bots.Length desired.Length run ()