mid

module
v0.0.18 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2025 License: MIT

README

mid

Pulumi-native configuration management

[!CAUTION] This provider is PRE-ALPHA software and NOT fit for production use!

mid combines the simplicity of Ansible, the declarativeness of Nix, and the power of Pulumi to make server configuration management simple, easy, and fast. mid is a "middle ground" between all of them to give you just what you need with as minimal overhead as possible.

Design Principles

Goals
  • Agentless[^1]; do everything over SSH without a persistent agent service running or any further networking required.
  • Manage machines quickly and in parallel (like Ansible, but with even more parallelization).
  • Declarative and determinate (e.g. deleting the Pulumi resource should delete the associated thing on the server[^2])
  • Mostly drop-in replacement for the remote module of the Pulumi Command Provider
Non-goals
  • Nix-levels of determinism - achieving fully deterministic systems means managing the entire world deterministically and that just isn't feasible. If you need/want that level of determinism, just use Nix and NixOS.
  • Interop with other CM systems (Ansible, Puppet, Salt) - mid incorporates a very stripped down fork of Ansible that uses a custom Go-based task execution engine. This allows for significantly faster feature development and provides valuable escape hatches for the many cases where a first-class resource or function hasn't been developed yet. However, any kind of support for interop with official Ansible or any other CM systems is not planned[^3]. pulumi-ansible-provisioner might be of interest for using existing Ansible roles.
  • Pull-based or agent-based workflows - I'm hyperfocusing on push-based deployments to keep it simple. Check out my pulumi-aws-ec2-instance component resources for ideas on how to interop Ansible with EC2 userdata (or your cloud's equivalent).
  • Windows support - Only Linux is supported for now. Other unix-likes are future goals.
Future-goals
  • Better OS support (except Windows) - Right now only Linux is supported, and really only Ubuntu/Debian are truly supported[^4]. While I expect Debian-based distros to have the most support, there is no reason that other distros can't be supported just as well. Other unix-likes such as the BSDs should be better supported as well since those are plenty prevalent albeit not to the same degree as Linux. macOS support might happen as a side effect of other work but I'm unsure if having any kind of first-class support is useful.
  • Be usable by non-root (and non-sudo) - The vast majority of use cases require root and a fast majority of systems have sudo. Right now this is hardcoded[^5] but in the future it would be nice to have this be more flexible.
  • Pluggable module system - Right now everything baked into the provider but it might be nice to be able to expand it somehow.
  • More language support - Only Go, TypeScript, Python, and YAML are supported at the moment since those are the only languages I use with Pulumi. C# and Java support will come eventually.

[^1]: Technically there is an "agent" that runs on the remote node, however it only runs for the duration that the Pulumi provider runs and communicates with the provider over stdin/stdout, not TCP or any other side channel network protocol. This is very similar to how Ansible modules are executed. So if you are okay with using Ansible, then you should be okay with using mid.

[^2]: There will be cases where mid is unable to know what to do on a delete. It should generally try to do the "correct" thing but this is not guaranteed. If you want to err on the side of caution, use Pulumi's retainOnDelete resource option to skip doing any delete operations.

[^3]: While "first-class" support for external CM system interop is not planned, a byproduct of the embedded Ansible module system means there is support for gathering facts by using the ansibleExecute function with the setup module. There is even support for running the facter module to get facts from Facter. I have no intention of removing the ability to do this, since this is extremely useful in certain cases. Just don't expect any kind of top-level mid.getFacts() function.

[^4]: Ubuntu is the most supported distro 1. because it is what I use in my servers (for better or worse) and 2. because it by far has the best cloud-init integration which makes initial bootstrapping and testing so much easier. That said, on my non-servers I use Arch (btw), so any OS or distro that can run Pulumi should be able to use the mid provider, it just might not be able to be configured by mid.

[^5]: It will use sudo if present. If the sudo command isn't found it will run any commands without sudo. There is a high likelihood those commands will fail unless running as root though. Also, there is no support for sudo passwords for now, but that is planned. cloud-init sets NOPASSWD for the default user by default, and using the default user is the main way I envisioned this being used, hence why I haven't prioritized this.

Installation and usage

[!CAUTION] Again, this is PRE-ALPHA software. It is not fit for general use!

Go

Grab the module

go get github.com/sapslaj/mid/sdk

Set up a provider instance

// main.go
package main

import (
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
	"github.com/sapslaj/mid/sdk/go/mid"
	"github.com/sapslaj/mid/sdk/go/mid/resource"
	"github.com/sapslaj/mid/sdk/go/mid/types"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		provider, err := mid.NewProvider(ctx, "provider", &mid.ProviderArgs{
			Connection: &types.ConnectionArgs{
				// TODO: use ESC for this for something
				User:     pulumi.String("root"),
				Password: pulumi.String("hunter2"),
				Host:     pulumi.String("localhost"),
				Port:     pulumi.Float64(22),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}

Add some resources

// main.go

// ...
func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		// ...

		_, err = resource.NewPackage(ctx, "vim", &resource.PackageArgs{
			Name:   pulumi.String("vim"),
			Ensure: pulumi.String("present"),
		}, pulumi.Provider(provider))
		if err != nil {
			return err
		}

		return nil
	})
}

Go!

pulumi up
TypeScript

mid is not published on NPM yet. Set up GitHub Packages as an NPM registry for the @sapslaj scope first.

Then npm install

npm install --save @sapslaj/pulumi-mid

Set up a provider instance

// index.ts
import * as pulumi from "@pulumi/pulumi";
import * as mid from "@sapslaj/pulumi-mid";

