Coder Social home page Coder Social logo

unosd / pulumi.fsharp.extensions Goto Github PK

View Code? Open in Web Editor NEW
90.0 6.0 6.0 1.54 MB

F# computational expressions to reduce boilerplate in Pulumi code

License: GNU General Public License v2.0

F# 99.89% Batchfile 0.03% Shell 0.08%
fsharp pulumi azure pulumi-azure iac myriad aws kubernetes pulumi-aws pulumi-kubernetes

pulumi.fsharp.extensions's Introduction

Pulumi.FSharp.Extensions

F# computational expressions to reduce boilerplate in Pulumi code

NuGet Version and Downloads count NuGet Version and Downloads count NuGet Version and Downloads count NuGet Version and Downloads count NuGet Version and Downloads count NuGet Version and Downloads count NuGet Version and Downloads count NuGet Version and Downloads count

Readability difference

Pulumi.Tls vs Pulumi.FSharp.Tls for a self signed certificate

Pulumi.Tls

The computational expression syntax removes redundant parenthesis, input/io/inputList helpers, equal signs, lists for single input, subitems boilerplate.

Packages examples

Pulumi.FSharp.Aws

bucket {
    name "bucket-example"
    acl  "private"

    bucketWebsite { 
        indexDocument "index.html"
    }
}

Pulumi.FSharp.Azure

let rg =
    resourceGroup {
        name                   "ResourceGroupName"
    }

let sa =
    storageAccount {
        name                   "StorageAccountName"
        resourceGroup          rg.Name
        accountReplicationType "LRS"
        accountTier            "Standard"
        enableHttpsTrafficOnly true
    }
    
let container =
    storageContainer {
        name                   "StorageContainer"
        account                sa.Name
    }
    
let contentBlob =
    blob {
        name                   "StorageBlob"
        storageAccountName     storage
        storageContainerName   buildContainer
        source                 { Text = "Blob content" }.ToPulumiType
    }
    
let sasToken =
    sasToken {
        storage                sa
        blob                   contentBlob
    }
    
let appServicePlan =
    plan {
        name                   "FunctionAppServiceName"
        resourceGroup          rg.Name
        kind                   "FunctionApp"
        
        planSku {
            size "Y1"
            tier "Dynamic"
        }
    }

Pulumi.FSharp.AzureAD

application {
    name                    "AzureADApplicationName"
    displayName             "AzureAD application name"
    oauth2AllowImplicitFlow true
    
    replyUrls               [
        config.["WebEndpoint"]
        "https://jwt.ms"
        "http://localhost:8080"
    ]            
    
    applicationOptionalClaims {
        idTokens [
            applicationOptionalClaimsIdToken {
                name                 "upn"
                additionalProperties "include_externally_authenticated_upn"
                essential            true
            }
        ]
    }
}

Pulumi.FSharp.AzureNative

let storage =
    storageAccount {
        resourceGroup rg.Name
        location      rg.Location
        name          "StorageAccount"            
        sku           { name "LRS" }            
        kind          Kind.StorageV2
    }

blobContainer { 
    accountName       storage.Name
    resourceGroup     rg.Name
    name              "StorageContainer"
    
    PublicAccess.None
}

Pulumi.FSharp.Core

// Output computational expressions
let deploymentCountBars =
    output {
        let! previousOutputs =
            StackReference(Deployment.Instance.StackName).Outputs
        
        return previousOutputs.["CountBars"] + "I"
    }
    
// Output as secret
let someSecret =
    secretOutput {
        let! key1 = sa.PrimaryConnectionString
        let! key2 = sa.SecondaryConnectionString
        
        return $"Secret connection strings: {key1} {key2}"
    }
    
// Mixing Output<> and Task<>
let sas =
    output {
        let! connectionString = sa.PrimaryConnectionString
        let! containerName = container.Name
        let! url = blob.Url

        let start =
            DateTime.Now.ToString("u").Replace(' ', 'T')
        
        let expiry =
            DateTime.Now.AddHours(1.).ToString("u").Replace(' ', 'T')
        
        // Task to Output
        let! tokenResult =
            GetAccountBlobContainerSASArgs(
                ConnectionString = connectionString,
                ContainerName = containerName,
                Start = start,
                Expiry = expiry,
                Permissions = (GetAccountBlobContainerSASPermissionsArgs(Read = true))
            ) |>
            // This returns Task<>
            GetAccountBlobContainerSAS.InvokeAsync

        return url + tokenResult.Sas
    }

