I'm experimenting with writing some infra management as Gleam code. I'm Looking for comments on the pseudo code below.
I'm looking at alchemy.run (as well as terraform) for inspiration. alchemy convinced me it shouldn't be that hard.
- Everything is lazy, i.e. you can run the infra function and it returns a description of all resources, that can then be shown as a plan.
- I don't like that I have to write an encoder/decoder for every resource's config. Maybe I'll just use term to binary to store the last input value on disk.
- Names,
yield/donework on different types to make sure all resources have to be declared at the top level. So the plan is sure to show all resources. - Names again, I should probably use more domain specific language, i.e.
do->declareawait->depend
pub fn infra() {
use dns <- do(dnsimple(), yield("example.com"))
use dev <- do(netlify_site(), yield(NetlifySiteConfig("dev", None)))
use prod <- do(netlify_site(), {
use record <- await(dns)
yield(NetlifySiteConfig("prod", Some(record.domain)))
})
done()
}
type NetlifySiteConfig {
NetlifySiteConfig(name: String, dns: Option(String))
}
type NetlifySite {
NetlifySite
}
fn netlify_site() {
Resource(
create: fn(config) { NetlifySite },
update: fn(config, site) { NetlifySite },
id: fn(config: NetlifySiteConfig) { config.name },
decoder: todo as "decoder for saved config",
)
}
type Dnsimple {
Dnsimple(domain: String)
}
fn dnsimple() -> Resource(String, Dnsimple) {
todo
}
type Resource(i, o) {
Resource(
create: fn(i) -> o,
// update is optional, depending on output? Scheduled needs to be a specific state
update: fn(i, o) -> o,
id: fn(i) -> String,
decoder: decode.Decoder(o),
)
}
fn yield(value: t) -> Ref(t) {
todo
}
type Ref(o)
type Instance(o)
fn do(
resource: Resource(i, o),
config: Ref(i),
k: fn(Instance(o)) -> Instance(t),
) {
todo
}
// external systems don't get to switch
fn await(ref: Instance(t), k: fn(t) -> Ref(u)) -> Ref(u) {
todo
}
// list.fold([NetlifySiteConfig, NetlifySiteConfig], yield(Nil), fn(acc, c) {
// use _site <- do(netlify_site(), yield(c))
// acc
// })
fn done() -> Instance(Nil) {
todo
}