#Infra as Gleam code

1 messages · Page 1 of 1 (latest)

carmine fern
#

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/done work 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 -> declare await -> 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
}
old sparrow
#

Looks cool!

I worked close to this project previously and I like their approach. Might be good inspiration?
https://github.com/golingon/lingon

Essentially, they provide k8s and terraform resources as Go types and then "compile" them to yaml/json before wrapping the CLI calls that applies the changes. I think they wanted to extract the relevant API calling parts from the kubectl/terraform CLIs but there was a bit too much magic and settled on reliably generate configs in smaller "layers" from regular, typed Go code

GitHub

Lingon is a collection of libraries and tools for building platforms using Go. - golingon/lingon

velvet osprey
#

I like it, but the yield/await syntax feels a little strange. Could the do function not take a function as its argument? Then you could have a block with your use await and just return netlify_site(NetlifySiteConfig(..))

radiant horizon
#

I've been planning on working on something like this for a while now with gleam. I basically wanna create a self-hosted fly.io and provide something similar to FLAME (https://fly.io/blog/rethinking-serverless-with-flame/)
Not quite just infrastructure as code but I think there'll be a lot of crossover

carmine fern
velvet osprey
# carmine fern Think I need a little more to get your vision here

Yeah sorry - was on my phone. Basically, I think the yield thing feels a little clunky, and it might be nice not to have that:

pub fn infra() {
  use dns <- do(dnsimple("example.com"))
  use dev <- do(netlify_site(), yield(NetlifySiteConfig("dev", None)))
  use prod <- do({
    use record <- await(dns)
    netlify_site(NetlifySiteConfig("prod", Some(record.domain)))
  })
  done()
}
tacit plover
#

did you take a look at winglang? its awesome

radiant horizon
#

website seems to be down thought yikes

carmine fern
tacit plover
#

sorry I havent used it, its on my aim when Ill need to provision something as it outputs terraform, with the iam rules out of the box

carmine fern
carmine fern
carmine fern
velvet osprey
#

Could you not use a unique ID for each resource and attach it to the Resource(a)? That's the strategy tools like Pulumi use, afaik