Pulumi.FSharp.Kubernetes

deployment {
    name "application"

    deploymentSpec {
        replicas 1

        labelSelector { 
            matchLabels [ "app", input "nginx" ]
        }

        podTemplateSpec {
            objectMeta {
                labels [ "app", input "nginx" ]
            }

            podSpec {
                containers [
                    container {
                        name  "nginx"
                        image "nginx"
                        ports [ containerPort { containerPortValue 80 } ]
                    }
                ]
            }
        }
    }
}

Full stack file example

  • Create a Pulumi F# project using pulumi new fsharp
  • Upgrade the project to .NET 5
  • Add the NuGet package Pulumi.FSharp.Azure
  • Edit the Program.fs and paste the example below
  • Run pulumi up and create the infrastructure using a readable strongly-typed DSL
  • Log in your new Visual Studio VM using the IP from the outputs and credentials in code

To discover available properties for each resource, examine the code documentation of the builders (E.G. hover over a Pulumi.FSharp.Azure.Compute.windowsVirtualMachine computational expression to find all available properties and on each property to discover their description)

module Program

open Pulumi.FSharp.Azure.Compute.Inputs
open Pulumi.FSharp.Azure.Network.Inputs
open Pulumi.FSharp.Azure.Compute
open Pulumi.FSharp.Azure.Network
open Pulumi.FSharp.Azure.Core
open Pulumi.FSharp

let infra () =
    let rg =
        resourceGroup {
            name     "rg-example"
            location "West Europe"
        }

    let pip =
        publicIp {
            name             "pip-example"
            resourceGroup    rg.Name
            location         rg.Location
            allocationMethod "Dynamic"
        }
    
    let vnet =
        virtualNetwork {
            name          "vnet-example"
            addressSpaces "10.0.0.0/16"
            location      rg.Location
            resourceGroup rg.Name
        }

    let subnet =
        subnet {
            name               "snet-example"
            resourceGroup      rg.Name
            virtualNetworkName vnet.Name
            addressPrefixes    "10.0.2.0/24"
        }

    let nic =
        networkInterface {
            name          "nic-example"
            location      rg.Location
            resourceGroup rg.Name

            ipConfigurations [ 
                networkInterfaceIpConfiguration {
                    name                       "internal"
                    subnetId                   subnet.Id
                    privateIpAddressAllocation "Dynamic"
                    publicIpAddressId          pip.Id
                }
            ]
        }
    
    let vm =
        windowsVirtualMachine {
            name                "vm-example"
            resourceName        "vm-example"
            resourceGroup       rg.Name
            size                "Standard_A1_v2"
            networkInterfaceIds nic.Id
            
            windowsVirtualMachineOsDisk {
                caching            "ReadWrite"
                storageAccountType "Standard_LRS"
            }
            
            adminUsername "unosdpulumi"
            adminPassword "ReplaceThisWithAProperPassword%%55"
            
            windowsVirtualMachineSourceImageReference {
                offer     "visualstudio2019latest"
                publisher "microsoftvisualstudio"
                sku       "vs-2019-comm-latest-win10-n"
                version   "latest"
            }
        }
        
    dict [ "PublicIP", vm.PublicIpAddress :> obj ]
           
[<EntryPoint>]
let main _ =
  Deployment.run infra

Examples library

https://github.com/UnoSD/Pulumi.FSharp.Extensions.Examples

Example project using the library

https://github.com/UnoSD/UnoCash