const provider = new mid.Provider("provider", {
  connection: {
    // TODO: use ESC for this or something
    user: "root",
    password: "hunter2",
    host: "localhost",
    port: 22,
  },
});

Add some resources

// ...
new mid.resource.Package("vim", {
  name: "vim",
  ensure: "present",
}, {
  provider: provider,
});

Go!

pulumi up
Python

mid is not published on PyPI yet. Install the Pulumi provider package directly from GitHub. Note that you might want to replace @main with a release git tag.

pip install 'pulumi_mid @ git+https://github.com/sapslaj/mid.git@main#subdirectory=sdk/python'

Set up a provider instance

# __main__.py
import pulumi
import pulumi_mid as mid

provider = mid.Provider(
    "provider",
    # TODO: use ESC for this or something
    connection={
        "user": "root",
        "password": "hunter2",
        "host": "localhost",
        "port": 22,
    },
)

Add some resources

vim = mid.resource.Package(
    "vim",
    name="vim",
    ensure="present",
    opts=pulumi.ResourceOptions(provider=provider),
)

Go!

pulumi up

Directories

Path Synopsis
Code generated by ./hack/generate-agent-binaries.py DO NOT EDIT
Code generated by ./hack/generate-agent-binaries.py DO NOT EDIT
ansible
Code generated by ./hack/generate-ansible-types.py DO NOT EDIT
Code generated by ./hack/generate-ansible-types.py DO NOT EDIT
cmd/mid-agent command
rpc
pkg
env
log
providerfw
Package provider works as a shared high-level interface for rpc.ResourceProviderServer.
Package provider works as a shared high-level interface for rpc.ResourceProviderServer.
providerfw/ende
Package ende - ENcoding and DEcoding resource.Property* values
Package ende - ENcoding and DEcoding resource.Property* values
providerfw/infer
Package infer is a framework to define Pulumi resources and functions derived from go types.
Package infer is a framework to define Pulumi resources and functions derived from go types.
providerfw/infer/tests
Package tests is a generated GoMock package.
Package tests is a generated GoMock package.
providerfw/infer/types
Package types provides ancillary types for use with github.com/sapslaj/mid/pkg/providerfw/infer.
Package types provides ancillary types for use with github.com/sapslaj/mid/pkg/providerfw/infer.
providerfw/integration
Package integration is a test library for validating in-memory providers behave correctly.
Package integration is a test library for validating in-memory providers behave correctly.
providerfw/integration/fake
Package fake implements a fake pulumirpc.EngineServer and pulumirpc.ResourceMonitorServer for integration test purposes.
Package fake implements a fake pulumirpc.EngineServer and pulumirpc.ResourceMonitorServer for integration test purposes.
providerfw/introspect
Package introspect has shared utilities for reflecting.
Package introspect has shared utilities for reflecting.
providerfw/key
Package key provides an internal set of keys for use with context.WithValue and context.Context.Value that can be shared across packages source.
Package key provides an internal set of keys for use with context.WithValue and context.Context.Value that can be shared across packages source.
providerfw/middleware
Package middleware defines common interfaces multiple middleware components use.
Package middleware defines common interfaces multiple middleware components use.
providerfw/middleware/cancel
Package cancel provides a middle-ware that ties the Cancel gRPC call from Pulumi to Go's context.Context cancellation system.
Package cancel provides a middle-ware that ties the Cancel gRPC call from Pulumi to Go's context.Context cancellation system.
providerfw/middleware/cancel/evict
Package evict is a helper package for github.com/sapslaj/mid/pkg/providerfw/middleware/cancel.
Package evict is a helper package for github.com/sapslaj/mid/pkg/providerfw/middleware/cancel.
providerfw/middleware/complexconfig
Package complexconfig adds middleware for schema informed complex configuration encoding/decoding as a work-around for https://github.com/pulumi/pulumi/pull/15032.
Package complexconfig adds middleware for schema informed complex configuration encoding/decoding as a work-around for https://github.com/pulumi/pulumi/pull/15032.
providerfw/middleware/context
Package context allows systemic wrapping of provider.Context before invoking a subsidiary provider.
Package context allows systemic wrapping of provider.Context before invoking a subsidiary provider.
providerfw/middleware/dispatch
Package dispatch provides a provider that dispatches calls by URN such as `Create` to resource level invocations.
Package dispatch provides a provider that dispatches calls by URN such as `Create` to resource level invocations.
providerfw/middleware/rpc
Package rpc allows projecting a rpc.ResourceProviderServer into a p.Provider.
Package rpc allows projecting a rpc.ResourceProviderServer into a p.Provider.
providerfw/middleware/schema
Package schema provides a middleware to respond to GetSchema.
Package schema provides a middleware to respond to GetSchema.
providerfw/putil
Package putil contains utility functions for working with [resource.PropertyValue]s and related types.
Package putil contains utility functions for working with [resource.PropertyValue]s and related types.
providerfw/rapid/reflect
Package reflect provides [rapid.Generator]s for reflect types.
Package reflect provides [rapid.Generator]s for reflect types.
providerfw/rapid/resource
Package resource provides [rapid.Generator]s for [resource.PropertyValue]s.
Package resource provides [rapid.Generator]s for [resource.PropertyValue]s.
providerfw/rpc
Package rpc provides utilities for marshaling and unmarshaling of resource properties.
Package rpc provides utilities for marshaling and unmarshaling of resource properties.
ptr
syncmap
VERY slim wrapper around sync.Map with Go generics for that sweet sweet type safety
VERY slim wrapper around sync.Map with Go generics for that sweet sweet type safety
sdk module
tests
acceptance/integration
Package integration implements an integration test framework for Pulumi.
Package integration implements an integration test framework for Pulumi.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL