CompositionalIT / farmer

Repeatable Azure deployments with ARM templates - made easy!
https://compositionalit.github.io/farmer
MIT License
525 stars 157 forks source link

Conditional values in Farmer builders, or composing builders? #731

Open Thorium opened 3 years ago

Thorium commented 3 years ago

I didn't find documentation about this: What is the best practice to work with conditional values in Farmer custom builders?

For example, the VM IP ARM (PublicIpId) is an Option type:

 let deployment = arm {
        location Location.UKSouth
        // more resources here
        add_resource myVm
        output "vmIP" myVm.PublicIpId.Value.ArmExpression
    }

The code fails if PublicIpId is None. When the deployments and resources are compex, I wouldn't want to create multiple copies of the same builders.

I'd like to do something like:

    let deployment = arm {
        location Location.UKSouth
        // more resources here
        add_resource myVm
        match myVm.PublicIpId with
        | Some ip -> output "vmIP" ip.ArmExpression
        | None -> ()
    }
// or
    let deployment = arm {
        location Location.UKSouth
        // more resources here
        add_resource myVm
        if myVm.PublicIpId.IsSome then
            output "vmIP" myVm.PublicIpId.Value.ArmExpression
    }

This control construct may only be used if the computation expression builder defines a 'For' method.

Or could I use composition and still take the advantage of the builder? Currently I've only find a solution to jump out of the builder and start to build manually the state, losing the convenience of builder with proper type-conversions in overloaded methods:

    let composition =
        match myVm.PublicIpId with
        | None -> deployment
        | Some ip -> { deployment with Outputs = deployment.Outputs.Add("vmIP", ip.ArmExpression.Eval()) }
Thorium commented 3 years ago
    let deployment = arm {
        location Location.UKSouth
        add_resource myVm
        output "vmIP" (myVm.PublicIpId |> Option.map(fun ip -> ip.ArmExpression))
    }

Now, only thing more to add, what if there are a list of VMs...

davidglassborow commented 1 year ago

I've got exactly the same issue, trying to work out how to configure different instances (staging/acc/prod) from the same set of builders