A configuration management framework written in Go.
The framework allows you to write configuration in plain Go, which you would then compile and distribute as a binary to the target machines.
This means that you don't need to bootstrap an instance with configuration files or a runtime environment (eg "install chef"): simply download the binary, and run it!
I'm using Viaduct to set up my personal development environment at surminus/myduct.
Create a project in main.go and create a new manifest:
import (
"github.com/surminus/viaduct"
)
func main() {
// m is our manifest object
m := viaduct.New()
}A standard set of resources are found in the resources package.
To add them:
import (
"github.com/surminus/viaduct"
"github.com/surminus/viaduct/resources"
)
func main() {
m := viaduct.New()
m.Add(&resources.Directory{Path: "/tmp/test"})
m.Add(&resources.File{Path: "/tmp/test/foo"})
}All resources will run concurrently, so in this example we will declare a dependency so that the directory is created before the file:
func main() {
m := viaduct.New()
dir := m.Add(&resources.Directory{Path: "/tmp/test"})
m.Add(&resources.File{Path: "/tmp/test/foo"}, dir)
}When you've added all the resources you need, we can apply them:
func main() {
m := viaduct.New()
dir := m.Add(&resources.Directory{Path: "/tmp/test"})
m.Add(&resources.File{Path: "/tmp/test/foo"}, dir)
m.Run()
}Compile the package and run it:
go build -o viaduct
./viaductSee the example in the examples directory.
The compiled binary comes with runtime flags:
./viaduct --helpThere are helper functions to allow us to use the
embed package to flexibly work with files and
templates.
To create a template, first create a file in templates/test.txt using Go
template syntax:
My cat is called {{ .Name }}We can then generate the data to create our file:
import (
"embed"
"github.com/surminus/viaduct"
"github.com/surminus/viaduct/resources"
)
//go:embed templates
var templates embed.FS
func main() {
m := viaduct.New()
template := resources.NewTemplate(
templates,
"templates/test.txt",
struct{ Name string }{Name: "Bella"},
)
// CreateFile is a helper function that takes two arguments
m.Add(resources.CreateFile("test/foo", template))
}The EmbeddedFile function works in a similar way, but without variables.
Like any good configuration management tool, we also have access to node
attributes under the Attribute variable:
import (
"fmt"
"github.com/surminus/viaduct"
"github.com/surminus/viaduct/resources"
)
func main() {
m := viaduct.New()
// E is an alias for creating an Execute resource
m.Add(resources.Exec(fmt.Sprintf("echo \"Hello %s!\"", viaduct.Attribute.User.Username)))
}If you require to perform actions that require sudo access, such as using the
Package resource, or creating files using File, then you should run the
executible using sudo.
Otherwise, assigning permissions should be achieved by explicitly setting the user and group in the resource.
Alternatively, you can set a default user attribute:
func main() {
viaduct.Attribute.SetUser("laura")
m := viaduct.New()
// Will print my home directory
m.Add(resources.Echo(viaduct.Attribute.User.Homedir))
m.Run()
}Custom resources just need to implement the
ResourceAttributes
interface.
See the example custom resource in the examples directory.