One language to rule them all (F# eXchange 2020)

I had the pleasure of being invited to speak at the F# eXchange 2020 on the 21st of October and, as promised, I have created a repo to share the slides of the talk: https://github.com/UnoSD/FSharp-eXChange2020

The talk goes through infrastructure as code in F# with Pulumi in general and explains the rationale and some of the technical details behind this repository.

Link to the video: https://skillsmatter.com/skillscasts/14888-lightning-talk-one-language-to-rule-them-all-iac-in-f-sharp

Development notes

Given that changes to the Pulumi.FSharp.Myriad project do not trigger re-generation unless the Myriad.fs file is modified, a PreBuildEvent in each fsproj file uses sed to change a dummy variable to a random integer on each build (this only works on GNU/Linux machines with sed). To avoid git finding changes in the Myriad.fs file every time, use the following:

git update-index --skip-worktree Pulumi.FSharp.Aws/Myriad.fs
git update-index --skip-worktree Pulumi.FSharp.Gcp/Myriad.fs
git update-index --skip-worktree Pulumi.FSharp.Tls/Myriad.fs
git update-index --skip-worktree Pulumi.FSharp.Azure/Myriad.fs
git update-index --skip-worktree Pulumi.FSharp.AzureAD/Myriad.fs
git update-index --skip-worktree Pulumi.FSharp.Kubernetes/Myriad.fs
git update-index --skip-worktree Pulumi.FSharp.AzureNative/Myriad.fs

pulumi.fsharp.extensions's People

Contributors

baronfel avatar lihram avatar mvsmal avatar unosd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

pulumi.fsharp.extensions's Issues

Some builders don't support all setter properties

VpcPeeringConnectionArgs has a R/W property Accepter: Input<Inputs.VpcPeeringConnectionAccepterArgs>
but vpcPeeringConnection { accepter ... } doesn't work (i.e. VpcPeeringConnectionBuilder lacks Accepter())

PeeringConnectionOptionsBuilder seems to have the same problem.

Might they be unique in that they take a single option object rather than InputList, InputMap?

Screenshot 2023-03-22 at 1 34 28 AM

How to use CustomResourceOptions?

Hi,

I've been looking through the code and am really struggling to understand how to use CustomResourceOptions (e.g. to mark a resource as protected when importing).
Any pointers on how this can be done?

Happy to submit a PR with docs if you can point me in the right direction.

Pulumi.FSharp.Kubernetes type mismatch

image

i receive that error on type mismatch, code was taken from readme as an example but had to adjust a bit on metadata, the other part i coudlnt' figure out

// create k8s deployment
module K8s =

    open Pulumi.FSharp.Kubernetes
    open Pulumi.FSharp.Kubernetes.Apps.V1
    open Pulumi.FSharp.Kubernetes.Apps.V1.Inputs
    open Pulumi.FSharp.Kubernetes.Meta.V1.Inputs
    open Pulumi.FSharp.Kubernetes.Core.V1.Inputs

    let test_k8s_dep () project_name = 
        deployment {
            objectMeta {
                name "application"
            }

            deploymentSpec {
                replicas 1

                labelSelector { 
                    matchLabels [ ("app", input "nginx") ]
                }

                podTemplateSpec {
                    objectMeta {
                        labels ([ "app", input "nginx" ])
                    }

                    podSpec {
                        containers [
                            container {
                                name  "nginx"
                                image "nginx"
                                ports [ containerPort { containerPortValue 80 } ]
                            }
                        ]
                    }
                }
            }
        }

Resource name overload

My issue is that Pulumi is appending generated characters to my resource names.
pulumi/pulumi#7368

Is it possible to specify resource names in such a way that generated characters are not appended?
According the the Pulumi docs, you must do this:

var role = new Aws.Iam.Role("my-role", new Aws.Iam.RoleArgs
{
    Name = "my-role-001",
});

It seems that name in the F# builder only takes a string. Would it be possible to overload it to take a resource name that will not be changed?

Great job..

Once again, amazing job on this library!

Myriad is a steep learning curve, I know; but the fact that you are generating the CEs makes this library incredibly reliable and resilient. Also, the embedded computation expressions make it so clean and a joy to use.

I only had to fallback to the base Pulumi API once, and that was because I had a pre-existing resource group that I needed to import via pulumi import, so I needed to create it with the Protect = true option:

    let rgName = $"my-resourcegroup"
    let rg = 
        Pulumi.AzureNative.Resources.ResourceGroup(
            rgName, 
            Pulumi.AzureNative.Resources.ResourceGroupArgs(
                Location = pIn "northcentralus",
                ResourceGroupName = pIn rgName
            ), Pulumi.CustomResourceOptions(Protect = true))

But I was able to do everything else via your CEs. ๐ŸŽ‰๐ŸŽ‰

CI running for a long time

Hi,

I was wondering if you knew why sometimes the CI would just not complete running for certain packages? E.g. https://github.com/UnoSD/Pulumi.FSharp.Extensions/runs/5834434536 has been running for a while now, which I figured was normal until I looked further up the CI history and saw that some jobs had been queued for 60+ days. My previous MR's main purpose was to get the latest version of Pulumi.FSharp.Gcp, and I'm wondering if there's something missing to make that happen? Please LMK if I can help.

Edit: Example of 60+ queued job: https://github.com/UnoSD/Pulumi.FSharp.Extensions/runs/4941344244

How to set AppService Identity

I am trying to set a web AppService Identity property, but the appService computation expression doesn't have an identity custom operation.

I'm trying to set it to "SystemAssigned" per this example so that I can give it access to a KeyVault resource.

Is there a way to set the identity?

Pulumi.Fsharp.Gcp

image

was testing the result from fsx script but not sure it exactly working as expected, generated docs have many generic types 'a ...

doesnt seem completely right

The future of this project

Hi there,

First of all I would like to thank you so much for this amazing project. We have been using the libraries quite heavily in our projects. I'd say that we strongly depend on them nowadays.

Unfortunately, looking at the commits history and the open issues it is obvious the you don't have much time for maintenance.
I was wondering what is the future of this project? Are you planning to put effort into it or you are going to abandon it completely?

If my team offers support on maintenance, how should we better do that? Would you have time to review our PRs?

Or maybe you can add me/us as collaborators so we can continue keeping the project up to date? In this case I would highly appreciate if you find time for an introduction call, just to go over the project structure and code style conventions. We don't want to spoil all the hard work you've done. We don't want to fork the project and create duplicates in the Nuget repository, we'd rather contribute to the original version.

Please let me know your thoughts. I'd be happy to discuss any details.

Cannot create EKS cluster

Hello, I'm trying to create EKS cluster but it seems that there is not possible to set vpcConfig with the computation expression. The vpcConfig is mentioned in the comments of the ClustedBuilder but the function is missing and after running pulumi up I get an error:

 System.ArgumentNullException: [Input] Pulumi.Aws.Eks.ClusterArgs.VpcConfig is required but was not given a value (Parameter 'VpcConfig')

my code is:

    let rolePolicy = """{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": "sts:AssumeRole",
                "Principal": {
                    "Service": "eks.amazonaws.com"
                },
                "Effect": "Allow",
                "Sid": ""
            }
        ]
    }"""

    let eksClusterRole = role {
        name "eksClusterRole"
        assumeRolePolicy rolePolicy
    }


    let myCluster = cluster {
        name "my-cluster"
        roleArn eksClusterRole.Arn
        //vpcConfig myVpc
    }

nuget packages used:

<ItemGroup>
        <PackageReference Include="Pulumi.FSharp" Version="2.*"/>
        <PackageReference Include="Pulumi.Aws" Version="3.*"/>
        <PackageReference Include="Pulumi.FSharp.Aws" Version="2.13.1.22"/>
        <PackageReference Include="Pulumi.FSharp.Core" Version="2.0.2"/>
</ItemGroup>

also as a side note, there seems to be some error with required nuget versions Pulumi.FSharp.Aws wants to use Pulumi.FSharp.Core of version 2.13.1.22 but this version doesn't exist.

namespaces issues

i think namespace usage of open is too complex and hard to troubleshoot, e.g. when using the simplest

Pulumi.FSharp.Kubernetes to just deploy an nginx pod in minikube, it's not really clear which namespaces are needed and what to use in open statements from the docs...

image

Support default values for resources

lt would be awesome if we could support something like:

let defaultK8sDeployment = deployment {
    ...
}

let k8sDeploy = deployment {
    withDefault defaultK8sDeployment
}

The k8s is just an example, we should be able to do that for everything. That will make it super easy to create small helpers that are reusable.

intellisense on types

maybe type intellisense could get an improvement somehow, the description of types and usage are quite complex and also seems wrong, so it's not easy to pass arguments to functions in the CE...

image

or another example...

image

e.g. container image is a standard string type

i think in many cases the type suggetion of intellisense are totally wrong / misleading, and could be much simplified

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.