Add docs for writing go based plugins
This commit is contained in:
parent
ad0a164871
commit
b470522767
222
website/content/docs/plugins/go-plugins/guests.mdx
Normal file
222
website/content/docs/plugins/go-plugins/guests.mdx
Normal file
@ -0,0 +1,222 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: Custom Guests - Go Plugin Development
|
||||
description: |-
|
||||
This page documents how to add new guest OS detection to Vagrant, allowing
|
||||
Vagrant to properly configure new operating systems. Prior to reading this,
|
||||
you should be familiar with the plugin development basics.
|
||||
---
|
||||
|
||||
# Go Plugin Development: Guests
|
||||
|
||||
Outside of these components, the caller must provide all other arguments
|
||||
that are required.
|
||||
|
||||
The most basic guest plugin is composed of:
|
||||
1. A detection function that determines if the plugin is usable on the system
|
||||
(is the expected guest)
|
||||
2. A set of capabilities that define actions that can be run against the guest
|
||||
3. An entry point defining the plugin options
|
||||
|
||||
**Note**: To quickly get started writing Go guest plugins, clone the [vagrant-guest-plugin-skeleton](https://github.com/soapy1/vagrant-guest-plugin-skeleton)
|
||||
template and follow the Readme.
|
||||
|
||||
The file structure of a guest plugin looks like:
|
||||
|
||||
```
|
||||
- myplugin
|
||||
|- main.go
|
||||
\- guest
|
||||
|- myguest.go
|
||||
\- cap
|
||||
|- mycapability.go
|
||||
```
|
||||
|
||||
Where `main.go` defines the plugin options. `guest/myguest.go` defines the core plugin
|
||||
functionality including the detection of the guest. `cap/*` has the definitions of
|
||||
all the guest plugin capabilities. These capabilities are the same as those for [Ruby
|
||||
plugins](../guest-capabilities).
|
||||
|
||||
## Writing a guest plugin
|
||||
|
||||
A guest must satisfy the interface defined for a guest component
|
||||
|
||||
```
|
||||
GuestDetectFunc() interface{}
|
||||
ParentFunc() interface{}
|
||||
HasCapabilityFunc() interface{}
|
||||
CapabilityFunc(capName string) interface{}
|
||||
```
|
||||
Src: https://github.com/hashicorp/vagrant-plugin-sdk/blob/main/component/component.go
|
||||
|
||||
`GuestDetectFunc`: returns a function that defines the code that determines if the guest is
|
||||
detected. The returned function must return a `bool`.
|
||||
|
||||
`ParentFunc`: returns a function that defines the code that determines the most immediate parent
|
||||
plugin. A child plugin will inherit all the capabilities defined in the parent. The
|
||||
returned function must return a `string`.
|
||||
|
||||
`HasCapabilityFunc`: returns a function that defines a lookup for a capability. The returned
|
||||
function must return an `bool`.
|
||||
|
||||
`CapabilityFunc`: returns a capability function that is defined by the plugin registered by a given name.
|
||||
|
||||
An example guest plugin
|
||||
|
||||
```
|
||||
// file: myplugin/guest/myguest.go
|
||||
package guest
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/vagrant-plugin-sdk/component"
|
||||
sdkcore "github.com/hashicorp/vagrant-plugin-sdk/core"
|
||||
)
|
||||
|
||||
// AlwaysTrueGuest is a Guest implementation for myplugin.
|
||||
type AlwaysTrueGuest struct {
|
||||
}
|
||||
|
||||
// DetectFunc implements component.Guest
|
||||
func (h *AlwaysTrueGuest) GuestDetectFunc() interface{} {
|
||||
return h.Detect
|
||||
}
|
||||
|
||||
func (h *AlwaysTrueGuest) Detect(t sdkcore.Target) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ParentsFunc implements component.Guest
|
||||
func (h *AlwaysTrueGuest) ParentFunc() interface{} {
|
||||
return h.Parent
|
||||
}
|
||||
|
||||
func (h *AlwaysTrueGuest) Parent() string {
|
||||
// This plugin has no parents
|
||||
return ""
|
||||
}
|
||||
|
||||
// HasCapabilityFunc implements component.Guest
|
||||
func (h *AlwaysTrueGuest) HasCapabilityFunc() interface{} {
|
||||
return h.CheckCapability
|
||||
}
|
||||
|
||||
func (h *AlwaysTrueGuest) CheckCapability(n *component.NamedCapability) bool {
|
||||
// This plugin has no capabilities
|
||||
return false
|
||||
}
|
||||
|
||||
// CapabilityFunc implements component.Guest
|
||||
func (h *AlwaysTrueGuest) CapabilityFunc(name string) interface{} {
|
||||
return fmt.Errorf("requested capability %s not found", name)
|
||||
}
|
||||
|
||||
var (
|
||||
_ component.Guest = (*AlwaysTrueGuest)(nil)
|
||||
)
|
||||
```
|
||||
|
||||
```
|
||||
// file: myplugin/main.go
|
||||
package myplugin
|
||||
|
||||
import (
|
||||
sdk "github.com/hashicorp/vagrant-plugin-sdk"
|
||||
"github.com/hashicorp/vagrant/builtin/myplugin/guest"
|
||||
)
|
||||
|
||||
// Options are the SDK options to use for instantiation.
|
||||
var ComponentOptions = []sdk.Option{
|
||||
sdk.WithComponents(
|
||||
// Include the defined guest as a component defined in this plugin
|
||||
&guest.AlwaysTrueGuest{},
|
||||
),
|
||||
}
|
||||
|
||||
func main() {
|
||||
sdk.Main(ComponentOptions...)
|
||||
os.Exit(0)
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the guest plugin will always be detected. It does not define any
|
||||
capabilities, or have any parent plugins.
|
||||
|
||||
### Defining and registering guest capabilities
|
||||
|
||||
A guest plugin may have capabilities two ways:
|
||||
1. By defining and implementing the capability in the plugin
|
||||
2. By inheriting the capability from a parent guest plugin
|
||||
|
||||
Define a capability by writing out a function that returns the desired capability
|
||||
|
||||
```
|
||||
// file: myplugin/guest/cap/mycapability.go
|
||||
package cap
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/hashicorp/vagrant-plugin-sdk/terminal"
|
||||
)
|
||||
|
||||
func WriteHelloFunc() interface{} {
|
||||
return WriteHello
|
||||
}
|
||||
|
||||
func WriteHello(trm terminal.UI) error {
|
||||
trm.Output("Hello world")
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Make the capability available to the plugin by filling in the capability functions
|
||||
|
||||
```
|
||||
myplugin/guest/myguest.go
|
||||
// HasCapabilityFunc implements component.Guest
|
||||
func (h *AlwaysTrueGuest) HasCapabilityFunc() interface{} {
|
||||
return h.CheckCapability
|
||||
}
|
||||
|
||||
func (h *AlwaysTrueGuest) CheckCapability(n *component.NamedCapability) bool {
|
||||
if n.Capability == "write_hello" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CapabilityFunc implements component.Guest
|
||||
func (h *AlwaysTrueGuest) CapabilityFunc(name string) interface{} {
|
||||
if name == "write_hello" {
|
||||
return h.WriteHelloCap
|
||||
}
|
||||
return errors.New("Invalid capability requested")
|
||||
}
|
||||
|
||||
func (h *AlwaysTrueGuest) WriteHelloCap(ui terminal.UI) error {
|
||||
return cap.WriteHello(ui)
|
||||
}
|
||||
```
|
||||
|
||||
A guest plugin may inherit the capabilities of a parent function by defining
|
||||
a parent in the plugin implementation. This is done by setting the return
|
||||
value of the `Parent` function to the name of the desired parent plugin. Go
|
||||
based guest plugins may use Ruby based plugins as their parent.
|
||||
|
||||
```
|
||||
// file: myplugin/guest/myguest.go
|
||||
|
||||
...
|
||||
|
||||
// ParentsFunc implements component.Guest
|
||||
func (h *AlwaysTrueGuest) ParentFunc() interface{} {
|
||||
return h.Parent
|
||||
}
|
||||
|
||||
func (h *AlwaysTrueGuest) Parent() string {
|
||||
// This plugin sets the parent to the "debian" plugin which is provided
|
||||
// as a Ruby plugin. This AlwaysTrueGuest now inherits all the capabilities
|
||||
// of the debian Ruby guest plugin.
|
||||
return "debian"
|
||||
}
|
||||
```
|
||||
74
website/content/docs/plugins/go-plugins/index.mdx
Normal file
74
website/content/docs/plugins/go-plugins/index.mdx
Normal file
@ -0,0 +1,74 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: Go Based Plugins
|
||||
description: |-
|
||||
Vagrant comes with many great features out of the box to get your environments
|
||||
up and running. Sometimes, however, you want to change the way Vagrant does
|
||||
something or add additional functionality to Vagrant. This can be done via
|
||||
Vagrant plugins.
|
||||
---
|
||||
|
||||
# Go Vagrant Plugins
|
||||
|
||||
With the introduction of Vagrant-go, Vagrant now supports running plugins
|
||||
implemented in Go. Note that Vagrant-go can run Go and Ruby based plugins
|
||||
while Vagrant-ruby only runs Ruby based plugins.
|
||||
|
||||
## Anatomy of a Go plugin
|
||||
|
||||
When a plugin is started, it runs in its own process and is able to communicate
|
||||
with the other plugins over GRPC.
|
||||
|
||||
A Vagrant-go plugin must implement an interface for a [plugin component](https://github.com/hashicorp/vagrant-plugin-sdk/blob/main/component/component.go).
|
||||
A plugin may satisfy more than one component interface. The plugin interfaces
|
||||
define the `<name>Func` functions for the plugin. These functions are meant to
|
||||
return the actual function that represents the named action. For example the
|
||||
`Host` component defines a `DetectFunc`. So, a plugin must have a `DetectFunc`
|
||||
implementation that returns a function that can detect if Vagrant is running
|
||||
on the given host. For example
|
||||
|
||||
```
|
||||
// DetectFunc implements component.Host
|
||||
func (h *AlwaysTrueHost) DetectFunc() interface{} {
|
||||
return h.Detect
|
||||
}
|
||||
|
||||
func (h *AlwaysTrueHost) Detect() bool {
|
||||
// This plugin always detects that it is running on the expected host
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
Using this pattern of `<name>Func` functions, Vagrant is able to allow flexibility
|
||||
over the receivers of the functions that actually define the behavior of the plugin.
|
||||
This injection of dependencies is done using go-argmapper. So, in the same example,
|
||||
the `Detect` function may be made to accept some arguments.
|
||||
|
||||
```
|
||||
// DetectFunc implements component.Host
|
||||
func (h *AlwaysTrueHost) DetectFunc() interface{} {
|
||||
return h.Detect
|
||||
}
|
||||
|
||||
func (h *AlwaysTrueHost) Detect(string msg, trm terminal.UI) bool {
|
||||
trm.Output(msg)
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
Now, in order to run the `Detect` function, the caller must provide a `string` and
|
||||
`terminal.UI` argument. By default, Vagrant will always inject the following arguments
|
||||
into a call to a plugin:
|
||||
|
||||
- `terminal.UI` component
|
||||
- basis
|
||||
- project (when available)
|
||||
- context
|
||||
- logger
|
||||
|
||||
For each component type, Vagrant may also inject some additional arguments.
|
||||
|
||||
Outside of these components, the caller must provide all other arguments that are required.
|
||||
So, in the case above, in order to successfully call this `Detect` function, the caller must
|
||||
also provide a `string`. It is recommended that plugin authors do not rely on arguments being
|
||||
injected into their implementations outside of these sets of arguments.
|
||||
@ -699,6 +699,19 @@
|
||||
{
|
||||
"title": "Packaging & Distribution",
|
||||
"path": "plugins/packaging"
|
||||
},
|
||||
{
|
||||
"title": "Go Plugins",
|
||||
"routes": [
|
||||
{
|
||||
"title": "Overview",
|
||||
"path": "plugins/go-plugins"
|
||||
},
|
||||
{
|
||||
"title": "Guests",
|
||||
"path": "plugins/go-plugins/guests"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user