quorate/services/mirrored-image/k8s/bootstrap/bootstrap-lib.fsx

93 lines
2.8 KiB
FSharp

module Bootstrap
open System
type App =
{ Name: string
User: string
Org: string
Scopes: string list
Client: string }
type Session = { User: string; State: obj }
type Store =
{ Read: string -> Map<string, string>
Write: string -> Map<string, string> -> unit }
type Quay =
{ LoginAuth: unit -> string
Login: string -> string -> string -> Session
Access: string -> App -> unit
Application: string -> App -> string
Assign: string -> Session -> App -> unit
Issue: Session -> App -> string }
type Config = { AdminPath: string }
let apps =
[ { Name = "candidates-reader"
User = "candidates-bot"
Org = "candidates"
Scopes = [ "repo:read" ]
Client = "" }
{ Name = "candidates-writer"
User = "candidates-bot"
Org = "candidates"
Scopes = [ "repo:create"; "repo:write" ]
Client = "" }
{ Name = "mirror-reader"
User = "mirror-bot"
Org = "mirror"
Scopes = [ "repo:read" ]
Client = "" }
{ Name = "mirror-writer"
User = "mirror-bot"
Org = "mirror"
Scopes = [ "repo:create"; "repo:write" ]
Client = "" } ]
let personaPath user = $"secret/data/quay/personas/{user}"
let tokenPath app = $"secret/data/quay/oauth/{app.Name}"
let private field name (values: Map<string, string>) =
match Map.tryFind name values with
| Some value when not (String.IsNullOrWhiteSpace value) && value <> "PLACEHOLDER" -> value
| _ -> invalidOp "credential is absent"
let run config store quay =
let pending =
apps
|> List.filter (fun app ->
let values = store.Read(tokenPath app)
match Map.tryFind "token" values with
| Some value when not (String.IsNullOrWhiteSpace value) && value <> "PLACEHOLDER" -> false
| _ -> true)
if not pending.IsEmpty then
let admin = store.Read config.AdminPath |> field "token"
let loginAuth = quay.LoginAuth()
let sessions =
pending
|> List.map _.User
|> List.distinct
|> List.map (fun user ->
let password = store.Read(personaPath user) |> field "password"
let session = quay.Login user password loginAuth
let app = pending |> List.find (fun app -> app.User = user)
quay.Access admin app
user, session)
|> Map.ofList
for definition in pending do
let client = quay.Application admin definition
let app = { definition with Client = client }
let session = sessions[app.User]
quay.Assign admin session app
let token = quay.Issue session app
store.Write (tokenPath app) (Map.ofList (List.singleton ("token", token)))